feat(smzdm): 🚀 更新 App 版本并优化请求签名与风控对抗

* 升级 `APP_VERSION` 至 `11.1.95`,并同步更新 `APP_VERSION_REV`。
* 引入服务器时间同步机制:通过 `SERVER_TIME_URL` 获取服务端时间,解决本地时间偏差导致的签名失效问题。
* 优化签名算法:改进 `signFormData` 的实现,确保参数排序与空格处理符合最新 App 逻辑。
* 增强风控对抗能力:
    * 引入 `waitHuman` 模拟人类行为的等待机制,替换原有的固定 `wait`。
    * 在任务执行逻辑中加入随机打乱(Shuffle)机制,降低行为模式特征。
    * 增加对 WAF/风控拦截(如 403/429 错误或 HTML 验证码页)的识别与处理逻辑。
* 完善功能细节:
    * 支持 `SMZDM_COMMENT` 环境变量配置多条文案(使用 `|` 分隔),实现随机评论以降低风险。
    * 修复签到逻辑,支持 `CREATE_CENTER_VIEW` 和 `IS_INSTALL_ZHANGDAMA` 等新增参数。
    * 优化任务列表获取,增加对 `is_install_zhangdama` 字段的支持。
* 文档更新:在 `README.md` 中补充了新增任务类型及环境变量的使用说明。
This commit is contained in:
Hex
2026-10-13 16:56:44 +08:00
parent eff365b2a4
commit c325760c45
7 changed files with 574 additions and 286 deletions

View File

@@ -20,6 +20,10 @@
* 关注用户 * 关注用户
* 关注栏目 * 关注栏目
* 关注品牌 * 关注品牌
* 站外浏览
* 打开第三方 App
* 开启推送
* 创建桌面签到快捷方式
* 限时累计活动 * 限时累计活动
* 全民众测能量值任务 * 全民众测能量值任务
@@ -62,7 +66,7 @@ ql repo https://github.com/hex-ci/smzdm_script.git "smzdm_" "" "env.js|bot.js|se
* `SMZDM_SK`: 这个值是可选值,会自动计算,如果你一定想用自己的,可以抓取,是从安卓 App 的 `https://user-api.smzdm.com/checkin` 请求参数中抓包抓到的,多用户可以用 `&` 分隔,或者使用多个同名环境变量,顺序要保持与 `SMZDM_COOKIE` 多用户顺序一致。 * `SMZDM_SK`: 这个值是可选值,会自动计算,如果你一定想用自己的,可以抓取,是从安卓 App 的 `https://user-api.smzdm.com/checkin` 请求参数中抓包抓到的,多用户可以用 `&` 分隔,或者使用多个同名环境变量,顺序要保持与 `SMZDM_COOKIE` 多用户顺序一致。
* `SMZDM_USER_AGENT_APP`: 这个值是可选值,是指 APP 的 User-Agent,从 APP 的 API 请求头中抓包得到,建议抓取 Android 的 User-Agent,不填使用脚本默认值。 * `SMZDM_USER_AGENT_APP`: 这个值是可选值,是指 APP 的 User-Agent,从 APP 的 API 请求头中抓包得到,建议抓取 Android 的 User-Agent,不填使用脚本默认值。
* `SMZDM_USER_AGENT_WEB`: 这个值是可选值,是指 APP 中访问网页的 User-Agent,一般在 APP 内的转盘网页中抓包得到,建议抓取 Android 的 User-Agent,不填使用脚本默认值。 * `SMZDM_USER_AGENT_WEB`: 这个值是可选值,是指 APP 中访问网页的 User-Agent,一般在 APP 内的转盘网页中抓包得到,建议抓取 Android 的 User-Agent,不填使用脚本默认值。
* `SMZDM_COMMENT`: 如果要完成评论文章的任务请设置这个环境变量,环境变量的内容是评论的文案,文案要大于 10 个汉字,建议用比较个性化的文案,脚本发布评论后会删除这条评论,但是为防止删除失败的情况,请尽量用好一点的文案,防止被判定为恶意灌水。 * `SMZDM_COMMENT`: 如果要完成评论文章的任务请设置这个环境变量,环境变量的内容是评论的文案,文案要大于 10 个汉字,建议用比较个性化的文案,脚本发布评论后会删除这条评论,但是为防止删除失败的情况,请尽量用好一点的文案,防止被判定为恶意灌水。可以写多条文案(用换行或 `|` 分隔,每条都要大于 10 个汉字),脚本每次随机选一条,避免每天发同样的内容。
* `SMZDM_CROWD_SILVER_5`: 每日抽奖任务默认只进行免费抽奖,如要进行 5 碎银子的抽奖,请设置这个环境变量的值为 `yes`,请注意,只有在没有免费抽奖的时候,才会执行非免费抽奖,而且,这个抽奖不是转盘抽奖。 * `SMZDM_CROWD_SILVER_5`: 每日抽奖任务默认只进行免费抽奖,如要进行 5 碎银子的抽奖,请设置这个环境变量的值为 `yes`,请注意,只有在没有免费抽奖的时候,才会执行非免费抽奖,而且,这个抽奖不是转盘抽奖。
* `SMZDM_CROWD_KEYWORD`: 抽奖关键词,执行非免费抽奖时,会优先选择包含此关键词的抽奖,如果未找到包含此关键词的抽奖,则会随机选择一个。 * `SMZDM_CROWD_KEYWORD`: 抽奖关键词,执行非免费抽奖时,会优先选择包含此关键词的抽奖,如果未找到包含此关键词的抽奖,则会随机选择一个。
* `SMZDM_TASK_TESTING`: 是否运行全民众测能量值任务,如要运行此任务,请设置这个环境变量的值为 `yes`,否则不运行。 * `SMZDM_TASK_TESTING`: 是否运行全民众测能量值任务,如要运行此任务,请设置这个环境变量的值为 `yes`,否则不运行。

134
bot.js
View File

