mirror of
https://github.com/XiaoGe-LiBai/yangmao.git
synced 2025-12-17 05:18:14 +08:00
224 lines
8.2 KiB
JavaScript
224 lines
8.2 KiB
JavaScript
// ==UserScript==
|
||
// @name 浓五酒馆自动登录签到
|
||
// @namespace http://tampermonkey.net/
|
||
// @version 1.1
|
||
// @description 青龙面板脚本,浓五酒馆自动签到,支持 JWT Token 缓存
|
||
// @match http://*/*
|
||
// @grant none
|
||
// ==/UserScript==
|
||
|
||
/*
|
||
环境变量说明:
|
||
- NWJG_CK: 登录请求体,JSON 格式,例: {"code":"xxx","appId":"wxed3cf95a14b58a26"}
|
||
- NWJG_TOKEN: 缓存的 JWT Token,例: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9...
|
||
- 多账号: NWJG_CK 和 NWJG_TOKEN 用 & 分隔,顺序对应
|
||
- 获取 NWJG_CK: 抓包 POST https://stdcrm.dtmiller.com/std-weixin-mp-service/miniApp/custom/login 的 Request Body
|
||
*/
|
||
|
||
const axios = require('axios');
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
// 环境变量名称
|
||
const CK_ENV_NAME = 'NWJG_CK';
|
||
const TOKEN_ENV_NAME = 'NWJG_TOKEN';
|
||
const TOKEN_FILE = path.join(__dirname, 'nwjg_token.json'); // 持久化存储 token
|
||
|
||
// 日志前缀
|
||
const LOG_PREFIX = '[浓五酒馆自动登录签到]';
|
||
|
||
// API 配置
|
||
const BASE_URL = 'https://stdcrm.dtmiller.com';
|
||
const LOGIN_API = '/std-weixin-mp-service/miniApp/custom/login';
|
||
const USER_INFO_API = '/scrm-promotion-service/mini/wly/user/info';
|
||
const SIGN_INFO_API = '/scrm-promotion-service/promotion/sign/userinfo?promotionId=PI6811d6f99b099a000a0c4613';
|
||
const SIGN_TODAY_API = '/scrm-promotion-service/promotion/sign/today?promotionId=PI6811d6f99b099a000a0c4613';
|
||
|
||
// 请求头模板
|
||
const HEADERS = {
|
||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090c33)XWEB/13487',
|
||
'Content-Type': 'application/json',
|
||
'Accept': '*/*',
|
||
'sec-fetch-site': 'cross-site',
|
||
'sec-fetch-mode': 'cors',
|
||
'sec-fetch-dest': 'empty',
|
||
'Referer': 'https://servicewechat.com/wxed3cf95a14b58a26/223/page-frame.html',
|
||
'Accept-Encoding': 'gzip, deflate, br',
|
||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
||
'Priority': 'u=1, i'
|
||
};
|
||
|
||
// 获取环境变量
|
||
function getEnv(key) {
|
||
return process.env[key] || '';
|
||
}
|
||
|
||
// 读取缓存的 token
|
||
function readTokens() {
|
||
try {
|
||
if (fs.existsSync(TOKEN_FILE)) {
|
||
return JSON.parse(fs.readFileSync(TOKEN_FILE, 'utf8'));
|
||
}
|
||
} catch (error) {
|
||
console.log(`${LOG_PREFIX} 读取 token 失败: ${error.message}`);
|
||
}
|
||
return {};
|
||
}
|
||
|
||
// 保存 token 到文件
|
||
function saveTokens(tokens) {
|
||
try {
|
||
fs.writeFileSync(TOKEN_FILE, JSON.stringify(tokens, null, 2));
|
||
} catch (error) {
|
||
console.log(`${LOG_PREFIX} 保存 token 失败: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
// 发送通知
|
||
function sendNotify(title, content) {
|
||
console.log(`${title}\n${content}`);
|
||
}
|
||
|
||
// 登录获取 Token
|
||
async function login(requestBody) {
|
||
try {
|
||
const response = await axios.post(`${BASE_URL}${LOGIN_API}`, requestBody, { headers: HEADERS });
|
||
if (response.data.code === 0 && response.data.data) {
|
||
return response.data.data; // 返回 JWT Token
|
||
} else {
|
||
throw new Error(response.data.msg || '登录失败');
|
||
}
|
||
} catch (error) {
|
||
throw new Error(`登录请求失败: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
// 获取用户信息
|
||
async function getUserInfo(token) {
|
||
try {
|
||
const headers = { ...HEADERS, 'Authorization': `Bearer ${token}` };
|
||
const response = await axios.get(`${BASE_URL}${USER_INFO_API}`, { headers });
|
||
if (response.data.code === 0 && response.data.data) {
|
||
return response.data.data;
|
||
} else {
|
||
throw new Error(response.data.msg || '获取用户信息失败');
|
||
}
|
||
} catch (error) {
|
||
throw new Error(`获取用户信息失败: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
// 获取签到信息
|
||
async function getSignInfo(token) {
|
||
try {
|
||
const headers = { ...HEADERS, 'Authorization': `Bearer ${token}` };
|
||
const response = await axios.get(`${BASE_URL}${SIGN_INFO_API}`, { headers });
|
||
if (response.data.code === 0 && response.data.data) {
|
||
return response.data.data;
|
||
} else {
|
||
throw new Error(response.data.msg || '获取签到信息失败');
|
||
}
|
||
} catch (error) {
|
||
throw new Error(`获取签到信息失败: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
// 执行今日签到
|
||
async function doSignToday(token) {
|
||
try {
|
||
const headers = { ...HEADERS, 'Authorization': `Bearer ${token}` };
|
||
const response = await axios.get(`${BASE_URL}${SIGN_TODAY_API}`, { headers });
|
||
if (response.data.code === 0 && response.data.data) {
|
||
return response.data.data;
|
||
} else {
|
||
throw new Error(response.data.msg || '签到失败');
|
||
}
|
||
} catch (error) {
|
||
throw new Error(`签到请求失败: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
// 主函数
|
||
async function main() {
|
||
const accounts = getEnv(CK_ENV_NAME).split('&').filter(Boolean);
|
||
const tokenEnv = getEnv(TOKEN_ENV_NAME).split('&').filter(Boolean);
|
||
let tokens = readTokens();
|
||
|
||
if (!accounts.length) {
|
||
sendNotify(LOG_PREFIX, '❌ 未配置环境变量 NWJG_CK');
|
||
return;
|
||
}
|
||
|
||
for (let i = 0; i < accounts.length; i++) {
|
||
const account = accounts[i];
|
||
const accountKey = `account_${i}`; // 每个账号的唯一键
|
||
console.log(`\n${LOG_PREFIX} 处理第 ${i + 1} 个账号`);
|
||
|
||
try {
|
||
// 解析请求体
|
||
let requestBody;
|
||
try {
|
||
requestBody = JSON.parse(account);
|
||
} catch (error) {
|
||
sendNotify(LOG_PREFIX, `❌ 账号 ${i + 1} 环境变量格式错误: ${error.message}`);
|
||
continue;
|
||
}
|
||
|
||
// 尝试使用缓存的 token
|
||
let token = tokens[accountKey] || tokenEnv[i];
|
||
let tokenValid = false;
|
||
|
||
if (token) {
|
||
console.log(`${LOG_PREFIX} 🚀 尝试使用缓存的 token...`);
|
||
try {
|
||
await getUserInfo(token); // 测试 token 是否有效
|
||
tokenValid = true;
|
||
console.log(`${LOG_PREFIX} ✅ 缓存 token 有效`);
|
||
} catch (error) {
|
||
console.log(`${LOG_PREFIX} ⚠️ 缓存 token 无效: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
// 如果 token 无效,重新登录
|
||
if (!tokenValid) {
|
||
console.log(`${LOG_PREFIX} 🚀 尝试登录...`);
|
||
token = await login(requestBody);
|
||
tokens[accountKey] = token;
|
||
saveTokens(tokens);
|
||
console.log(`${LOG_PREFIX} ✅ 登录成功,token 已缓存`);
|
||
}
|
||
|
||
// 获取用户信息
|
||
const userInfo = await getUserInfo(token);
|
||
const member = userInfo.member;
|
||
const grade = userInfo.grade;
|
||
console.log(`${LOG_PREFIX} 👤 用户信息: ${member.nick_name} (${member.mobile})`);
|
||
console.log(`${LOG_PREFIX} 🎖️ 会员等级: ${grade.level_name} (到期: ${grade.expire_time})`);
|
||
console.log(`${LOG_PREFIX} 💰 当前积分: ${member.points}`);
|
||
|
||
// 获取签到信息
|
||
const signInfo = await getSignInfo(token);
|
||
console.log(`${LOG_PREFIX} 📅 签到活动: ${signInfo.promotionName}`);
|
||
console.log(`${LOG_PREFIX} 📈 累计签到: ${signInfo.signDays} 天`);
|
||
console.log(`${LOG_PREFIX} 🎁 今日奖励: ${signInfo.signDayPrizeName}`);
|
||
console.log(`${LOG_PREFIX} ✅ 今日已签: ${signInfo.today ? '是' : '否'}`);
|
||
|
||
// 如果今日未签到,执行签到
|
||
if (!signInfo.today) {
|
||
console.log(`${LOG_PREFIX} 🚀 尝试签到...`);
|
||
const signResult = await doSignToday(token);
|
||
console.log(`${LOG_PREFIX} ✅ 签到成功,获得: ${signResult.prize.prizeName}`);
|
||
} else {
|
||
console.log(`${LOG_PREFIX} ℹ️ 今日已签到,无需重复操作`);
|
||
}
|
||
|
||
} catch (error) {
|
||
sendNotify(LOG_PREFIX, `❌ 账号 ${i + 1} 处理失败: ${error.message}`);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 执行主函数
|
||
main().catch(error => {
|
||
sendNotify(LOG_PREFIX, `❌ 脚本执行异常: ${error.message}`);
|
||
}); |