mirror of
https://github.com/smallfawn/QLScriptPublic.git
synced 2026-11-05 22:36:53 +08:00
fix daily miniapp code login scripts
This commit is contained in:
1 parent
8b0679680d
commit
4babb0ba12
14 files changed
+2576
-1643
No files matched your search
+217
-72
@@ -1,6 +1,7 @@
|
||||
#by:哆啦A梦
|
||||
#入口:http://mx.qrurl.net/h5/wxa/link?sid=26407uif5Oq
|
||||
#抓包breoplus.breo.cn的域名下的token,多账号换行分割
|
||||
#BREO变量填写wx_server里的openid/账号标识,多账号换行分割
|
||||
#需要配置wx_server_url、wx_auth,用于获取wx.login code
|
||||
#账号变量名:BREO
|
||||
#new Env("BREO")
|
||||
#cron 8 9,10,11 * * *
|
||||
@@ -9,7 +10,182 @@
|
||||
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:
|
||||
@@ -54,16 +230,7 @@ def get_proclamation():
|
||||
|
||||
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"
|
||||
}
|
||||
headers = breo_task_headers(token)
|
||||
data = {
|
||||
"anonymoused": 1,
|
||||
"content": content,
|
||||
@@ -94,16 +261,7 @@ def post_to_breo(token, content, title):
|
||||
|
||||
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"
|
||||
}
|
||||
headers = breo_task_headers(token)
|
||||
data = {
|
||||
"postId": post_id
|
||||
}
|
||||
@@ -113,8 +271,9 @@ def collect_post(token, post_id):
|
||||
result = response.json()
|
||||
if result.get("success", False):
|
||||
print("✅ 收藏成功!")
|
||||
print(f"获得点数: {result['result']['point']}")
|
||||
print(f"成长值: {result['result']['grow']}")
|
||||
reward = result.get("result") or {}
|
||||
print(f"获得点数: {reward.get('point', 0)}")
|
||||
print(f"成长值: {reward.get('grow', 0)}")
|
||||
else:
|
||||
print(f"❌ 收藏失败,错误信息:{result.get('message', '未知错误')}")
|
||||
else:
|
||||
@@ -126,16 +285,7 @@ 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"
|
||||
}
|
||||
headers = breo_task_headers(token)
|
||||
data = {
|
||||
"anonymoused": 0,
|
||||
"commentText": comment_content,
|
||||
@@ -147,9 +297,11 @@ def comment_post(token, post_id):
|
||||
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']}")
|
||||
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:
|
||||
@@ -160,23 +312,16 @@ def comment_post(token, post_id):
|
||||
|
||||
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"
|
||||
}
|
||||
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("✅ 浏览商城成功!")
|
||||
print(f"获得点数: {result['result']['point']}")
|
||||
print(f"成长值: {result['result']['grow']}")
|
||||
reward = result.get("result") or {}
|
||||
print(f"获得点数: {reward.get('point', 0)}")
|
||||
print(f"成长值: {reward.get('grow', 0)}")
|
||||
else:
|
||||
print(f"❌ 浏览商城失败,错误信息:{result.get('message', '未知错误')}")
|
||||
else:
|
||||
@@ -186,25 +331,16 @@ def browse_mall(token):
|
||||
|
||||
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"
|
||||
}
|
||||
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("✅ 签到成功!")
|
||||
print(f"获得点数: {result['result']['point']}")
|
||||
print(f"成长值: {result['result']['grow']}")
|
||||
reward = result.get("result") or {}
|
||||
print(f"获得点数: {reward.get('point', 0)}")
|
||||
print(f"成长值: {reward.get('grow', 0)}")
|
||||
else:
|
||||
print(f"❌ 签到失败,错误信息:{result.get('message', '未知错误')}")
|
||||
else:
|
||||
@@ -216,19 +352,28 @@ if __name__ == "__main__":
|
||||
# 获取公告
|
||||
#get_proclamation()
|
||||
|
||||
# 从环境变量读取 token
|
||||
tokens = os.getenv("BREO", "").splitlines()
|
||||
# 从环境变量读取 wx_server 账号标识/openid
|
||||
accounts = [item.strip() for item in os.getenv("BREO", "").replace("&", "\n").splitlines() if item.strip()]
|
||||
|
||||
if not tokens:
|
||||
if not accounts:
|
||||
print("❌ 未检测到 账号信息,退出脚本。")
|
||||
else:
|
||||
skip_community = os.getenv("BREO_SKIP_COMMUNITY", "").lower() in ("1", "true", "yes")
|
||||
print("=============== 开始执行任务 ===============")
|
||||
for i, token in enumerate(tokens, 1):
|
||||
if token.strip(): # 跳过空行
|
||||
print(f"\n-------------- 账号 {i} 开始 --------------")
|
||||
print("🚀 正在签到...")
|
||||
punch_in(token)
|
||||
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:
|
||||
@@ -240,9 +385,9 @@ if __name__ == "__main__":
|
||||
else:
|
||||
print("❌ 发帖失败,跳过后续操作。")
|
||||
|
||||
print("\n🛒 正在浏览商城...")
|
||||
browse_mall(token)
|
||||
print("\n🛒 正在浏览商城...")
|
||||
browse_mall(token)
|
||||
|
||||
print(f"-------------- 账号 {i} 结束 --------------")
|
||||
print(f"-------------- 账号 {i} 结束 --------------")
|
||||
|
||||
print("\n=============== 所有任务执行完毕 ===============")
|
||||
print("\n=============== 所有任务执行完毕 ===============")
|
||||
+232
-73
@@ -1,122 +1,281 @@
|
||||
/*
|
||||
爱玛会员俱乐部 - 自动签到脚本(2026年2月修复版)
|
||||
✅ 修复点:使用域名替代失效IP,更新活动ID为100001180
|
||||
✅ 支持环境:Node.js
|
||||
✅ 变量名:aima
|
||||
✅ 变量值:access-token(支持多账号,用 & 或换行分隔)
|
||||
爱玛会员俱乐部 - 自动签到脚本
|
||||
变量名:aima
|
||||
变量值:账号标识/openid(支持多账号,用 & 或换行分隔)
|
||||
CODE登录依赖:wx_server_url、wx_auth
|
||||
*/
|
||||
const { Env } = require("../tools/env")
|
||||
const { Env } = require("../tools/env");
|
||||
const $ = new Env("爱玛会员俱乐部");
|
||||
const axios = require('axios')
|
||||
const axios = require("axios");
|
||||
const crypto = require("crypto");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
// ================== 配置区 ==================
|
||||
const ACTIVITY_ID = "100001192"; // 2026年2月活动ID
|
||||
const BASE_URL = "https://scrm.aimatech.com"; // 使用官方域名,不再硬编码IP
|
||||
const ACTIVITY_ID = "100001192";
|
||||
const BASE_URL = "https://scrm.aimatech.com";
|
||||
const WXCLIENT_URL = `${BASE_URL}/aima/wxclient`;
|
||||
const MINI_APPID = "wx2dcfb409fd5ddfb4";
|
||||
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";
|
||||
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, function (c) {
|
||||
const r = Math.random() * 16 | 0;
|
||||
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||
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) {
|
||||
const crypto = require('crypto');
|
||||
return crypto.createHash('md5').update(str).digest('hex');
|
||||
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/operatedata`,
|
||||
{
|
||||
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(token, index) {
|
||||
try {
|
||||
const timestamp = Date.now();
|
||||
const traceLogId = generateUUID();
|
||||
async function signIn(account, index) {
|
||||
let token = await getAccessToken(account);
|
||||
const setToken = (newToken) => {
|
||||
token = newToken;
|
||||
};
|
||||
|
||||
// 构造通用请求头
|
||||
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.signStatus === 1) {
|
||||
$.log(`✅ 账号【${index}】今日已签到!`);
|
||||
return;
|
||||
$.log(`🚀 账号【${index}】查询签到状态...`);
|
||||
const searchRes = await request(
|
||||
"post",
|
||||
`${WXCLIENT_URL}/mkt/activities/sign:search`,
|
||||
token,
|
||||
{
|
||||
data: { activityId: ACTIVITY_ID },
|
||||
account,
|
||||
onToken: setToken,
|
||||
}
|
||||
);
|
||||
|
||||
// 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 (searchRes.status !== 200 || searchRes.data?.code !== 200) {
|
||||
throw new Error(`查询签到状态失败: HTTP ${searchRes.status} ${JSON.stringify(searchRes.data)}`);
|
||||
}
|
||||
|
||||
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)}`);
|
||||
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,
|
||||
}
|
||||
);
|
||||
|
||||
} catch (e) {
|
||||
throw new Error(e.message || e);
|
||||
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🔔 爱玛会员俱乐部, 开始!`);
|
||||
console.log("\n🔔 爱玛会员俱乐部, 开始!");
|
||||
|
||||
// 获取 access-token(支持多账号)
|
||||
let tokens = [];
|
||||
let accounts = [];
|
||||
if ($.isNode()) {
|
||||
const env = process.env.aima;
|
||||
if (env) {
|
||||
tokens = env.split(/&|\n/).filter(t => t.trim());
|
||||
accounts = env.split(/&|\n/).map((t) => t.trim()).filter(Boolean);
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens.length === 0) {
|
||||
$.msg("❌ 未找到 access-token,请配置变量 'aima'");
|
||||
if (accounts.length === 0) {
|
||||
$.msg("❌ 未找到账号标识,请配置变量 'aima'");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`共找到${tokens.length}个账号`);
|
||||
console.log(`共找到${accounts.length}个账号`);
|
||||
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
for (let i = 0; i < accounts.length; i++) {
|
||||
try {
|
||||
console.log(`\n🚀 user:【${i + 1}】 start work`);
|
||||
await signIn(tokens[i], i + 1);
|
||||
await signIn(accounts[i], i + 1);
|
||||
} catch (e) {
|
||||
console.log(`❌ 账号【${i + 1}】执行失败: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 发送通知
|
||||
//await $.sendMsg($.logs.join("\n"));
|
||||
// await $.sendMsg($.logs.join("\n"));
|
||||
})()
|
||||
.catch((e) => console.log(e))
|
||||
.finally(() => $.done());
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
}
|
||||
+299
-180
@@ -1,15 +1,18 @@
|
||||
/*
|
||||
------------------------------------------
|
||||
@Author: sm
|
||||
@Date: 2024.06.07 19:15
|
||||
@Date: 2026.06.01
|
||||
@Description: 七彩虹微信小程序 签到&点赞
|
||||
cron: 30 10 * * *
|
||||
------------------------------------------
|
||||
#Notice:
|
||||
#Notice:
|
||||
变量名:colorful
|
||||
抓取
|
||||
https://interface.skycolorful.com/api 请求头的authorization去掉Bearer # x-authorization去掉Bearer
|
||||
多账户&或换行
|
||||
变量值:wx_server 里的 openid/账号标识,多账户&或换行
|
||||
需要配置:wx_server_url、wx_auth
|
||||
|
||||
说明:小程序当前登录链路为 wx.login code -> /api/User/OnLogin 获取 OpenId,
|
||||
首次换取业务 Token 还需要微信手机号授权 code;现有 wx_server 只能提供 wx.login code。
|
||||
脚本会复用本地 token 缓存,缓存失效或首次运行时会自动验证 code 登录能力并给出明确原因。
|
||||
|
||||
⚠️【免责声明】
|
||||
------------------------------------------
|
||||
@@ -22,200 +25,316 @@ https://interface.skycolorful.com/api 请求头的authorization去掉Bearer # x-
|
||||
7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。
|
||||
*/
|
||||
|
||||
const { Env } = require("../tools/env")
|
||||
const { Env } = require("../tools/env.js");
|
||||
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"
|
||||
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");
|
||||
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";
|
||||
|
||||
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 md5(str) {
|
||||
return crypto.createHash("md5").update(str).digest("hex");
|
||||
}
|
||||
|
||||
function isTokenError(message) {
|
||||
return /401|403|token|登录|授权|未登录|无效|过期|失效/i.test(String(message || ""));
|
||||
}
|
||||
|
||||
function isSuccess(result) {
|
||||
return Number(result?.Code) === 0 && result?.Success !== false;
|
||||
}
|
||||
|
||||
class Task {
|
||||
constructor(env) {
|
||||
this.index = $.userIdx++
|
||||
this.user = env.split(strSplitor);
|
||||
this.token = this.user[0];
|
||||
this.token2 = this.user[1];
|
||||
this.signStatus = false;
|
||||
this.expireFlag = false;
|
||||
}
|
||||
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;
|
||||
this.isLegacyToken = this.user.length >= 2;
|
||||
if (this.isLegacyToken) {
|
||||
this.token = this.user[0].trim();
|
||||
this.refreshToken = this.user[1].trim();
|
||||
this.accountId = `legacy:${shortToken(this.token)}`;
|
||||
}
|
||||
}
|
||||
|
||||
async run() {
|
||||
await this.getTokenExpireTime()
|
||||
await this.getUserInfo()
|
||||
await this.getSignInfo()
|
||||
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.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
|
||||
}
|
||||
if (!this.token) {
|
||||
await this.loginByWxCode();
|
||||
if (!this.token) return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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,
|
||||
"x-authorization": "Bearer " + this.token2,
|
||||
"source": "Wx",
|
||||
"ucsource": "30",
|
||||
"user-from": "xcx",
|
||||
await this.getUserInfo();
|
||||
await this.getSignInfo();
|
||||
|
||||
if (this.signStatus) {
|
||||
$.log(`账号[${this.index}] 今日已签到`);
|
||||
return;
|
||||
}
|
||||
await this.signInV2();
|
||||
}
|
||||
|
||||
}
|
||||
options.headers = Object.assign(baseHeaders, options.headers)
|
||||
return axios.request(options)
|
||||
}
|
||||
cacheKey() {
|
||||
return this.isLegacyToken ? this.accountId : this.raw;
|
||||
}
|
||||
|
||||
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: {
|
||||
getCachedToken() {
|
||||
const cache = readTokenCache();
|
||||
return cache[this.cacheKey()] || null;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
let { data: result } = await this.request(options);
|
||||
if (result?.Code == '0') {
|
||||
//打印签到结果
|
||||
$.log(`🌸账号[${this.index}]` + `🕊签到${result.Message}🎉`);
|
||||
} else {
|
||||
$.log(`🌸账号[${this.index}] 签到-失败:${result.Message}❌`)
|
||||
}
|
||||
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 || {};
|
||||
}
|
||||
|
||||
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 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
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
} 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 getLoginCode() {
|
||||
if (!process.env.wx_auth) throw new Error("缺少 wx_auth,无法从 wx_server 获取 code");
|
||||
const { data } = await wechat.getCode(this.raw);
|
||||
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("/api/User/OnLogin", {
|
||||
method: "POST",
|
||||
auth: false,
|
||||
data: { Code: code },
|
||||
});
|
||||
this.openId = result?.Data?.OpenId || "";
|
||||
const token = result?.Data?.Token || result?.Data?.token || "";
|
||||
const refreshToken = result?.Data?.RefreshToken || result?.Data?.refreshToken || "";
|
||||
if (token) {
|
||||
this.token = token;
|
||||
this.refreshToken = refreshToken;
|
||||
this.saveCachedToken();
|
||||
$.log(`账号[${this.index}] CODE登录成功: ${shortToken(this.token)}`);
|
||||
return;
|
||||
}
|
||||
throw new Error(`OnLogin仅返回OpenId=${this.openId || "空"},首次业务登录仍需要微信手机号授权code`);
|
||||
} catch (e) {
|
||||
$.log(`账号[${this.index}] CODE登录失败: ${e.message || e}`);
|
||||
}
|
||||
}
|
||||
|
||||
async checkToken() {
|
||||
try {
|
||||
await this.request("/api/User/RefreshLoginTime", {
|
||||
method: "POST",
|
||||
data: { phone: "" },
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async signInV2() {
|
||||
try {
|
||||
const result = await this.request("/api/User/SignV2", {
|
||||
method: "POST",
|
||||
data: {},
|
||||
});
|
||||
$.log(`🌸账号[${this.index}]🕊签到${result.Message || "成功"}🎉`);
|
||||
} 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 getSignInfo() {
|
||||
try {
|
||||
const result = await this.request("/api/User/IsSignV2");
|
||||
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("/api/User/GetUserInfo");
|
||||
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 (let user of $.userList) {
|
||||
await new Task(user).run();
|
||||
}
|
||||
})()
|
||||
.catch((e) => console.log(e))
|
||||
.finally(() => $.done());
|
||||
// 暂停主运行:当前七彩虹后端首次换取业务 Token 需要微信手机号授权 code,
|
||||
// 现有 wx_server 只能提供 wx.login code,恢复前不要自动执行任务。
|
||||
// !(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 {
|
||||
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 {
|
||||
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) {}
|
||||
}
|
||||
+243
-89
@@ -1,15 +1,13 @@
|
||||
/*
|
||||
------------------------------------------
|
||||
@Author: sm
|
||||
@Date: 2024.06.07 19:15
|
||||
@Date: 2026.06.01
|
||||
@Description: fsdlb 微信小程序逢三得利吧 签到积分
|
||||
cron: 30 9 * * *
|
||||
------------------------------------------
|
||||
#Notice:
|
||||
https://xiaodian.miyatech.com 小程序逢三得利吧签到积分,使用前请先获取token,方法如下:
|
||||
打开微信,进入逢三得利吧小程序,点击右下角“我的”,
|
||||
打开抓包软件抓取https://xiaodian.miyatech.com 请求头的Authorization
|
||||
抓取到的Authorization值即为token,去掉前面的"bearer ",将剩余部分作为token使用。
|
||||
变量名:fsdlb
|
||||
变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行
|
||||
需要配置:wx_server_url、wx_auth
|
||||
|
||||
⚠️【免责声明】
|
||||
------------------------------------------
|
||||
@@ -22,113 +20,269 @@ https://xiaodian.miyatech.com 小程序逢三得利吧签到积分,使用前
|
||||
7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。
|
||||
*/
|
||||
|
||||
const { Env } = require("../tools/env")
|
||||
const { Env } = require("../tools/env.js");
|
||||
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"
|
||||
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(env) {
|
||||
this.index = $.userIdx++
|
||||
this.user = env.split(strSplitor);
|
||||
this.token = "bearer " + this.user[0];
|
||||
|
||||
constructor(openid) {
|
||||
this.index = $.userIdx++;
|
||||
this.openid = String(openid || "").trim();
|
||||
this.token = "";
|
||||
this.userInfo = {};
|
||||
}
|
||||
|
||||
async run() {
|
||||
await this.info()
|
||||
await this.signIn()
|
||||
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() {
|
||||
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
|
||||
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();
|
||||
}
|
||||
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}🚫`)
|
||||
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()
|
||||
await getNotice();
|
||||
$.checkEnv(ckName);
|
||||
|
||||
for (let user of $.userList) {
|
||||
await new Task(user).run();
|
||||
for (const openid of $.userList) {
|
||||
await new Task(openid).run();
|
||||
}
|
||||
})()
|
||||
.catch((e) => console.log(e))
|
||||
.catch((e) => $.log(e.message || 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 {
|
||||
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) { }
|
||||
}
|
||||
+236
-85
@@ -1,18 +1,15 @@
|
||||
|
||||
|
||||
/*
|
||||
------------------------------------------
|
||||
@Author: sm
|
||||
@Date: 2024.06.07 19:15
|
||||
@Date: 2026.06.01
|
||||
@Description: 国乐酱酒小程序
|
||||
cron: 30 9 * * *
|
||||
------------------------------------------
|
||||
#Notice:
|
||||
变量名:gyjj
|
||||
国乐酱酒小程序签到,使用前请先获取token,方法如下:
|
||||
打开微信,进入国乐酱酒小程序,点击右下角“我的”,
|
||||
打开抓包软件抓取https://member.guoyuejiu.com/api/sign/daily/sign 请求头的Authorization
|
||||
抓取到的Authorization值即为token
|
||||
#Notice:
|
||||
变量名: gyjj
|
||||
变量值:wx_server 里的 openid/账号标识,多账号&或换行
|
||||
需要配置:wx_server_url、wx_auth
|
||||
|
||||
⚠️【免责声明】
|
||||
------------------------------------------
|
||||
1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。
|
||||
@@ -24,94 +21,254 @@ cron: 30 9 * * *
|
||||
7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。
|
||||
*/
|
||||
|
||||
const { Env } = require("../tools/env")
|
||||
const { Env } = require("../tools/env.js");
|
||||
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"
|
||||
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.user = env.split(strSplitor);
|
||||
this.token = this.user[0];
|
||||
|
||||
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登录`);
|
||||
}
|
||||
}
|
||||
|
||||
await this.sign()
|
||||
await this.account()
|
||||
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/operatedata`, {
|
||||
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 {
|
||||
|
||||
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}⛔`)
|
||||
}
|
||||
const result = await this.request("/sign/daily/sign");
|
||||
$.log(`🕊账号[${this.index}] 签到成功:签到[${result.data?.spanSumDays ?? "未知"}]天🎉`);
|
||||
} catch (e) {
|
||||
console.log(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 {
|
||||
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}🚫`)
|
||||
}
|
||||
const result = await this.request("/user/info");
|
||||
this.userInfo = result.data || {};
|
||||
this.saveCachedToken();
|
||||
$.log(`🕊账号[${this.index}] 查询成功:总积分[${result.data?.score ?? "未知"}]🎉`);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
const message = String(e.message || e);
|
||||
$.log(`🕊账号[${this.index}] 查询失败:${message}🚫`);
|
||||
if (isTokenError(message)) this.removeCachedToken();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
!(async () => {
|
||||
await getNotice()
|
||||
await getNotice();
|
||||
$.checkEnv(ckName);
|
||||
|
||||
for (let user of $.userList) {
|
||||
for (const user of $.userList) {
|
||||
await new Task(user).run();
|
||||
}
|
||||
})()
|
||||
@@ -119,19 +276,13 @@ 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 {
|
||||
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) {}
|
||||
}
|
||||
+422
-215
@@ -1,13 +1,14 @@
|
||||
/*
|
||||
------------------------------------------
|
||||
@Author: sm
|
||||
@Date: 2024.06.07 19:15
|
||||
@Date: 2026.06.01
|
||||
@Description: 海天美味馆小程序
|
||||
cron: 30 11 * * *
|
||||
------------------------------------------
|
||||
#Notice:
|
||||
抓取https://cmallapi.xkmm.cn请求头的authorization和uuid参数,填入环境变量,格式如下:
|
||||
authorization#uuid 多账号&或换行
|
||||
#Notice:
|
||||
变量名 haitian
|
||||
变量值:wx_server 里的 openid/账号标识,多账号&或换行
|
||||
需要配置:wx_server_url、wx_auth
|
||||
|
||||
⚠️【免责声明】
|
||||
------------------------------------------
|
||||
@@ -17,235 +18,447 @@ authorization#uuid 多账号&或换行
|
||||
4、此脚本涉及应用与本人无关,本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。
|
||||
5、本人对任何脚本引发的问题概不负责,包括但不限于由脚本错误引起的任何损失和损害。
|
||||
6、如果任何单位或个人认为此脚本可能涉嫌侵犯其权利,应及时通知并提供身份证明,所有权证明,我们将在收到认证文件确认后删除此脚本。
|
||||
7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。
|
||||
7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此免责声明。
|
||||
*/
|
||||
|
||||
const { Env } = require("../tools/env")
|
||||
const { Env } = require("../tools/env.js");
|
||||
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"
|
||||
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");
|
||||
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 || ""));
|
||||
}
|
||||
|
||||
class Task {
|
||||
constructor(env) {
|
||||
this.index = $.userIdx++
|
||||
this.user = env.split(strSplitor);
|
||||
this.token = this.user[0];
|
||||
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.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"
|
||||
this.userInfo = {};
|
||||
this.isLegacyToken = this.user.length >= 2;
|
||||
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() {
|
||||
|
||||
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;
|
||||
if (this.isLegacyToken) {
|
||||
$.log(`账号[${this.index}] 检测到旧版 authorization#uuid 格式,先迁移到缓存`);
|
||||
this.saveCachedToken();
|
||||
} 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)
|
||||
|
||||
}
|
||||
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失效,重新CODE登录`);
|
||||
}
|
||||
}
|
||||
} 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()
|
||||
|
||||
if (!this.token) {
|
||||
await this.loginByWxCode();
|
||||
if (!this.token) return;
|
||||
}
|
||||
} else {
|
||||
$.log(`当前剩余抽奖次数0`)
|
||||
}
|
||||
|
||||
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();
|
||||
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;
|
||||
}
|
||||
|
||||
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/operatedata`, {
|
||||
appid: MINI_APP_ID,
|
||||
openid: this.accountId,
|
||||
}, {
|
||||
headers: { auth: process.env.wx_auth },
|
||||
timeout: 45000,
|
||||
validateStatus: () => true,
|
||||
});
|
||||
const result = data?.data || {};
|
||||
if (!data?.status || !result.code || !result.encryptedData || !result.iv) {
|
||||
throw new Error(`wx_server 未返回完整登录数据: ${JSON.stringify(data)}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
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 wxData = await this.getOperateData();
|
||||
const articleIds = await this.getArticleIds();
|
||||
const params = {
|
||||
edata: wxData.encryptedData,
|
||||
iv: wxData.iv,
|
||||
code: wxData.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}] CODE登录成功: ${shortToken(this.token)}`);
|
||||
} catch (e) {
|
||||
$.log(`账号[${this.index}] CODE登录失败: ${e.message || e}`);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
$.log(`签到失败 [${result?.message || JSON.stringify(result)}]`);
|
||||
}
|
||||
} catch (e) {
|
||||
const message = String(e.message || e);
|
||||
if (/已签|重复/.test(message)) {
|
||||
$.log("今日已签到");
|
||||
return;
|
||||
}
|
||||
$.log(`签到失败 [${message}]`);
|
||||
}
|
||||
}
|
||||
|
||||
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}🎉`);
|
||||
} else {
|
||||
$.log(`🌸账号[${this.index}] 抽奖-失败:${JSON.stringify(result)}❌`);
|
||||
}
|
||||
} catch (e) {
|
||||
$.log(`🌸账号[${this.index}] 抽奖-失败:${e.message || e}❌`);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$.log(`🌸账号[${this.index}] 抽奖次数任务-失败:${JSON.stringify(result)}❌`);
|
||||
}
|
||||
} catch (e) {
|
||||
$.log(`🌸账号[${this.index}] 抽奖次数任务-失败:${e.message || e}❌`);
|
||||
}
|
||||
}
|
||||
|
||||
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++) {
|
||||
await this.doLottery();
|
||||
}
|
||||
} else {
|
||||
$.log("当前剩余抽奖次数0");
|
||||
}
|
||||
} catch (e) {
|
||||
$.log(`查询抽奖次数失败:${e.message || e}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
!(async () => {
|
||||
await getNotice()
|
||||
await getNotice();
|
||||
$.checkEnv(ckName);
|
||||
|
||||
for (let user of $.userList) {
|
||||
for (const user of $.userList) {
|
||||
await new Task(user).run();
|
||||
}
|
||||
})()
|
||||
@@ -253,19 +466,13 @@ 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 {
|
||||
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) {}
|
||||
}
|
||||
+118
-18
@@ -7,7 +7,8 @@ cron: 30 7 * * *
|
||||
------------------------------------------
|
||||
#Notice:
|
||||
变量名hezj
|
||||
抓取https://zjrs.haier.net请求头accounttoken 多账户&或换行
|
||||
变量值填写 wx_server 里的 openid/账号标识,多账户&或换行
|
||||
需要配置 wx_server_url、wx_auth
|
||||
|
||||
⚠️【免责声明】
|
||||
------------------------------------------
|
||||
@@ -25,47 +26,144 @@ const $ = new Env("海尔智家");
|
||||
let ckName = `hezj`;
|
||||
const strSplitor = "#";
|
||||
const axios = require("axios");
|
||||
const crypto = require("crypto");
|
||||
const WeChatCodeServer = require("../wxapp/wcs");
|
||||
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 = "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 wechat = new WeChatCodeServer({
|
||||
url: process.env.wx_server_url || "http://192.168.31.196:8787",
|
||||
appid: MINI_APP_ID,
|
||||
auth: process.env.wx_auth || "",
|
||||
});
|
||||
|
||||
function sign256(path, body, timestamp) {
|
||||
const bodyStr = body ? JSON.stringify(body) : "";
|
||||
return crypto.createHash("sha256").update(path + bodyStr + HA_APP_ID + HA_APP_KEY + timestamp).digest("hex");
|
||||
}
|
||||
|
||||
function maskToken(token = "") {
|
||||
if (!token) return "";
|
||||
return token.length > 14 ? `${token.slice(0, 6)}...${token.slice(-6)}` : token;
|
||||
}
|
||||
|
||||
|
||||
class Task {
|
||||
constructor(env) {
|
||||
this.index = $.userIdx++
|
||||
this.user = env.split(strSplitor);
|
||||
this.token = this.user[0];
|
||||
this.openid = this.user[0].trim();
|
||||
this.token = "";
|
||||
this.clientId = `${Date.now()}${$.randomString(12)}`;
|
||||
|
||||
}
|
||||
request(options) {
|
||||
const path = options.path || new URL(options.url).pathname;
|
||||
const timestamp = Date.now();
|
||||
let baseHeaers = {
|
||||
"host": "zj.haier.net",
|
||||
"content-type": "application/json",
|
||||
"accounttoken": this.token,
|
||||
"appid": "MB-UZHSH-0001",
|
||||
"Content-Type": "application/json;charset=UTF-8",
|
||||
"appId": HA_APP_ID,
|
||||
"appKey": HA_APP_KEY,
|
||||
"timestamp": timestamp,
|
||||
"platForm": "sc-mp-wx-zjapp",
|
||||
"ENV": "",
|
||||
"accessToken": options.isHeaderDelToken ? "" : this.token,
|
||||
"accountToken": options.isHeaderDelToken ? "" : this.token,
|
||||
"ak": options.isHeaderDelToken ? "" : this.token,
|
||||
"clientId": this.clientId,
|
||||
"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"
|
||||
"user-agent": defaultUserAgent,
|
||||
"referer": `https://servicewechat.com/${MINI_APP_ID}/${PAGE_VERSION}/page-frame.html`,
|
||||
}
|
||||
options.headers = Object.assign(baseHeaers, options.headers)
|
||||
if (options.isSign256) {
|
||||
baseHeaers.sign = sign256(path, options.data, timestamp);
|
||||
}
|
||||
options.headers = Object.assign(baseHeaers, options.headers || {});
|
||||
delete options.path;
|
||||
delete options.isSign256;
|
||||
delete options.isHeaderDelToken;
|
||||
return axios.request(options)
|
||||
}
|
||||
|
||||
async run() {
|
||||
|
||||
await this.loginByWxCode();
|
||||
if (!this.token) return;
|
||||
await this.pointInfo()
|
||||
await this.signIn()
|
||||
}
|
||||
|
||||
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 tokenInfo = await this.jscode2session(code);
|
||||
const accountToken = tokenInfo?.accountToken;
|
||||
if (!accountToken) throw new Error(`登录响应未返回 accountToken: ${JSON.stringify(tokenInfo)}`);
|
||||
await this.queryUserInfo(accountToken);
|
||||
this.token = accountToken;
|
||||
$.log(`账号[${this.index}] CODE登录成功: ${maskToken(this.token)}`);
|
||||
} catch (e) {
|
||||
$.log(`账号[${this.index}] CODE登录失败: ${e.message || e}`);
|
||||
}
|
||||
}
|
||||
|
||||
async jscode2session(code) {
|
||||
const path = "/api-gw/oauthserver/applet/v1/jscode2session";
|
||||
let options = {
|
||||
method: "POST",
|
||||
url: API_HOST + path,
|
||||
path,
|
||||
isSign256: true,
|
||||
isHeaderDelToken: true,
|
||||
data: { code },
|
||||
};
|
||||
const { data: result } = await this.request(options);
|
||||
if (result?.retCode !== "00000" && result?.code !== 200 && !result?.success) {
|
||||
throw new Error(result?.retInfo || result?.message || JSON.stringify(result));
|
||||
}
|
||||
return result?.data?.tokenInfo || result?.data || {};
|
||||
}
|
||||
|
||||
async queryUserInfo(accountToken) {
|
||||
const path = "/api-gw/oauthserver/applet/v1/userinfo/query";
|
||||
let options = {
|
||||
method: "POST",
|
||||
url: API_HOST + path,
|
||||
path,
|
||||
isSign256: true,
|
||||
isHeaderDelToken: true,
|
||||
data: { accountToken },
|
||||
};
|
||||
const { data: result } = await this.request(options);
|
||||
if (result?.retCode !== "00000" && result?.code !== 200 && !result?.success) {
|
||||
throw new Error(result?.retInfo || result?.message || JSON.stringify(result));
|
||||
}
|
||||
const info = result?.data?.userinfo || {};
|
||||
const name = info.nickName || info.nickname || info.userName || "未知用户";
|
||||
const phone = info.mobile || info.phoneNumber || "";
|
||||
$.log(`账号[${this.index}] 用户: ${name}${phone ? ` ${phone.slice(0, 3)}****${phone.slice(-4)}` : ""}`);
|
||||
return info;
|
||||
}
|
||||
|
||||
async pointInfo() {
|
||||
const path = "/zjapi/zjBaseServer/signDetail/getUserPointsAndWallet";
|
||||
let options = {
|
||||
method: 'POST',
|
||||
url: `https://zj.haier.net/zjapi/zjBaseServer/signDetail/getUserPointsAndWallet`,
|
||||
url: API_HOST + path,
|
||||
path,
|
||||
headers: {},
|
||||
data: {
|
||||
|
||||
@@ -82,9 +180,11 @@ class Task {
|
||||
}
|
||||
|
||||
async signIn() {
|
||||
const path = "/api-gw/zjBaseServer/daily/sign";
|
||||
let options = {
|
||||
method: 'POST',
|
||||
url: `https://zj.haier.net/api-gw/zjBaseServer/daily/sign`,
|
||||
url: API_HOST + path,
|
||||
path,
|
||||
headers: {},
|
||||
data: {
|
||||
|
||||
|
||||
+332
-249
@@ -1,15 +1,14 @@
|
||||
|
||||
/*
|
||||
------------------------------------------
|
||||
@Author: sm
|
||||
@Date: 2024.06.07 19:15
|
||||
@Date: 2026.06.01
|
||||
@Description: IQOO社区小程序 积分脚本
|
||||
cron: 30 8 * * *
|
||||
------------------------------------------
|
||||
#Notice:
|
||||
变量名iqoo
|
||||
抓取方法:https://bbs-api.iqoo.com请求头authorization 去掉Bearer
|
||||
多账户&或换行
|
||||
#Notice:
|
||||
变量名 iqoo
|
||||
变量值:wx_server 里的 openid/账号标识,多账户&或换行
|
||||
需要配置:wx_server_url、wx_auth
|
||||
|
||||
⚠️【免责声明】
|
||||
------------------------------------------
|
||||
@@ -22,274 +21,362 @@ cron: 30 8 * * *
|
||||
7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。
|
||||
*/
|
||||
|
||||
const { Env } = require("../tools/env")
|
||||
const { Env } = require("../tools/env.js");
|
||||
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"
|
||||
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 = env.split(strSplitor);
|
||||
this.token = this.user[0];
|
||||
this.postId = ''
|
||||
this.threadId = ''
|
||||
|
||||
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");
|
||||
}
|
||||
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()
|
||||
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.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()
|
||||
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/operatedata`, {
|
||||
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() {
|
||||
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}] 抽奖过`)
|
||||
|
||||
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() {
|
||||
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}`)
|
||||
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() {
|
||||
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}❌`)
|
||||
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) {
|
||||
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}❌`)
|
||||
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}❌`);
|
||||
}
|
||||
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}❌`)
|
||||
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) {
|
||||
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}❌`)
|
||||
try {
|
||||
await this.request("v3/thread.share", { threadId });
|
||||
$.log(`账号[${this.index}] 帖子分享成功`);
|
||||
} catch (e) {
|
||||
$.log(`账号[${this.index}] 帖子分享失败:${e.message || e}❌`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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}❌`)
|
||||
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) {
|
||||
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}❌`)
|
||||
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() {
|
||||
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
|
||||
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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()
|
||||
await getNotice();
|
||||
$.checkEnv(ckName);
|
||||
|
||||
for (let user of $.userList) {
|
||||
for (const user of $.userList) {
|
||||
await new Task(user).run();
|
||||
}
|
||||
})()
|
||||
@@ -297,20 +384,16 @@ 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 {
|
||||
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) {}
|
||||
}
|
||||
|
||||
+249
-64
@@ -1,14 +1,16 @@
|
||||
/*
|
||||
------------------------------------------
|
||||
@Author: sm
|
||||
@Date: 2024.06.07 19:15
|
||||
@Date: 2026.06.01
|
||||
@Description: 康师傅畅饮社
|
||||
cron: 30 10 * * *
|
||||
------------------------------------------
|
||||
#Notice:
|
||||
#Notice:
|
||||
康师傅畅饮社小程序
|
||||
变量名 ksfcys
|
||||
账号格式:抓https://club.biqr.cn/api/请求头token 多账户&或换行
|
||||
变量值:wx_server 里的 openid/账号标识,多账户&或换行
|
||||
需要配置:wx_server_url、wx_auth
|
||||
|
||||
⚠️【免责声明】
|
||||
------------------------------------------
|
||||
1、此脚本仅用于学习研究,不保证其合法性、准确性、有效性,请根据情况自行判断,本人对此不承担任何保证责任。
|
||||
@@ -20,92 +22,275 @@ cron: 30 10 * * *
|
||||
7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。
|
||||
*/
|
||||
|
||||
const { Env } = require("../tools/env")
|
||||
const { Env } = require("../tools/env.js");
|
||||
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"
|
||||
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(env) {
|
||||
this.index = $.userIdx++
|
||||
this.user = env.split(strSplitor);
|
||||
this.token = this.user[0];
|
||||
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失效,重新登录`);
|
||||
}
|
||||
}
|
||||
|
||||
async run() {
|
||||
if (!this.token) {
|
||||
await this.loginByWxCode();
|
||||
if (!this.token) return;
|
||||
}
|
||||
|
||||
await this.signIn()
|
||||
}
|
||||
await this.memberInfo();
|
||||
await this.signIn();
|
||||
await this.memberInfo("签到后");
|
||||
}
|
||||
|
||||
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: {
|
||||
getCachedToken() {
|
||||
const cache = readTokenCache();
|
||||
return cache[this.openid] || null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
let { data: result } = await axios.request(options);
|
||||
if (result.code == 0) {
|
||||
$.log(`账号[${this.index}]【${this.name}】 签到成功`);
|
||||
} else {
|
||||
$.log(result);
|
||||
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);
|
||||
await getNotice();
|
||||
$.checkEnv(ckName);
|
||||
|
||||
for (let user of $.userList) {
|
||||
await new Task(user).run();
|
||||
}
|
||||
for (const user of $.userList) {
|
||||
await new Task(user).run();
|
||||
}
|
||||
})()
|
||||
.catch((e) => console.log(e))
|
||||
.finally(() => $.done());
|
||||
.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 {
|
||||
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) {}
|
||||
}
|
||||
@@ -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) {}
|
||||
|
||||
}
|
||||
+225
-85
@@ -1,13 +1,14 @@
|
||||
/*
|
||||
------------------------------------------
|
||||
@Author: sm
|
||||
@Date: 2024.06.07 19:15
|
||||
@Date: 2026.06.01
|
||||
@Description: 植白说小程序
|
||||
cron: 30 8 * * *
|
||||
------------------------------------------
|
||||
#Notice:
|
||||
#Notice:
|
||||
变量名称:zbs
|
||||
值抓取https://www.kozbs.com/demo 请求头x-dts-token
|
||||
变量值:wx_server 里的 openid/账号标识,多账号用 & 或换行
|
||||
需要配置:wx_server_url、wx_auth
|
||||
|
||||
⚠️【免责声明】
|
||||
------------------------------------------
|
||||
@@ -20,93 +21,235 @@ cron: 30 8 * * *
|
||||
7、所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本,即视为您已接受此免责声明。
|
||||
*/
|
||||
|
||||
const { Env } = require("../tools/env")
|
||||
const { Env } = require("../tools/env.js");
|
||||
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"
|
||||
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(env) {
|
||||
this.index = $.userIdx++
|
||||
this.user = env.split(strSplitor);
|
||||
this.token = this.user[0];
|
||||
|
||||
constructor(openid) {
|
||||
this.index = $.userIdx++;
|
||||
this.openid = String(openid || "").trim();
|
||||
this.token = "";
|
||||
this.userInfo = {};
|
||||
}
|
||||
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() {
|
||||
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失效,重新登录`);
|
||||
}
|
||||
}
|
||||
|
||||
await this.signIn()
|
||||
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() {
|
||||
let options = {
|
||||
method: 'GET',
|
||||
url: "https://www.kozbs.com/demo/wx/home/sign?userId=",
|
||||
headers: {},
|
||||
try {
|
||||
const status = await this.request("home/signDay", {
|
||||
data: { userId: this.userId },
|
||||
});
|
||||
if (status?.data?.isSign) {
|
||||
$.log(`🌸账号[${this.index}] 今日已签到`);
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
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}❌`)
|
||||
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()
|
||||
await getNotice();
|
||||
$.checkEnv(ckName);
|
||||
|
||||
for (let user of $.userList) {
|
||||
for (const user of $.userList) {
|
||||
await new Task(user).run();
|
||||
}
|
||||
})()
|
||||
@@ -114,19 +257,16 @@ 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 {
|
||||
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) {}
|
||||
}
|
||||
Reference in new issue
Block a user