@@ -3,28 +3,62 @@ const got = require('got');
// ------------------------------------ // ------------------------------------
const APP_VERSION = '10.4.26'; const APP_VERSION = '11.1.95';
const APP_VERSION_REV = '866'; const APP_VERSION_REV = '1195';
const DEFAULT_USER_AGENT_APP = `smzdm_android_V${APP_VERSION} rv:${APP_VERSION_REV} (Redmi Note 3;Android10.0;zh)smzdmapp`; const DEFAULT_USER_AGENT_APP = `smzdm_android_V${APP_VERSION} rv:${APP_VERSION_REV} (Redmi Note 3;Android10.0;zh)smzdmapp`;
const DEFAULT_USER_AGENT_WEB = `Mozilla/5.0 (Linux; Android 10.0; Redmi Build/Redmi Note 3; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/95.0.4638.74 Mobile Safari/537.36 smzdm_android_V${APP_VERSION} rv:${APP_VERSION_REV} (Redmi;Android10.0;zh) jsbv_1.0.0 webv_2.0 smzdmapp`; const DEFAULT_USER_AGENT_WEB = `Mozilla/5.0 (Linux; Android 10.0; Redmi Build/Redmi Note 3; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/95.0.4638.74 Mobile Safari/537.36 smzdm_android_V${APP_VERSION} rv:${APP_VERSION_REV} (Redmi;Android10.0;zh) jsbv_1.0.0 webv_2.0 smzdmapp`;
const SIGN_KEY = 'apr1$AwP!wRRT$gJ/q.X24poeBInlUJC'; const SIGN_KEY = 'apr1$AwP!wRRT$gJ/q.X24poeBInlUJC';
const ZHUANZAI_AB = '';
// 无法从设备侧还原的本地开关取值,与全新安装的 APP 行为一致
const CREATE_CENTER_VIEW = '';
const IS_INSTALL_ZHANGDAMA = '0';
// APP 用 HTTP Date 头作为签名时间,且偏差超过 5 分钟会重新获取
const SERVER_TIME_URL = 'https://app-api.smzdm.com/get_server_time';
const SERVER_TIME_MAX_AGE = 5 * 60 * 1000;
// ------------------------------------ // ------------------------------------
let serverTime = 0;
let serverTimeFetchedAt = 0;
const reVersion = /(smzdm_android_V|smzdm\s|iphone_smzdmapp\/)([\d.]+)/i; const reVersion = /(smzdm_android_V|smzdm\s|iphone_smzdmapp\/)([\d.]+)/i;
const reRev = /rv:([\d.]+)/i; const reRev = /rv:([\d.]+)/i;
const randomStr = (len = 18) => { // request_key = 8 位随机数 + 秒级时间戳
const char = '0123456789'; const requestKey = () => `${Math.floor(Math.random() * 90000000) + 10000000}${Math.floor(Date.now() / 1000)}`;
let str = '';
for (let i = 0; i < len; i++) { const getServerTime = async () => {
str += char.charAt(Math.floor(Math.random() * char.length)); if (serverTime && Date.now() - serverTimeFetchedAt <= SERVER_TIME_MAX_AGE) {
return serverTime;
} }
return str; try {
// APP 直接读 HTTP Date 头,不关心状态码,取不到才回退本地时间
const response = await got(SERVER_TIME_URL, {
method: 'GET',
throwHttpErrors: false,
retry: {
limit: 0
}
});
const date = new Date(response.headers.date).getTime();
if (date) {
serverTime = date;
serverTimeFetchedAt = Date.now();
}
}
catch (error) {
console.log(`获取服务器时间失败,使用本地时间: ${error.message}`);
}
return serverTime || Date.now();
}; };
const parseJSON = (str) => { const parseJSON = (str) => {
@@ -39,19 +73,20 @@ const parseJSON = (str) => {
const removeTags = (str) => str.replace(/<[^<]+?>/g, ''); const removeTags = (str) => str.replace(/<[^<]+?>/g, '');
// 添加公共参数并签名数据 // 添加公共参数并签名数据
const signFormData = (data) => { const signFormData = async (data) => {
const newData = { const newData = {
weixin: 1, weixin: 1,
basic_v: 0, basic_v: 0,
f: 'android', f: 'android',
v: APP_VERSION, v: APP_VERSION,
time: `${Math.round(new Date().getTime() / 1000)}000`, time: `${Math.round((await getServerTime()) / 1000)}000`,
zhuanzai_ab: ZHUANZAI_AB,
...data ...data
}; };
const keys = Object.keys(newData).filter(key => newData[key] !== '').sort(); const keys = Object.keys(newData).filter(key => newData[key] !== '').sort();
const signData = keys.map(key => `${key}=${String(newData[key]).replace(/\s+/, '')}`).join('&'); const signData = keys.map(key => `${key}=${newData[key]}`).join('&');
const sign = crypto.createHash('md5').update(`${signData}&key=${SIGN_KEY}`).digest('hex').toUpperCase(); const sign = crypto.createHash('md5').update(`${signData.replace(/ /g, '')}&key=${SIGN_KEY}`).digest('hex').toUpperCase();
return { return {
...newData, ...newData,
@@ -74,7 +109,7 @@ const requestApi = async (url, inputOptions = {}) => {
Object.keys(options.data).forEach(key => options.data[key] === undefined && delete options.data[key]); Object.keys(options.data).forEach(key => options.data[key] === undefined && delete options.data[key]);
if (options.sign !== false) { if (options.sign !== false) {
options.data = signFormData(options.data); options.data = await signFormData(options.data);
} }
const gotOptions = { const gotOptions = {
@@ -139,10 +174,22 @@ const requestApi = async (url, inputOptions = {}) => {
}) })
}; };
const updateCookie = (cookie, name, value) => { // APP 每次请求都用自己维护的字段重建 Cookie,缺失的字段需要补上
const re = new RegExp(`(^|;)${name}=[^;]+;`, 'ig'); const setCookie = (cookie, name, value) => {
const re = new RegExp(`(^|;)\\s*${name}=[^;]+`, 'i');
return cookie.replace(re, `$1${name}=${encodeURIComponent(value)};`); if (re.test(cookie)) {
return cookie.replace(re, `$1${name}=${encodeURIComponent(value)}`);
}
return `${cookie.replace(/;?\s*$/, ';')} ${name}=${encodeURIComponent(value)};`;
};
// APP 不发送这些历史字段,保留会导致请求与 APP 不一致
const removeCookie = (cookie, name) => {
const re = new RegExp(`(^|;)\\s*${name}=[^;]+;?`, 'ig');
return cookie.replace(re, '$1');
}; };
const getEnvCookies = () => { const getEnvCookies = () => {
@@ -179,6 +226,14 @@ const wait = (minSecond, maxSecond) => {
return new Promise(resolve => setTimeout(resolve, randomSecond * 1000)); return new Promise(resolve => setTimeout(resolve, randomSecond * 1000));
}; };
const waitHuman = async (minSecond, maxSecond) => {
await wait(minSecond, maxSecond);
if (Math.random() < 0.05) {
await wait(15, 45);
}
};
// ------------------------------------ // ------------------------------------
class SmzdmBot { class SmzdmBot {
@@ -190,16 +245,23 @@ class SmzdmBot {
// 处理 cookie // 处理 cookie
this.androidCookie = this.cookie.replace('iphone', 'android').replace('iPhone', 'Android'); this.androidCookie = this.cookie.replace('iphone', 'android').replace('iPhone', 'Android');
this.androidCookie = updateCookie(this.androidCookie, 'smzdm_version', APP_VERSION); this.androidCookie = setCookie(this.androidCookie, 'v', APP_VERSION);
this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm_version', APP_VERSION); this.androidCookie = setCookie(this.androidCookie, 'device_smzdm_version_code', APP_VERSION_REV);
this.androidCookie = updateCookie(this.androidCookie, 'v', APP_VERSION); this.androidCookie = setCookie(this.androidCookie, 'device_system_version', '10.0');
this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm_version_code', APP_VERSION_REV); this.androidCookie = setCookie(this.androidCookie, 'apk_partner_name', 'smzdm_download');
this.androidCookie = updateCookie(this.androidCookie, 'device_system_version', '10.0'); this.androidCookie = setCookie(this.androidCookie, 'partner_name', 'smzdm_download');
this.androidCookie = updateCookie(this.androidCookie, 'apk_partner_name', 'smzdm_download'); this.androidCookie = setCookie(this.androidCookie, 'device_smzdm', 'android');
this.androidCookie = updateCookie(this.androidCookie, 'partner_name', 'smzdm_download'); this.androidCookie = setCookie(this.androidCookie, 'f', 'android');
this.androidCookie = updateCookie(this.androidCookie, 'device_type', 'Android'); this.androidCookie = setCookie(this.androidCookie, 'basic_v', '0');
this.androidCookie = updateCookie(this.androidCookie, 'device_smzdm', 'android');
this.androidCookie = updateCookie(this.androidCookie, 'device_name', 'Android'); [
'smzdm_version',
'device_smzdm_version',
'device_type',
'device_name'
].forEach(name => {
this.androidCookie = removeCookie(this.androidCookie, name);
});
} }
getHeaders() { getHeaders() {
@@ -215,7 +277,7 @@ class SmzdmBot {
Accept: '*/*', Accept: '*/*',
'Accept-Language': 'zh-Hans-CN;q=1', 'Accept-Language': 'zh-Hans-CN;q=1',
'Accept-Encoding': 'gzip', 'Accept-Encoding': 'gzip',
'request_key': randomStr(18), 'request_key': requestKey(),
'User-Agent': userAgent, 'User-Agent': userAgent,
Cookie: this.androidCookie Cookie: this.androidCookie
}; };
@@ -242,6 +304,18 @@ class SmzdmBot {
getOneByRandom(listing) { getOneByRandom(listing) {
return listing[Math.floor(Math.random() * listing.length)]; return listing[Math.floor(Math.random() * listing.length)];
} }
// 打乱顺序
getShuffled(listing) {
const result = listing.slice();
for (let i = result.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[result[i], result[j]] = [result[j], result[i]];
}
return result;
}
} }
module.exports = { module.exports = {
@@ -250,5 +324,9 @@ module.exports = {
removeTags, removeTags,
parseJSON, parseJSON,
getEnvCookies, getEnvCookies,
wait getServerTime,
CREATE_CENTER_VIEW,
IS_INSTALL_ZHANGDAMA,
wait,
waitHuman
}; };

View File

@@ -1,4 +1,10 @@
const { SmzdmBot, requestApi, removeTags, wait } = require('./bot'); const {
SmzdmBot,
requestApi,
removeTags,
wait,
waitHuman
} = require('./bot');
// ------------------------------------ // ------------------------------------
@@ -13,8 +19,10 @@ class SmzdmTaskBot extends SmzdmBot {
async doTasks(tasks) { async doTasks(tasks) {
let notifyMsg = ''; let notifyMsg = '';
for (let i = 0; i < tasks.length; i++) { const list = this.getShuffled(tasks);
const task = tasks[i];
for (let i = 0; i < list.length; i++) {
const task = list[i];
// 待领取任务 // 待领取任务
if (task.task_status == '3') { if (task.task_status == '3') {
@@ -24,7 +32,7 @@ class SmzdmTaskBot extends SmzdmBot {
notifyMsg += `${isSuccess ? '🟢' : '❌'}领取[${task.task_name}]奖励${isSuccess ? '成功' : '失败!请查看日志'}\n`; notifyMsg += `${isSuccess ? '🟢' : '❌'}领取[${task.task_name}]奖励${isSuccess ? '成功' : '失败!请查看日志'}\n`;
await wait(5, 15); await waitHuman(5, 15);
} }
// 未完成任务 // 未完成任务
else if (task.task_status == '2') { else if (task.task_status == '2') {
@@ -34,7 +42,7 @@ class SmzdmTaskBot extends SmzdmBot {
notifyMsg += this.getTaskNotifyMessage(isSuccess, task); notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await wait(5, 15); await waitHuman(5, 15);
} }
// 分享任务 // 分享任务
else if (task.task_event_type == 'interactive.share') { else if (task.task_event_type == 'interactive.share') {
@@ -42,7 +50,7 @@ class SmzdmTaskBot extends SmzdmBot {
notifyMsg += this.getTaskNotifyMessage(isSuccess, task); notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await wait(5, 15); await waitHuman(5, 15);
} }
// 抽奖任务 // 抽奖任务
else if (task.task_event_type == 'guide.crowd') { else if (task.task_event_type == 'guide.crowd') {
@@ -52,7 +60,7 @@ class SmzdmTaskBot extends SmzdmBot {
notifyMsg += this.getTaskNotifyMessage(isSuccess, task); notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
} }
await wait(5, 15); await waitHuman(5, 15);
} }
// 关注用户任务 // 关注用户任务
else if (task.task_event_type == 'interactive.follow.user') { else if (task.task_event_type == 'interactive.follow.user') {
@@ -60,7 +68,7 @@ class SmzdmTaskBot extends SmzdmBot {
notifyMsg += this.getTaskNotifyMessage(isSuccess, task); notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await wait(5, 15); await waitHuman(5, 15);
} }
// 关注栏目任务 // 关注栏目任务
else if (task.task_event_type == 'interactive.follow.tag') { else if (task.task_event_type == 'interactive.follow.tag') {
@@ -68,7 +76,7 @@ class SmzdmTaskBot extends SmzdmBot {
notifyMsg += this.getTaskNotifyMessage(isSuccess, task); notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await wait(5, 15); await waitHuman(5, 15);
} }
// 关注品牌 // 关注品牌
else if (task.task_event_type == 'interactive.follow.brand') { else if (task.task_event_type == 'interactive.follow.brand') {
@@ -76,7 +84,7 @@ class SmzdmTaskBot extends SmzdmBot {
notifyMsg += this.getTaskNotifyMessage(isSuccess, task); notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await wait(5, 15); await waitHuman(5, 15);
} }
// 收藏任务 // 收藏任务
else if (task.task_event_type == 'interactive.favorite') { else if (task.task_event_type == 'interactive.favorite') {
@@ -84,7 +92,7 @@ class SmzdmTaskBot extends SmzdmBot {
notifyMsg += this.getTaskNotifyMessage(isSuccess, task); notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await wait(5, 15); await waitHuman(5, 15);
} }
// 点赞任务 // 点赞任务
else if (task.task_event_type == 'interactive.rating') { else if (task.task_event_type == 'interactive.rating') {
@@ -92,21 +100,67 @@ class SmzdmTaskBot extends SmzdmBot {
notifyMsg += this.getTaskNotifyMessage(isSuccess, task); notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await wait(5, 15); await waitHuman(5, 15);
} }
// 评论任务 // 评论任务
else if (task.task_event_type == 'interactive.comment') { else if (task.task_event_type == 'interactive.comment') {
if (process.env.SMZDM_COMMENT && String(process.env.SMZDM_COMMENT).length > 10) { const comment = this.getCommentContent();
const { isSuccess } = await this.doCommentTask(task);
if (comment) {
const { isSuccess } = await this.doCommentTask(task, comment);
notifyMsg += this.getTaskNotifyMessage(isSuccess, task); notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await wait(5, 15); await waitHuman(5, 15);
} }
else { else {
this.$env.log('🟡请设置 SMZDM_COMMENT 环境变量后才能做评论任务!'); this.$env.log('🟡请设置 SMZDM_COMMENT 环境变量后才能做评论任务!');
} }
} }
// 站外浏览任务
else if (task.task_event_type == 'interactive.view.zhanwai') {
const { isSuccess } = await this.doViewZhanwaiTask(task);
notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await waitHuman(5, 15);
}
// 打开第三方 App 任务
else if (task.task_event_type == 'interactive.open_third_party_app') {
const { isSuccess } = await this.doOpenThirdPartyTask(task);
notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await waitHuman(5, 15);
}
// 开启推送任务
else if (task.task_event_type == 'guide.open_app_push') {
const { isSuccess } = await this.doOpenAppPushTask(task);
notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await waitHuman(5, 15);
}
// 创建桌面签到快捷方式任务
else if (task.task_event_type == 'guide.create_app_checkin_shortcut') {
const { isSuccess } = await this.doCreateCheckinShortcutTask(task);
notifyMsg += this.getTaskNotifyMessage(isSuccess, task);
await waitHuman(5, 15);
}
// 爆料任务,静默跳过
else if (task.task_event_type == 'publish.baoliao_new') {
continue;
}
// 下载张大妈任务
else if (task.task_event_type == 'interactive.download_zhangdama') {
this.$env.log(`跳过[${task.task_name}]任务:APP 只跳转下载页,没有完成接口`);
}
// 未知类型
else {
this.$env.log(`跳过[${task.task_name}]任务:未知类型 ${task.task_event_type}`);
}
} }
} }
@@ -117,8 +171,23 @@ class SmzdmTaskBot extends SmzdmBot {
return `${isSuccess ? '🟢' : '❌'}完成[${task.task_name}]任务${isSuccess ? '成功' : '失败!请查看日志'}\n`; return `${isSuccess ? '🟢' : '❌'}完成[${task.task_name}]任务${isSuccess ? '成功' : '失败!请查看日志'}\n`;
} }
// APP 在列表场景下用 article_hash_id 作为文章标识
getArticleId(article) {
return article.article_hash_id || article.article_id;
}
// 随机取一条评论文案,多条时用换行或 | 分隔
getCommentContent() {
const words = String(process.env.SMZDM_COMMENT || '')
.split(/[\n|]/)
.map(word => word.trim())
.filter(word => word.length > 10);
return words.length > 0 ? this.getOneByRandom(words) : '';
}
// 执行评论任务 // 执行评论任务
async doCommentTask(task) { async doCommentTask(task, content) {
this.$env.log(`开始任务: ${task.task_name}`); this.$env.log(`开始任务: ${task.task_name}`);
const articles = await this.getArticleList(20); const articles = await this.getArticleList(20);
@@ -132,12 +201,15 @@ class SmzdmTaskBot extends SmzdmBot {
// 随机选一篇文章来评论 // 随机选一篇文章来评论
const article = articles[Math.floor(Math.random() * articles.length)]; const article = articles[Math.floor(Math.random() * articles.length)];
// 先打开文章
await this.getArticleDetail(article.article_id);
await wait(3, 10); await wait(3, 10);
const {isSuccess, data } = await this.submitComment({ const {isSuccess, data } = await this.submitComment({
articleId: article.article_id, articleId: article.article_id,
channelId: article.article_channel_id, channelId: article.article_channel_id,
content: process.env.SMZDM_COMMENT content
}); });
if (!isSuccess) { if (!isSuccess) {
@@ -160,7 +232,7 @@ class SmzdmTaskBot extends SmzdmBot {
} }
this.$env.log('领取奖励'); this.$env.log('领取奖励');
await wait(5, 15); await waitHuman(5, 15);
return await this.receiveReward(task.task_id); return await this.receiveReward(task.task_id);
} }
@@ -219,12 +291,14 @@ class SmzdmTaskBot extends SmzdmBot {
await wait(3, 10); await wait(3, 10);
const articleId = this.getArticleId(article);
if (article.article_price) { if (article.article_price) {
// 点值 // 点值
await this.rating({ await this.rating({
method: 'worth_cancel', method: 'worth_cancel',
type: 3, type: 3,
id: article.article_id, id: articleId,
channelId: article.article_channel_id channelId: article.article_channel_id
}); });
@@ -233,7 +307,7 @@ class SmzdmTaskBot extends SmzdmBot {
await this.rating({ await this.rating({
method: 'worth_create', method: 'worth_create',
type: 1, type: 1,
id: article.article_id, id: articleId,
channelId: article.article_channel_id channelId: article.article_channel_id
}); });
@@ -242,7 +316,7 @@ class SmzdmTaskBot extends SmzdmBot {
await this.rating({ await this.rating({
method: 'worth_cancel', method: 'worth_cancel',
type: 3, type: 3,
id: article.article_id, id: articleId,
channelId: article.article_channel_id channelId: article.article_channel_id
}); });
} }
@@ -250,7 +324,7 @@ class SmzdmTaskBot extends SmzdmBot {
// 点赞 // 点赞
await this.rating({ await this.rating({
method: 'like_cancel', method: 'like_cancel',
id: article.article_id, id: articleId,
channelId: article.article_channel_id channelId: article.article_channel_id
}); });
@@ -258,7 +332,7 @@ class SmzdmTaskBot extends SmzdmBot {
await this.rating({ await this.rating({
method: 'like_create', method: 'like_create',
id: article.article_id, id: articleId,
channelId: article.article_channel_id channelId: article.article_channel_id
}); });
@@ -266,7 +340,7 @@ class SmzdmTaskBot extends SmzdmBot {
await this.rating({ await this.rating({
method: 'like_cancel', method: 'like_cancel',
id: article.article_id, id: articleId,
channelId: article.article_channel_id channelId: article.article_channel_id
}); });
@@ -274,7 +348,7 @@ class SmzdmTaskBot extends SmzdmBot {
await this.rating({ await this.rating({
method: 'like_create', method: 'like_create',
id: article.article_id, id: articleId,
channelId: article.article_channel_id channelId: article.article_channel_id
}); });
@@ -282,13 +356,13 @@ class SmzdmTaskBot extends SmzdmBot {
await this.rating({ await this.rating({
method: 'like_cancel', method: 'like_cancel',
id: article.article_id, id: articleId,
channelId: article.article_channel_id channelId: article.article_channel_id
}); });
} }
this.$env.log('领取奖励'); this.$env.log('领取奖励');
await wait(5, 15); await waitHuman(5, 15);
return await this.receiveReward(task.task_id); return await this.receiveReward(task.task_id);
} }
@@ -312,12 +386,12 @@ class SmzdmTaskBot extends SmzdmBot {
const article = this.getOneByRandom(articles); const article = this.getOneByRandom(articles);
articleId = article.article_id; articleId = this.getArticleId(article);
channelId = article.article_channel_id; channelId = article.article_channel_id;
} }
else if (task.task_redirect_url.link_type === 'tag') { else if (task.task_redirect_url.link_type === 'tag') {
// 从 Tag 获取文章 // 从标签/话题获取文章
const articles = await this.getArticleListFromTag(task.task_redirect_url.link_val, task.task_redirect_url.link_title, 20); const articles = await this.getArticleListFromTag(task.task_redirect_url.link_val, 20);
if (articles.length < 1) { if (articles.length < 1) {
return { return {
@@ -327,7 +401,7 @@ class SmzdmTaskBot extends SmzdmBot {
const article = this.getOneByRandom(articles); const article = this.getOneByRandom(articles);
articleId = article.article_id; articleId = this.getArticleId(article);
channelId = article.article_channel_id; channelId = article.article_channel_id;
} }
else if (task.task_redirect_url.link_val == '0' || !task.task_redirect_url.link_val) { else if (task.task_redirect_url.link_val == '0' || !task.task_redirect_url.link_val) {
@@ -342,7 +416,7 @@ class SmzdmTaskBot extends SmzdmBot {
const article = this.getOneByRandom(articles); const article = this.getOneByRandom(articles);
articleId = article.article_id; articleId = this.getArticleId(article);
channelId = article.article_channel_id; channelId = article.article_channel_id;
} }
else { else {
@@ -362,6 +436,7 @@ class SmzdmTaskBot extends SmzdmBot {
await wait(3, 10); await wait(3, 10);
// 先取消
await this.favorite({ await this.favorite({
method: 'destroy', method: 'destroy',
id: articleId, id: articleId,
@@ -385,7 +460,7 @@ class SmzdmTaskBot extends SmzdmBot {
}); });
this.$env.log('领取奖励'); this.$env.log('领取奖励');
await wait(5, 15); await waitHuman(5, 15);
return await this.receiveReward(task.task_id); return await this.receiveReward(task.task_id);
} }
@@ -410,6 +485,7 @@ class SmzdmTaskBot extends SmzdmBot {
await this.follow({ await this.follow({
method: 'destroy', method: 'destroy',
type: 'user', type: 'user',
keywordId: user.keyword_id,
keyword: user.keyword keyword: user.keyword
}); });
@@ -419,6 +495,7 @@ class SmzdmTaskBot extends SmzdmBot {
await this.follow({ await this.follow({
method: 'create', method: 'create',
type: 'user', type: 'user',
keywordId: user.keyword_id,
keyword: user.keyword keyword: user.keyword
}); });
@@ -428,6 +505,7 @@ class SmzdmTaskBot extends SmzdmBot {
await this.follow({ await this.follow({
method: 'destroy', method: 'destroy',
type: 'user', type: 'user',
keywordId: user.keyword_id,
keyword: user.keyword keyword: user.keyword
}); });
} }
@@ -436,7 +514,7 @@ class SmzdmTaskBot extends SmzdmBot {
} }
this.$env.log('领取奖励'); this.$env.log('领取奖励');
await wait(5, 15); await waitHuman(5, 15);
return await this.receiveReward(task.task_id); return await this.receiveReward(task.task_id);
} }
@@ -456,7 +534,7 @@ class SmzdmTaskBot extends SmzdmBot {
}; };
} }
lanmuId = tag.lanmu_id; lanmuId = tag.keyword_id;
await wait(3, 10); await wait(3, 10);
} }
@@ -467,7 +545,7 @@ class SmzdmTaskBot extends SmzdmBot {
// 获取栏目信息 // 获取栏目信息
const tagDetail = await this.getTagDetail(lanmuId); const tagDetail = await this.getTagDetail(lanmuId);
if (!tagDetail.lanmu_id) { if (!tagDetail.keyword_id) {
this.$env.log('获取栏目信息失败!'); this.$env.log('获取栏目信息失败!');
return { return {
@@ -480,8 +558,8 @@ class SmzdmTaskBot extends SmzdmBot {
await this.follow({ await this.follow({
method: 'destroy', method: 'destroy',
type: 'tag', type: 'tag',
keywordId: tagDetail.lanmu_id, keywordId: tagDetail.keyword_id,
keyword: tagDetail.lanmu_info.lanmu_name keyword: tagDetail.keyword
}); });
await wait(3, 10); await wait(3, 10);
@@ -489,8 +567,8 @@ class SmzdmTaskBot extends SmzdmBot {
await this.follow({ await this.follow({
method: 'create', method: 'create',
type: 'tag', type: 'tag',
keywordId: tagDetail.lanmu_id, keywordId: tagDetail.keyword_id,
keyword: tagDetail.lanmu_info.lanmu_name keyword: tagDetail.keyword
}); });
await wait(3, 10); await wait(3, 10);
@@ -498,12 +576,12 @@ class SmzdmTaskBot extends SmzdmBot {
await this.follow({ await this.follow({
method: 'destroy', method: 'destroy',
type: 'tag', type: 'tag',
keywordId: tagDetail.lanmu_id, keywordId: tagDetail.keyword_id,
keyword: tagDetail.lanmu_info.lanmu_name keyword: tagDetail.keyword
}); });
this.$env.log('领取奖励'); this.$env.log('领取奖励');
await wait(5, 15); await waitHuman(5, 15);
return await this.receiveReward(task.task_id); return await this.receiveReward(task.task_id);
} }
@@ -546,7 +624,7 @@ class SmzdmTaskBot extends SmzdmBot {
}); });
this.$env.log('领取奖励'); this.$env.log('领取奖励');
await wait(5, 15); await waitHuman(5, 15);
return await this.receiveReward(task.task_id); return await this.receiveReward(task.task_id);
} }
@@ -578,7 +656,7 @@ class SmzdmTaskBot extends SmzdmBot {
} }
} }
await wait(5, 15); await waitHuman(5, 15);
const result = await this.joinCrowd(data); const result = await this.joinCrowd(data);
@@ -589,7 +667,7 @@ class SmzdmTaskBot extends SmzdmBot {
} }
this.$env.log('领取奖励'); this.$env.log('领取奖励');
await wait(5, 15); await waitHuman(5, 15);
return await this.receiveReward(task.task_id); return await this.receiveReward(task.task_id);
} }
@@ -633,7 +711,7 @@ class SmzdmTaskBot extends SmzdmBot {
await this.shareDailyReward(article.article_channel_id); await this.shareDailyReward(article.article_channel_id);
await this.shareCallback(article.article_id, article.article_channel_id); await this.shareCallback(article.article_id, article.article_channel_id);
await wait(5, 15); await waitHuman(5, 15);
} }
this.$env.log('领取奖励'); this.$env.log('领取奖励');
@@ -649,7 +727,18 @@ class SmzdmTaskBot extends SmzdmBot {
let articles = []; let articles = [];
let isRead = true; let isRead = true;
if (task.article_id == '0') { // APP 按任务给的浏览时长决定行为,为 0 时不打开文章页
const seconds = parseInt(task.view_seconds) || 0;
const readSeconds = seconds > 0 ? (parseInt(task.task_redirect_url.browse_task_second) || seconds) : 0;
if (seconds === 0 && task.article_id != '0') {
isRead = false;
articles = [{
article_id: task.article_id,
article_channel_id: task.channel_id
}];
}
else if (task.article_id == '0') {
isRead = true; isRead = true;
articles = await this.getArticleList(task.task_even_num - task.task_finished_num); articles = await this.getArticleList(task.task_even_num - task.task_finished_num);
@@ -681,8 +770,15 @@ class SmzdmTaskBot extends SmzdmBot {
} }
} }
this.$env.log('模拟阅读文章'); if (readSeconds > 0) {
await wait(20, 50); const dwell = readSeconds + Math.floor(Math.random() * 10);
this.$env.log(`模拟阅读文章 ${dwell} 秒`);
await wait(dwell, dwell + 5);
}
else {
await wait(3, 10);
}
const { isSuccess, response } = await requestApi('https://user-api.smzdm.com/task/event_view_article_sync', { const { isSuccess, response } = await requestApi('https://user-api.smzdm.com/task/event_view_article_sync', {
method: 'post', method: 'post',
@@ -701,7 +797,7 @@ class SmzdmTaskBot extends SmzdmBot {
this.$env.log(`完成阅读失败!${response}`); this.$env.log(`完成阅读失败!${response}`);
} }
await wait(5, 15); await waitHuman(5, 15);
} }
this.$env.log('领取奖励'); this.$env.log('领取奖励');
@@ -710,6 +806,58 @@ class SmzdmTaskBot extends SmzdmBot {
return await this.receiveReward(task.task_id); return await this.receiveReward(task.task_id);
} }
// 上报任务完成事件
async reportTaskEvent(url, task) {
const { isSuccess, response } = await requestApi(url, {
method: 'post',
headers: this.getHeaders(),
data: {
task_id: task.task_id
}
});
if (isSuccess) {
this.$env.log('任务事件上报成功。');
}
else {
this.$env.log(`任务事件上报失败!${response}`);
}
await waitHuman(5, 15);
this.$env.log('领取奖励');
return await this.receiveReward(task.task_id);
}
// 执行站外浏览任务
async doViewZhanwaiTask(task) {
this.$env.log(`开始任务: ${task.task_name}`);
return await this.reportTaskEvent('https://user-api.smzdm.com/task/event_view_zhanwai', task);
}
// 执行打开第三方 App 任务
async doOpenThirdPartyTask(task) {
this.$env.log(`开始任务: ${task.task_name}`);
return await this.reportTaskEvent('https://user-api.smzdm.com/task/event_view_third_party_app', task);
}
// 执行开启推送任务
async doOpenAppPushTask(task) {
this.$env.log(`开始任务: ${task.task_name}`);
return await this.reportTaskEvent('https://user-api.smzdm.com/task/open_app_push', task);
}
// 执行创建桌面签到快捷方式任务
async doCreateCheckinShortcutTask(task) {
this.$env.log(`开始任务: ${task.task_name}`);
return await this.reportTaskEvent('https://user-api.smzdm.com/task/create_app_checkin_shortcut', task);
}
// 关注/取关 // 关注/取关
async follow({keywordId, keyword, type, method}) { async follow({keywordId, keyword, type, method}) {
let touchstone = ''; let touchstone = '';
@@ -775,9 +923,9 @@ class SmzdmTaskBot extends SmzdmBot {
headers: this.getHeaders(), headers: this.getHeaders(),
data: { data: {
nav_id: 0, nav_id: 0,
page: 1,
type: 'user', type: 'user',
time_code: '' time_code: '',
limit: 20
} }
}); });
@@ -1008,17 +1156,13 @@ class SmzdmTaskBot extends SmzdmBot {
// 获取文章列表 // 获取文章列表
async getArticleList(num = 1) { async getArticleList(num = 1) {
const { isSuccess, data, response } = await requestApi('https://article-api.smzdm.com/ranking_list/articles', { const { isSuccess, data, response } = await requestApi('https://article-api.smzdm.com/ranking_list/article_and_biji', {
headers: this.getHeaders(), headers: this.getHeaders(),
data: { data: {
tab: '2',
order: '1',
offset: 0, offset: 0,
channel_id: 76, exclude_article_ids: ''
tab: 2,
order: 0,
limit: 20,
exclude_article_ids: '',
stream: 'a',
ab_code: 'b'
} }
}); });
@@ -1050,12 +1194,13 @@ class SmzdmTaskBot extends SmzdmBot {
// 获取栏目信息 // 获取栏目信息
async getTagDetail(id) { async getTagDetail(id) {
const { isSuccess, data, response } = await requestApi('https://common-api.smzdm.com/lanmu/config_data', { const { isSuccess, data, response } = await requestApi('https://app-api.smzdm.com/common/config_data', {
headers: this.getHeaders(), headers: this.getHeaders(),
data: { data: {
middle_page: '', id,
tab_selects: '', type: 'lanmu',
redirect_params: id calendar_time: '',
token: this.token
} }
}); });
@@ -1063,7 +1208,7 @@ class SmzdmTaskBot extends SmzdmBot {
return data.data; return data.data;
} }
else { else {
this.$env.log(`获取栏目信息失败!${response}`); this.$env.log(`获取栏目信息失败: ${response}`);
return {}; return {};
} }
@@ -1071,13 +1216,11 @@ class SmzdmTaskBot extends SmzdmBot {
// 获取栏目列表 // 获取栏目列表
async getTagByRandom() { async getTagByRandom() {
const { isSuccess, data, response } = await requestApi('https://dingyue-api.smzdm.com/tuijian/search_result', { const { isSuccess, data, response } = await requestApi('https://dingyue-api.smzdm.com/dy/user/dingyue/tuijian_search', {
method: 'post',
headers: this.getHeaders(), headers: this.getHeaders(),
data: { data: {
time_code: '', type: 'tag'
nav_id: '',
type: 'tag',
limit: 20
} }
}); });
@@ -1097,12 +1240,10 @@ class SmzdmTaskBot extends SmzdmBot {
headers: this.getHeaders(), headers: this.getHeaders(),
data: { data: {
comment_flow: '', comment_flow: '',
hashcode: '',
lastest_update_time: '', lastest_update_time: '',
uhome: 0, uhome: 0,
imgmode: 0, imgmode: 0,
article_channel_id: 0, article_channel_id: 0
h5hash: ''
} }
}); });
@@ -1139,24 +1280,30 @@ class SmzdmTaskBot extends SmzdmBot {
// 收藏 // 收藏
async favorite({id, channelId, method}) { async favorite({id, channelId, method}) {
const data = {
touchstone_event: this.getTouchstoneEvent({
event_value: {
aid: id,
cid: channelId,
is_detail: true
},
sourceMode: '我的_我的任务页',
sourcePage: `Android/长图文/P/${id}/`,
upperLevel_url: '个人中心/赚奖励/'
}),
token: this.token,
id,
channel_id: channelId
};
if (method === 'create') {
data.sub_channel_id = '2';
}
const { isSuccess, response } = await requestApi(`https://user-api.smzdm.com/favorites/${method}`, { const { isSuccess, response } = await requestApi(`https://user-api.smzdm.com/favorites/${method}`, {
method: 'post', method: 'post',
headers: this.getHeaders(), headers: this.getHeaders(),
data: { data
touchstone_event: this.getTouchstoneEvent({
event_value: {
aid: id,
cid: channelId,
is_detail: true
},
sourceMode: '我的_我的任务页',
sourcePage: `Android/长图文/P/${id}/`,
upperLevel_url: '个人中心/赚奖励/'
}),
token: this.token,
id,
channel_id: channelId
}
}); });
if (isSuccess) { if (isSuccess) {
@@ -1236,36 +1383,29 @@ class SmzdmTaskBot extends SmzdmBot {
if (isSuccess) { if (isSuccess) {
return data.data; return data.data;
} }
else {
this.$env.log(`获取品牌信息失败!${response}`);
return {}; this.$env.log(`获取品牌信息失败!${response}`);
}
return {};
} }
// 根据栏目信息获取文章列表 // 根据栏目信息获取文章列表
async getArticleListFromLanmu(id, num = 1) { async getArticleListFromLanmu(id, num = 1) {
const lanmuDetail = await this.getTagDetail(id); const lanmuDetail = await this.getTagDetail(id);
if (!lanmuDetail.lanmu_id) { if (!lanmuDetail.keyword_id) {
return []; return [];
} }
const { isSuccess, data, response } = await requestApi('https://common-api.smzdm.com/lanmu/list_data', { const tabParams = lanmuDetail.tab && lanmuDetail.tab[0] ? lanmuDetail.tab[0].params : '';
const { isSuccess, data, response } = await requestApi('https://app-api.smzdm.com/common/list_data', {
headers: this.getHeaders(), headers: this.getHeaders(),
data: { data: {
price_lt: '', params: lanmuDetail.params,
order: '', tab_params: tabParams,
category_ids: '',
price_gt: '',
referer_article: '',
tag_params: '',
mall_ids: '',
time_sort: '',
page: 1, page: 1,
params: id, limit: 20
limit: 20,
tab_params: lanmuDetail.tab[0].params
} }
}); });
@@ -1279,6 +1419,29 @@ class SmzdmTaskBot extends SmzdmBot {
} }
} }
// 根据标签/话题获取文章列表
async getArticleListFromTag(id, num = 1) {
const { isSuccess, data, response } = await requestApi('https://article-api.smzdm.com/shaiwu/shaiwu_juhe_new', {
headers: this.getHeaders(),
data: {
page: 1,
size: 20,
tag_id: id,
tab_id: '0',
middle_page: ''
}
});
if (isSuccess) {
return data.data.rows.slice(0, num);
}
else {
this.$env.log(`获取文章列表失败: ${response}`);
return [];
}
}
// 点赞 // 点赞
async rating({id, channelId, method, type}) { async rating({id, channelId, method, type}) {
const { isSuccess, response } = await requestApi(`https://user-api.smzdm.com/rating/${method}`, { const { isSuccess, response } = await requestApi(`https://user-api.smzdm.com/rating/${method}`, {
@@ -1332,7 +1495,6 @@ class SmzdmTaskBot extends SmzdmBot {
upperLevel_url: '好物社区/首页/全部/', upperLevel_url: '好物社区/首页/全部/',
sourceRoot: '社区' sourceRoot: '社区'
}), }),
is_like: 3,
reply_from: 3, reply_from: 3,
smiles: 0, smiles: 0,
atta: 0, atta: 0,
@@ -1381,58 +1543,6 @@ class SmzdmTaskBot extends SmzdmBot {
}; };
} }
// 获取 Dingyue 状态
async getDingyueStatus(name) {
const { isSuccess, data, response } = await requestApi('https://dingyue-api.smzdm.com/dingyue/follow_status', {
method: 'post',
headers: this.getHeaders(),
data: {
rules: JSON.stringify([{
type: 'tag',
keyword: name
}])
}
});
if (isSuccess) {
return data;
}
else {
this.$env.log(`获取订阅状态失败: ${response}`);
return {};
}
}
// 根据 Tag ID 获取文章列表
async getArticleListFromTag(id, name, num = 1) {
const status = this.getDingyueStatus(name);
const { isSuccess, data, response } = await requestApi('https://tag-api.smzdm.com/theme/detail_feed', {
headers: this.getHeaders(),
data: {
article_source: 1,
past_num: 0,
feed_sort: 2,
smzdm_id: status.smzdm_id,
tag_id: id,
name,
time_sort: 0,
page: 1,
article_tab: 0,
limit: 20
}
});
if (isSuccess) {
// 取前 num 个做任务
return data.data.rows.slice(0, num);
}
else {
this.$env.log(`获取文章列表失败: ${response}`);
return [];
}
}
// 通过 url 获取文章 channel_id // 通过 url 获取文章 channel_id
async getArticleChannelIdForTesting(url) { async getArticleChannelIdForTesting(url) {
const { isSuccess, response } = await requestApi(url, { const { isSuccess, response } = await requestApi(url, {

View File

@@ -6,7 +6,16 @@ cron: 10 8 * * *
*/ */
const Env = require('./env'); const Env = require('./env');
const { SmzdmBot, requestApi, removeTags, getEnvCookies, wait } = require('./bot'); const {
SmzdmBot,
requestApi,
removeTags,
getEnvCookies,
wait,
waitHuman,
CREATE_CENTER_VIEW,
IS_INSTALL_ZHANGDAMA
} = require('./bot');
const notify = require('./sendNotify'); const notify = require('./sendNotify');
const CryptoJS = require('crypto-js'); const CryptoJS = require('crypto-js');
@@ -49,7 +58,7 @@ class SmzdmCheckinBot extends SmzdmBot {
🏅碎银: ${data.data.pre_re_silver} 🏅碎银: ${data.data.pre_re_silver}
🏅补签卡: ${data.data.cards}`; 🏅补签卡: ${data.data.cards}`;
await wait(3, 10); await waitHuman(3, 10);
const vip = await this.getVipInfo(); const vip = await this.getVipInfo();
@@ -85,22 +94,24 @@ class SmzdmCheckinBot extends SmzdmBot {
}); });
if (isSuccess) { if (isSuccess) {
const msg1 = `${data.data.normal_reward.reward_add.title}: ${data.data.normal_reward.reward_add.content}`; const normal = data.data.normal_reward;
let msg2 = ''; // reward_add 为空说明今天没有奖励增加(已领过或没有),退回展示签到卡片文案
const msg1 = normal.reward_add.title
? `${normal.reward_add.title}: ${normal.reward_add.content}`
: removeTags(normal.gift.content);
if (data.data.normal_reward.gift.title) { const msg2 = normal.gift.title
msg2 = `${data.data.normal_reward.gift.title}: ${data.data.normal_reward.gift.content_str}`; ? `${normal.gift.title}: ${normal.gift.content_str}`
} : normal.gift.sub_content;
else {
msg2 = `${data.data.normal_reward.gift.sub_content}`;
}
$.log(`${msg1}\n${msg2}\n`); const msg = [msg1, msg2].filter(text => text).join('\n');
$.log(`${msg}\n`);
return { return {
isSuccess, isSuccess,
msg: `${msg1}\n${msg2}\n\n` msg: `${msg}\n\n`
}; };
} }
else { else {
@@ -129,7 +140,7 @@ class SmzdmCheckinBot extends SmzdmBot {
}; };
} }
await wait(5, 10); await waitHuman(5, 10);
const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/checkin/extra_reward', { const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/checkin/extra_reward', {
method: 'post', method: 'post',
@@ -159,13 +170,17 @@ class SmzdmCheckinBot extends SmzdmBot {
async isContinueCheckin() { async isContinueCheckin() {
const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/checkin/show_view_v2', { const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/checkin/show_view_v2', {
method: 'post', method: 'post',
headers: this.getHeaders() headers: this.getHeaders(),
data: {
is_install_zhangdama: IS_INSTALL_ZHANGDAMA
}
}); });
if (isSuccess) { if (isSuccess) {
const result = data.data.rows.find(item => item.cell_type == '18001'); // 连续签到的卡片,直接按有没有 checkin_continue 来找
const result = data.data.rows.find(item => item.cell_data && item.cell_data.checkin_continue);
return result.cell_data.checkin_continue.continue_checkin_reward_show; return !!(result && result.cell_data.checkin_continue.continue_checkin_reward_show);
} }
else { else {
$.log(`查询是否有额外奖励失败!${response}`); $.log(`查询是否有额外奖励失败!${response}`);
@@ -179,7 +194,8 @@ class SmzdmCheckinBot extends SmzdmBot {
method: 'post', method: 'post',
headers: this.getHeaders(), headers: this.getHeaders(),
data: { data: {
token: this.token token: this.token,
create_center_view: CREATE_CENTER_VIEW
} }
}); });

View File

@@ -6,7 +6,14 @@ cron: 20 8 * * *
*/ */
const Env = require('./env'); const Env = require('./env');
const { SmzdmBot, requestApi, parseJSON, getEnvCookies, wait } = require('./bot'); const {
SmzdmBot,
requestApi,
parseJSON,
getEnvCookies,
wait,
waitHuman
} = require('./bot');
const notify = require('./sendNotify'); const notify = require('./sendNotify');
// ------------------------------------ // ------------------------------------
@@ -34,7 +41,7 @@ class SmzdmLotteryBot extends SmzdmBot {
const vipId1 = await this.getActivityIdFromVip('https://m.smzdm.com/topic/bwrzf5/516lft'); const vipId1 = await this.getActivityIdFromVip('https://m.smzdm.com/topic/bwrzf5/516lft');
if (vipId1) { if (vipId1) {
await wait(3, 10); await waitHuman(3, 10);
notifyMsg += `转盘抽奖ID: ${vipId1}\n`; notifyMsg += `转盘抽奖ID: ${vipId1}\n`;
notifyMsg += await this.draw(vipId1); notifyMsg += await this.draw(vipId1);
@@ -42,13 +49,13 @@ class SmzdmLotteryBot extends SmzdmBot {
} }
$.log(); $.log();
await wait(5, 15); await waitHuman(5, 15);
$.log(); $.log();
const vipId2 = await this.getActivityIdFromVip('https://m.smzdm.com/topic/zhyzhuanpan/cjzp/'); const vipId2 = await this.getActivityIdFromVip('https://m.smzdm.com/topic/zhyzhuanpan/cjzp/');
if (vipId2) { if (vipId2) {
await wait(3, 10); await waitHuman(3, 10);
notifyMsg += `转盘抽奖ID: ${vipId2}\n`; notifyMsg += `转盘抽奖ID: ${vipId2}\n`;
notifyMsg += await this.draw(vipId2); notifyMsg += await this.draw(vipId2);

View File

@@ -6,7 +6,14 @@ cron: 20 14 * * *
*/ */
const Env = require('./env'); const Env = require('./env');
const { requestApi, removeTags, getEnvCookies, wait } = require('./bot'); const {
requestApi,
removeTags,
getEnvCookies,
wait,
waitHuman,
IS_INSTALL_ZHANGDAMA
} = require('./bot');
const notify = require('./sendNotify'); const notify = require('./sendNotify');
const { SmzdmTaskBot } = require('./library_task'); const { SmzdmTaskBot } = require('./library_task');
@@ -25,21 +32,21 @@ class SmzdmNormalTaskBot extends SmzdmTaskBot {
const { tasks } = await this.getTaskList(); const { tasks } = await this.getTaskList();
await wait(5, 10); await waitHuman(5, 10);
let notifyMsg = ''; let notifyMsg = '';
notifyMsg = await this.doTasks(tasks); notifyMsg = await this.doTasks(tasks);
$.log('查询是否有限时累计活动阶段奖励'); $.log('查询是否有限时累计活动阶段奖励');
await wait(5, 15); await waitHuman(5, 15);
// 领取活动奖励 // 领取活动奖励
const { detail } = await this.getTaskList(); const { detail } = await this.getTaskList();
if (detail.cell_data && detail.cell_data.activity_reward_status == '1') { if (detail.cell_data && detail.cell_data.activity_reward_status == '1') {
$.log('有奖励,领取奖励'); $.log('有奖励,领取奖励');
await wait(5, 15); await waitHuman(5, 15);
const { isSuccess } = await this.receiveActivity(detail.cell_data); const { isSuccess } = await this.receiveActivity(detail.cell_data);
@@ -56,7 +63,10 @@ class SmzdmNormalTaskBot extends SmzdmTaskBot {
async getTaskList() { async getTaskList() {
const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/task/list_v2', { const { isSuccess, data, response } = await requestApi('https://user-api.smzdm.com/task/list_v2', {
method: 'post', method: 'post',
headers: this.getHeaders() headers: this.getHeaders(),
data: {
is_install_zhangdama: IS_INSTALL_ZHANGDAMA
}
}); });
if (isSuccess) { if (isSuccess) {

View File

@@ -6,7 +6,7 @@ cron: 20 15 * * *
*/ */
const Env = require('./env'); const Env = require('./env');
const { requestApi, getEnvCookies, wait } = require('./bot'); const { requestApi, getEnvCookies, wait, waitHuman } = require('./bot');
const notify = require('./sendNotify'); const notify = require('./sendNotify');
const { SmzdmTaskBot } = require('./library_task'); const { SmzdmTaskBot } = require('./library_task');
@@ -21,13 +21,28 @@ class SmzdmTestingTaskBot extends SmzdmTaskBot {
// 主函数 // 主函数
async run() { async run() {
let notifyMsg = await this.doTestingTasks();
await waitHuman(5, 10);
notifyMsg += await this.getEnergyList();
await waitHuman(5, 10);
notifyMsg += await this.getWinCouponList();
return notifyMsg;
}
// 执行众测能量值任务
async doTestingTasks() {
const activityId = await this.getTestingActivityId(); const activityId = await this.getTestingActivityId();
if (!activityId) { if (!activityId) {
return ''; return this.wafBlocked ? '🟡众测任务未执行:接口被 WAF/风控拦截\n' : '';
} }
await wait(5, 10); await waitHuman(5, 10);
const activityInfo = await this.getTestingActivityInfo(activityId); const activityInfo = await this.getTestingActivityInfo(activityId);
@@ -35,87 +50,71 @@ class SmzdmTestingTaskBot extends SmzdmTaskBot {
return ''; return '';
} }
await wait(5, 10); await waitHuman(5, 10);
let notifyMsg = await this.doTasks(activityInfo.activity_task.default_list); return await this.doTasks(activityInfo.activity_task.default_list);
await wait(3, 5);
// 查询当前拥有的能量数量, 以及过期时间
notifyMsg += await this.getMyTestingInfo();
return notifyMsg || '无可执行任务';
} }
// 获取当前能量值任务的活动 ID // 众测接口被 WAF 拦时返回 403、429 或 HTML 验证码页,不是 JSON
async getTestingActivityId() { isWafBlocked(response) {
$.log('获取活动 ID'); return /WAF|验证码|<!DOCTYPE html>|<script|Response code 40[13]|Response code 429|ECONNRESET|ETIMEDOUT/i.test(String(response));
}
const { isSuccess, data, response } = await requestApi('https://zhiyou.m.smzdm.com/task/task/ajax_get_activity_id', { // 请求众测接口,被 WAF 拦时置标记并返回 false
async requestTestingApi(url, data) {
const { response } = await requestApi(url, {
method: 'get', method: 'get',
data: { data,
'from': 'zhongce'
},
headers: { headers: {
...this.getHeadersForWeb(), ...this.getHeadersForWeb(),
Origin: 'https://test.m.smzdm.com', Origin: 'https://test.m.smzdm.com',
Referer: 'https://test.m.smzdm.com/' Referer: 'https://test.m.smzdm.com/'
} },
parseJSON: false
}); });
if (isSuccess) { if (this.isWafBlocked(response)) {
return data.data.activity_id; this.wafBlocked = true;
}
else { $.log('🔴众测任务接口被 WAF 拦截,本次跳过众测任务');
$.log(`获取活动 ID 失败!${response}`);
return false; return false;
} }
try {
const json = JSON.parse(response);
if (json.error_code == '0') {
return json.data;
}
$.log(`众测接口返回错误:${json.error_msg}`);
}
catch (e) {
$.log(`众测接口返回异常:${String(response).slice(0, 150)}`);
}
return false;
}
// 获取众测能量值任务的活动 ID
async getTestingActivityId() {
$.log('获取众测活动 ID');
const data = await this.requestTestingApi('https://zhiyou.m.smzdm.com/task/task/ajax_get_activity_id', {
'from': 'zhongce'
});
return data ? data.activity_id : false;
} }
// 获取活动下的所有任务 // 获取活动下的所有任务
async getTestingActivityInfo(id) { async getTestingActivityInfo(id) {
$.log('获取活动信息'); $.log('获取众测活动信息');
const { isSuccess, data, response } = await requestApi('https://zhiyou.m.smzdm.com/task/task/ajax_get_activity_info', { return await this.requestTestingApi('https://zhiyou.m.smzdm.com/task/task/ajax_get_activity_info', {
method: 'get', 'activity_id': id
data: {
'activity_id': id
},
headers: this.getHeadersForWeb()
}); });
if (isSuccess) {
return data.data;
}
else {
$.log(`获取活动信息失败!${response}`);
return false;
}
}
// 众测中心-必中券信息查询
async getMyTestingInfo() {
$.log('获取必中券信息');
const { isSuccess, data, response } = await requestApi('https://test.m.smzdm.com/win_coupon/user_data', {
method: 'get',
headers: this.getHeadersForWeb()
});
if (isSuccess) {
const msg = `当前拥有必中券: ${data.data.my_energy.my_energy_total}\n必中券过期时间: ${data.data.my_energy.energy_expired_time}`;
$.log(msg);
return `\n${msg}\n`;
}
else {
$.log(`获取个人必中券信息失败!${response}`);
return '';
}
} }
// 领取奖励 // 领取奖励
@@ -125,10 +124,11 @@ class SmzdmTestingTaskBot extends SmzdmTaskBot {
data: { data: {
'task_id': taskId 'task_id': taskId
}, },
headers: this.getHeadersForWeb() headers: this.getHeadersForWeb(),
parseJSON: false
}); });
if (isSuccess) { if (!this.isWafBlocked(response) && isSuccess) {
$.log('领取成功!'); $.log('领取成功!');
return { return {
@@ -136,14 +136,77 @@ class SmzdmTestingTaskBot extends SmzdmTaskBot {
msg: '' msg: ''
}; };
} }
else {
$.log(`领取任务奖励失败!${response}`);
return { $.log(`领取任务奖励失败!${String(response).slice(0, 150)}`);
isSuccess,
msg: '领取任务奖励失败!' return {
}; isSuccess: false,
msg: '领取任务奖励失败!'
};
}
// 能量值数量、过期时间与明细
async getEnergyList() {
$.log('查询能量值');
const { isSuccess, data, response } = await requestApi('https://test-api.smzdm.com/win_coupon/energy_list', {
method: 'get',
headers: this.getHeaders(),
data: {
'page': 1
}
});
if (!isSuccess) {
$.log(`查询能量值失败!${response}`);
return '';
} }
const myEnergy = data.data.my_energy || {};
const list = data.data.list || [];
let msg = `🏅能量值: ${myEnergy.my_energy_total}\n🏅能量值过期时间: ${myEnergy.energy_expired_time}\n`;
if (list.length > 0) {
msg += `🏅能量值明细:\n${list.map(item => ` ${item.article_title}`).join('\n')}\n`;
}
$.log(msg);
return `${msg}\n`;
}
// 必中券列表
async getWinCouponList() {
$.log('查询必中券列表');
const { isSuccess, data, response } = await requestApi('https://test-api.smzdm.com/win_coupon/win_coupon_list', {
method: 'get',
headers: this.getHeaders(),
data: {
'page': 1,
'type': '0'
}
});
if (!isSuccess) {
$.log(`查询必中券列表失败!${response}`);
return '';
}
const list = data.data.list || [];
if (list.length < 1) {
return '🏅暂无必中券\n';
}
const msg = `🏅必中券 ${list.length} 项:\n${list.map(item => ` ${item.article_title}`).join('\n')}\n`;
$.log(msg);
return msg;
} }
} }