fix(qdreader): align tasks with upstream flow

This commit is contained in:
2026-05-22 18:09:14 +08:00
parent 25d3f2c73b
commit eaae089589
3 changed files with 131 additions and 109 deletions
+34 -32
View File
@@ -4,12 +4,12 @@
//[author: Hermes]
//[service: BOSS]
//[class: 工具类]
//[version: 2.10.9]
//[version: 2.11.0]
//[platform: web,qq,wx,tg,tb,fs,we]
//[public: false]
//[price: 0]
//[disable: false]
//[description: 启点读书(QDReader) Autman 签到插件:保存 QX 抓到的 H5 Cookie,支持手动“启点签到”;定时使用 `1 7 * * *` 每日 07:01 签到;每次签到运行结束后立即归档并清空最近运行日志,不再依赖单独归档定时;带独立 bucket、多用户隔离、请求重试、签名响应解析、结果摘要和安全脱敏。]
//[description: 启点读书(QDReader) Autman 签到插件:保存 QX 抓到的 H5 Cookie,支持手动“启点签到”;定时使用 `1 7 * * *` 每日 07:01 签到;完全体可选任务按上游原项目解密流程执行;每次签到运行结束后立即归档并清空最近运行日志,不再依赖单独归档定时;带独立 bucket、多用户隔离、请求重试、签名响应解析、结果摘要和安全脱敏。]
//[rule: ^启点(账号|查询|ck|CK|cookie|Cookie|签到|读书|归档|日志归档)(.*)$]
//[rule: ^qdreader(.*)$]
//[admin: true]
@@ -276,7 +276,7 @@ function contentText() {
}
function usage() {
return [
"启点读书签到插件 v2.10.9",
"启点读书签到插件 v2.11.0",
"【一级菜单】",
"账号管理:启点账号",
"执行查询:启点查询",
@@ -640,63 +640,65 @@ function doReceiveGifts(cookie) {
}
function doAdvTask(cookie) {
var main = qdGet("/argus/api/v2/video/adv/mainPage", {}, cookie)
if (!taskResultOk(main)) return { name: "激励任务", ok: false, msg: resultMsg(main) || "获取任务失败", path: "/argus/api/v2/video/adv/mainPage" }
var tasks = firstArray(nested(main, ["Data", "VideoRewardTab", "TaskList"]), nested(main, ["data", "VideoRewardTab", "TaskList"]), nested(main, ["Data", "TaskList"]), nested(main, ["data", "TaskList"]))
if (!tasks.length) return { name: "激励任务", ok: false, msg: "未找到任务列表", path: "/argus/api/v2/video/adv/mainPage" }
if (taskFinished(tasks[tasks.length - 1])) return { name: "激励任务", ok: true, msg: "已完成", path: "/argus/api/v2/video/adv/mainPage" }
if (!taskResultOk(main)) return { name: "激励任务", ok: false, msg: resultMsg(main) || "获取任务列表失败", path: "/argus/api/v2/video/adv/mainPage" }
var tasks = firstArray(nested(main, ["Data", "DailyBenefitModule", "TaskList"]), nested(main, ["data", "DailyBenefitModule", "TaskList"]))
if (!tasks.length) return { name: "激励任务", ok: false, msg: "任务列表为空", path: "/argus/api/v2/video/adv/mainPage" }
if (taskFinished(tasks[tasks.length - 1])) return { name: "激励任务", ok: true, msg: "任务已完成", path: "/argus/api/v2/video/adv/mainPage" }
var submittedCount = 0
for (var i = 0; i < tasks.length; i++) {
var t = tasks[i] || {}
if (taskFinished(t)) continue
var tid = taskIdOf(t)
if (!tid) continue
var fr = finishVideoTask(t, cookie, 1)
var fr = finishVideoTask(tid, cookie, 1)
submittedCount += fr.ok
if (fr.ok < fr.total) return { name: "激励任务", ok: false, msg: resultMsg(fr.last) || ("第 " + (i + 1) + " 个视频任务失败"), path: "/argus/api/v1/video/adv/finishWatch" }
if (fr.ok < fr.total) return { name: "激励任务", ok: false, msg: resultMsg(fr.last) || ("第 " + (i + 1) + " 个任务失败"), path: "/argus/api/v1/video/adv/finishWatch" }
}
var verify = qdGet("/argus/api/v2/video/adv/mainPage", {}, cookie)
var after = firstArray(nested(verify, ["Data", "VideoRewardTab", "TaskList"]), nested(verify, ["data", "VideoRewardTab", "TaskList"]), nested(verify, ["Data", "TaskList"]), nested(verify, ["data", "TaskList"]))
var finished = !!(after && after.length && taskFinished(after[after.length - 1]))
return { name: "激励任务", ok: finished, msg: finished ? "已完成" : (submittedCount ? "任务未完成" : "未找到可提交任务"), path: "/argus/api/v2/video/adv/mainPage" }
var after = firstArray(nested(verify, ["Data", "DailyBenefitModule", "TaskList"]), nested(verify, ["data", "DailyBenefitModule", "TaskList"]))
var finished = !!(after && after.length && after.every(function (t) { return taskFinished(t) }))
return { name: "激励任务", ok: finished, msg: finished ? "任务已完成" : (submittedCount ? "部分任务未完成" : "未找到可提交任务"), path: "/argus/api/v2/video/adv/mainPage" }
}
function taskReceived(task) {
return Number(field(task, ["IsReceived", "Received", "Status", "status"], 0)) === 1
}
function doDailyTask(cookie) {
var list = qdGet("/argus/api/v3/checkin/packagelist", {}, cookie)
if (!taskResultOk(list)) return { name: "每日任务", ok: false, msg: resultMsg(list) || "获取任务列表失败", path: "/argus/api/v3/checkin/packagelist" }
var data = list.Data || list.data || {}
var pre = field(data, ["Task", "SurpriseTask", "CurrentTask"], null)
var main = qdGet("/argus/api/v2/video/adv/mainPage", {}, cookie)
if (!taskResultOk(main)) return { name: "每日任务", ok: false, msg: resultMsg(main) || "获取任务列表失败", path: "/argus/api/v2/video/adv/mainPage" }
var data = main.Data || main.data || {}
var done = 0
var pre = data.SurpriseBenefit
if (pre && !taskFinished(pre) && taskIdOf(pre)) {
var pr = finishVideoTask(pre, cookie, 1)
var pr = finishVideoTask(taskIdOf(pre), cookie, 1)
done += pr.ok
if (pr.ok < pr.total) return { name: "每日任务", ok: false, msg: resultMsg(pr.last) || "惊喜福利任务失败", path: "/argus/api/v1/video/adv/finishWatch" }
}
var tasks = firstArray(nested(list, ["Data", "PackageList", "TaskList"]), nested(list, ["data", "PackageList", "TaskList"]), nested(list, ["Data", "TaskList"]), nested(list, ["data", "TaskList"]), nested(list, ["Data", "PackageList"]), nested(list, ["data", "PackageList"]))
var tasks = firstArray(nested(main, ["Data", "VideoRewardTab", "TaskList"]), nested(main, ["data", "VideoRewardTab", "TaskList"]))
if (!tasks.length) return { name: "每日任务", ok: false, msg: "任务列表为空", path: "/argus/api/v2/video/adv/mainPage" }
var oneAd = null
var target = null
for (var i = 0; i < tasks.length; i++) {
var n = taskTitle(tasks[i])
if (!oneAd && /完成\s*1\s*个广告任务|1个广告|one.?ad/i.test(n)) oneAd = tasks[i]
if (!target && n === "每日任务") target = tasks[i]
var title = taskTitle(tasks[i])
if (!oneAd && title === "完成1个广告任务得奖励") oneAd = tasks[i]
if (!target && title === "完成3个广告任务得奖励") target = tasks[i]
}
if (!target) for (var k = 0; k < tasks.length; k++) { var n2 = taskTitle(tasks[k]); if (/每日|daily/i.test(n2)) { target = tasks[k]; break } }
if (oneAd && oneAd !== target && !taskFinished(oneAd) && taskIdOf(oneAd)) {
var ar = finishVideoTask(oneAd, cookie, 1)
if (oneAd && !taskReceived(oneAd) && taskIdOf(oneAd)) {
var ar = finishVideoTask(taskIdOf(oneAd), cookie, 1)
done += ar.ok
if (ar.ok < ar.total) return { name: "每日任务", ok: false, msg: resultMsg(ar.last) || "完成1个广告任务失败", path: "/argus/api/v1/video/adv/finishWatch" }
}
if (!target) return { name: "每日任务", ok: true, msg: done ? ("完成 " + done + " 次") : "无每日任务", path: "/argus/api/v3/checkin/packagelist" }
if (taskFinished(target)) return { name: "每日任务", ok: true, msg: "已完成", path: "/argus/api/v3/checkin/packagelist" }
if (!target) return { name: "每日任务", ok: false, msg: "未找到每日任务任务", path: "/argus/api/v2/video/adv/mainPage" }
if (taskReceived(target)) return { name: "每日任务", ok: true, msg: "任务已完成", path: "/argus/api/v2/video/adv/mainPage" }
var tid = taskIdOf(target)
if (!tid) return { name: "每日任务", ok: true, msg: done ? ("完成 " + done + " 次") : "无每日任务", path: "/argus/api/v3/checkin/packagelist" }
var tr = finishVideoTask(target, cookie, taskRunCount(target, 3))
if (!tid) return { name: "每日任务", ok: false, msg: "每日任务缺少 TaskId", path: "/argus/api/v2/video/adv/mainPage" }
var tr = finishVideoTask(tid, cookie, 3)
done += tr.ok
if (tr.ok < tr.total) return { name: "每日任务", ok: false, msg: resultMsg(tr.last) || "每日任务广告失败", path: "/argus/api/v1/video/adv/finishWatch" }
var verify = qdGet("/argus/api/v2/video/adv/mainPage", {}, cookie)
var after = firstArray(nested(verify, ["Data", "VideoRewardTab", "TaskList"]), nested(verify, ["data", "VideoRewardTab", "TaskList"]), nested(verify, ["Data", "TaskList"]), nested(verify, ["data", "TaskList"]))
var after = firstArray(nested(verify, ["Data", "VideoRewardTab", "TaskList"]), nested(verify, ["data", "VideoRewardTab", "TaskList"]))
var finished = false
for (var v = 0; v < after.length; v++) if (taskIdKey(taskIdOf(after[v])) === taskIdKey(tid) && taskFinished(after[v])) { finished = true; break }
if (!finished) for (var x = 0; x < after.length; x++) if (taskTitle(after[x]) === "每日任务" && taskFinished(after[x])) { finished = true; break }
return { name: "每日任务", ok: finished || done > 0, msg: finished ? "已完成" : (done > 0 ? ("完成 " + done + " 次") : "任务未完成"), path: "/argus/api/v3/checkin/packagelist" }
for (var v = 0; v < after.length; v++) if (taskTitle(after[v]) === "完成3个广告任务得奖励" && taskReceived(after[v])) { finished = true; break }
return { name: "每日任务", ok: finished, msg: finished ? "任务已完成" : "任务未完成", path: "/argus/api/v2/video/adv/mainPage" }
}
function doLotteryTask(cookie) {
var detail = qdGet("/argus/api/v2/checkin/detail", {}, cookie)
+34 -32
View File
@@ -4,12 +4,12 @@
//[author: Hermes]
//[service: BOSS]
//[class: 工具类]
//[version: 2.10.9]
//[version: 2.11.0]
//[platform: web,qq,wx,tg,tb,fs,we]
//[public: false]
//[price: 0]
//[disable: false]
//[description: 启点读书(QDReader) Autman 签到插件:保存 QX 抓到的 H5 Cookie,支持手动“启点签到”;定时使用 `1 7 * * *` 每日 07:01 签到;每次签到运行结束后立即归档并清空最近运行日志,不再依赖单独归档定时;带独立 bucket、多用户隔离、请求重试、签名响应解析、结果摘要和安全脱敏。]
//[description: 启点读书(QDReader) Autman 签到插件:保存 QX 抓到的 H5 Cookie,支持手动“启点签到”;定时使用 `1 7 * * *` 每日 07:01 签到;完全体可选任务按上游原项目解密流程执行;每次签到运行结束后立即归档并清空最近运行日志,不再依赖单独归档定时;带独立 bucket、多用户隔离、请求重试、签名响应解析、结果摘要和安全脱敏。]
//[rule: ^启点(账号|查询|ck|CK|cookie|Cookie|签到|读书|归档|日志归档)(.*)$]
//[rule: ^qdreader(.*)$]
//[admin: true]
@@ -276,7 +276,7 @@ function contentText() {
}
function usage() {
return [
"启点读书签到插件 v2.10.9",
"启点读书签到插件 v2.11.0",
"【一级菜单】",
"账号管理:启点账号",
"执行查询:启点查询",
@@ -640,63 +640,65 @@ function doReceiveGifts(cookie) {
}
function doAdvTask(cookie) {
var main = qdGet("/argus/api/v2/video/adv/mainPage", {}, cookie)
if (!taskResultOk(main)) return { name: "激励任务", ok: false, msg: resultMsg(main) || "获取任务失败", path: "/argus/api/v2/video/adv/mainPage" }
var tasks = firstArray(nested(main, ["Data", "VideoRewardTab", "TaskList"]), nested(main, ["data", "VideoRewardTab", "TaskList"]), nested(main, ["Data", "TaskList"]), nested(main, ["data", "TaskList"]))
if (!tasks.length) return { name: "激励任务", ok: false, msg: "未找到任务列表", path: "/argus/api/v2/video/adv/mainPage" }
if (taskFinished(tasks[tasks.length - 1])) return { name: "激励任务", ok: true, msg: "已完成", path: "/argus/api/v2/video/adv/mainPage" }
if (!taskResultOk(main)) return { name: "激励任务", ok: false, msg: resultMsg(main) || "获取任务列表失败", path: "/argus/api/v2/video/adv/mainPage" }
var tasks = firstArray(nested(main, ["Data", "DailyBenefitModule", "TaskList"]), nested(main, ["data", "DailyBenefitModule", "TaskList"]))
if (!tasks.length) return { name: "激励任务", ok: false, msg: "任务列表为空", path: "/argus/api/v2/video/adv/mainPage" }
if (taskFinished(tasks[tasks.length - 1])) return { name: "激励任务", ok: true, msg: "任务已完成", path: "/argus/api/v2/video/adv/mainPage" }
var submittedCount = 0
for (var i = 0; i < tasks.length; i++) {
var t = tasks[i] || {}
if (taskFinished(t)) continue
var tid = taskIdOf(t)
if (!tid) continue
var fr = finishVideoTask(t, cookie, 1)
var fr = finishVideoTask(tid, cookie, 1)
submittedCount += fr.ok
if (fr.ok < fr.total) return { name: "激励任务", ok: false, msg: resultMsg(fr.last) || ("第 " + (i + 1) + " 个视频任务失败"), path: "/argus/api/v1/video/adv/finishWatch" }
if (fr.ok < fr.total) return { name: "激励任务", ok: false, msg: resultMsg(fr.last) || ("第 " + (i + 1) + " 个任务失败"), path: "/argus/api/v1/video/adv/finishWatch" }
}
var verify = qdGet("/argus/api/v2/video/adv/mainPage", {}, cookie)
var after = firstArray(nested(verify, ["Data", "VideoRewardTab", "TaskList"]), nested(verify, ["data", "VideoRewardTab", "TaskList"]), nested(verify, ["Data", "TaskList"]), nested(verify, ["data", "TaskList"]))
var finished = !!(after && after.length && taskFinished(after[after.length - 1]))
return { name: "激励任务", ok: finished, msg: finished ? "已完成" : (submittedCount ? "任务未完成" : "未找到可提交任务"), path: "/argus/api/v2/video/adv/mainPage" }
var after = firstArray(nested(verify, ["Data", "DailyBenefitModule", "TaskList"]), nested(verify, ["data", "DailyBenefitModule", "TaskList"]))
var finished = !!(after && after.length && after.every(function (t) { return taskFinished(t) }))
return { name: "激励任务", ok: finished, msg: finished ? "任务已完成" : (submittedCount ? "部分任务未完成" : "未找到可提交任务"), path: "/argus/api/v2/video/adv/mainPage" }
}
function taskReceived(task) {
return Number(field(task, ["IsReceived", "Received", "Status", "status"], 0)) === 1
}
function doDailyTask(cookie) {
var list = qdGet("/argus/api/v3/checkin/packagelist", {}, cookie)
if (!taskResultOk(list)) return { name: "每日任务", ok: false, msg: resultMsg(list) || "获取任务列表失败", path: "/argus/api/v3/checkin/packagelist" }
var data = list.Data || list.data || {}
var pre = field(data, ["Task", "SurpriseTask", "CurrentTask"], null)
var main = qdGet("/argus/api/v2/video/adv/mainPage", {}, cookie)
if (!taskResultOk(main)) return { name: "每日任务", ok: false, msg: resultMsg(main) || "获取任务列表失败", path: "/argus/api/v2/video/adv/mainPage" }
var data = main.Data || main.data || {}
var done = 0
var pre = data.SurpriseBenefit
if (pre && !taskFinished(pre) && taskIdOf(pre)) {
var pr = finishVideoTask(pre, cookie, 1)
var pr = finishVideoTask(taskIdOf(pre), cookie, 1)
done += pr.ok
if (pr.ok < pr.total) return { name: "每日任务", ok: false, msg: resultMsg(pr.last) || "惊喜福利任务失败", path: "/argus/api/v1/video/adv/finishWatch" }
}
var tasks = firstArray(nested(list, ["Data", "PackageList", "TaskList"]), nested(list, ["data", "PackageList", "TaskList"]), nested(list, ["Data", "TaskList"]), nested(list, ["data", "TaskList"]), nested(list, ["Data", "PackageList"]), nested(list, ["data", "PackageList"]))
var tasks = firstArray(nested(main, ["Data", "VideoRewardTab", "TaskList"]), nested(main, ["data", "VideoRewardTab", "TaskList"]))
if (!tasks.length) return { name: "每日任务", ok: false, msg: "任务列表为空", path: "/argus/api/v2/video/adv/mainPage" }
var oneAd = null
var target = null
for (var i = 0; i < tasks.length; i++) {
var n = taskTitle(tasks[i])
if (!oneAd && /完成\s*1\s*个广告任务|1个广告|one.?ad/i.test(n)) oneAd = tasks[i]
if (!target && n === "每日任务") target = tasks[i]
var title = taskTitle(tasks[i])
if (!oneAd && title === "完成1个广告任务得奖励") oneAd = tasks[i]
if (!target && title === "完成3个广告任务得奖励") target = tasks[i]
}
if (!target) for (var k = 0; k < tasks.length; k++) { var n2 = taskTitle(tasks[k]); if (/每日|daily/i.test(n2)) { target = tasks[k]; break } }
if (oneAd && oneAd !== target && !taskFinished(oneAd) && taskIdOf(oneAd)) {
var ar = finishVideoTask(oneAd, cookie, 1)
if (oneAd && !taskReceived(oneAd) && taskIdOf(oneAd)) {
var ar = finishVideoTask(taskIdOf(oneAd), cookie, 1)
done += ar.ok
if (ar.ok < ar.total) return { name: "每日任务", ok: false, msg: resultMsg(ar.last) || "完成1个广告任务失败", path: "/argus/api/v1/video/adv/finishWatch" }
}
if (!target) return { name: "每日任务", ok: true, msg: done ? ("完成 " + done + " 次") : "无每日任务", path: "/argus/api/v3/checkin/packagelist" }
if (taskFinished(target)) return { name: "每日任务", ok: true, msg: "已完成", path: "/argus/api/v3/checkin/packagelist" }
if (!target) return { name: "每日任务", ok: false, msg: "未找到每日任务任务", path: "/argus/api/v2/video/adv/mainPage" }
if (taskReceived(target)) return { name: "每日任务", ok: true, msg: "任务已完成", path: "/argus/api/v2/video/adv/mainPage" }
var tid = taskIdOf(target)
if (!tid) return { name: "每日任务", ok: true, msg: done ? ("完成 " + done + " 次") : "无每日任务", path: "/argus/api/v3/checkin/packagelist" }
var tr = finishVideoTask(target, cookie, taskRunCount(target, 3))
if (!tid) return { name: "每日任务", ok: false, msg: "每日任务缺少 TaskId", path: "/argus/api/v2/video/adv/mainPage" }
var tr = finishVideoTask(tid, cookie, 3)
done += tr.ok
if (tr.ok < tr.total) return { name: "每日任务", ok: false, msg: resultMsg(tr.last) || "每日任务广告失败", path: "/argus/api/v1/video/adv/finishWatch" }
var verify = qdGet("/argus/api/v2/video/adv/mainPage", {}, cookie)
var after = firstArray(nested(verify, ["Data", "VideoRewardTab", "TaskList"]), nested(verify, ["data", "VideoRewardTab", "TaskList"]), nested(verify, ["Data", "TaskList"]), nested(verify, ["data", "TaskList"]))
var after = firstArray(nested(verify, ["Data", "VideoRewardTab", "TaskList"]), nested(verify, ["data", "VideoRewardTab", "TaskList"]))
var finished = false
for (var v = 0; v < after.length; v++) if (taskIdKey(taskIdOf(after[v])) === taskIdKey(tid) && taskFinished(after[v])) { finished = true; break }
if (!finished) for (var x = 0; x < after.length; x++) if (taskTitle(after[x]) === "每日任务" && taskFinished(after[x])) { finished = true; break }
return { name: "每日任务", ok: finished || done > 0, msg: finished ? "已完成" : (done > 0 ? ("完成 " + done + " 次") : "任务未完成"), path: "/argus/api/v3/checkin/packagelist" }
for (var v = 0; v < after.length; v++) if (taskTitle(after[v]) === "完成3个广告任务得奖励" && taskReceived(after[v])) { finished = true; break }
return { name: "每日任务", ok: finished, msg: finished ? "任务已完成" : "任务未完成", path: "/argus/api/v2/video/adv/mainPage" }
}
function doLotteryTask(cookie) {
var detail = qdGet("/argus/api/v2/checkin/detail", {}, cookie)
+63 -45
View File
@@ -88,7 +88,7 @@ test('README documents QDReader task schedule windows and required endpoints', (
'receivegifts',
'mainPage',
'finishWatch',
'packagelist',
'mainPage',
'lottery',
'checkinexchangepage',
'exchangegoods',
@@ -397,7 +397,6 @@ test('optional QDReader full tasks use upstream executable endpoints and sign ab
qdreader_user_bind_json: JSON.stringify({ '12345': 'user-a' }),
qdreader_task_pref_json: JSON.stringify({ '12345': { adv: true, extraAdv: true, lottery: true, weeklyExchange: true, chapterCard: true, messageBox: true } }),
};
const originalDate = Date;
const sunday = fixedDateClass('2026-05-24T20:01:00.000+08:00');
const r = runPlugin({
content: '启点签到',
@@ -410,13 +409,25 @@ test('optional QDReader full tasks use upstream executable endpoints and sign ab
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, msg: '奖励完成' } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: 'adv-1', IsFinished: 0 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: 'adv-1', Title: '激励碎片', IsFinished: 0 }] } } } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, msg: '视频完成' } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: 'adv-1', IsFinished: 1 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: 'adv-1', Title: '激励碎片', IsFinished: 1 }] } } } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, Data: { TaskList: [{ TaskId: 'daily-1', TaskName: '每日任务', IsFinished: 1, NeedWatchCount: 1 }] } } },
{ statusCode: 200, body: { code: 0, Data: { SurpriseBenefit: { TaskId: 'surprise-1', IsFinished: 0 }, VideoRewardTab: { TaskList: [{ TaskId: 'one-ad', Title: '完成1个广告任务得奖励', IsReceived: 0 }, { TaskId: 'daily-3', Title: '完成3个广告任务得奖励', IsReceived: 0 }] } } } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, msg: '惊喜福利完成' } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, msg: '一个广告完成' } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, msg: '每日广告1完成' } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, msg: '每日广告2完成' } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, msg: '每日广告3完成' } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: 'daily-3', Title: '完成3个广告任务得奖励', IsReceived: 1 }] } } } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
{ statusCode: 200, body: { code: 0, Data: { HasVideoUrge: 0, LotteryCount: 1 } } },
(req) => String(req.url).includes('/sign') ? { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } } : { statusCode: 200, body: { code: 0, msg: 'ok' } },
@@ -435,7 +446,7 @@ test('optional QDReader full tasks use upstream executable endpoints and sign ab
assert.ok(urls.some(u => /argus\/api\/v3\/checkin\/receivegifts$/.test(u)));
assert.ok(urls.some(u => /argus\/api\/v2\/video\/adv\/mainPage$/.test(u)));
assert.ok(urls.some(u => /argus\/api\/v1\/video\/adv\/finishWatch$/.test(u)));
assert.ok(urls.some(u => /argus\/api\/v3\/checkin\/packagelist$/.test(u)));
assert.ok(!urls.some(u => /argus\/api\/v3\/checkin\/packagelist$/.test(u)));
assert.ok(urls.some(u => /argus\/api\/v2\/checkin\/detail$/.test(u)));
assert.ok(urls.some(u => /argus\/api\/v2\/checkin\/lottery$/.test(u)));
assert.ok(urls.some(u => /argus\/api\/v3\/checkin\/checkinexchangepage$/.test(u)));
@@ -444,6 +455,10 @@ test('optional QDReader full tasks use upstream executable endpoints and sign ab
assert.ok(urls.some(u => /^https:\/\/magev6\.if\.qidian\.com\/argus\/api\/v2\/message\/pullmessage/.test(u)));
const signed = r.calls.filter(c => /api\.120399\.xyz\/qdreader\/sign$/.test(c.url)).map(c => JSON.parse(c.body).url);
assert.ok(signed.includes('https://magev6.if.qidian.com/argus/api/v2/message/pullmessage'));
const finishCalls = r.calls.filter(c => /argus\/api\/v1\/video\/adv\/finishWatch$/.test(c.url));
assert.equal(finishCalls.length, 6);
assert.deepEqual(finishCalls.map(c => new URLSearchParams(c.body).get('taskId')), ['adv-1', 'surprise-1', 'one-ad', 'daily-3', 'daily-3', 'daily-3']);
assert.match(r.replies[0], /激励任务✅/);
assert.match(r.replies[0], /每日任务✅/);
assert.match(r.replies[0], /每日抽奖✅/);
@@ -825,14 +840,14 @@ test('adv task treats upstream result 9 as accepted and verifies finished state'
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 1, msg: '无可领取礼包' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: 'old-done', Title: '已完成旧任务', IsFinished: 1 }, { TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 0 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: 'old-done', Title: '已完成旧任务', IsFinished: 1 }, { TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 0 }] } } } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { result: 9, message: '' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: 'old-done', Title: '已完成旧任务', IsFinished: 1 }, { TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 1 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: 'old-done', Title: '已完成旧任务', IsFinished: 1 }, { TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 1 }] } } } },
],
});
assert.match(r.replies[0], /激励任务✅\(已完成\)/);
assert.match(r.replies[0], /激励任务✅\(任务已完成\)/);
assert.match(r.replies[0], /汇总:成功 1 \/ 失败 0 \/ 总计 1/);
assert.equal(r.calls.filter(c => /video\/adv\/finishWatch$/.test(c.url)).length, 1);
assert.match(r.calls.find(c => /video\/adv\/finishWatch$/.test(c.url)).body, /1165585369246138372/);
@@ -854,18 +869,18 @@ test('adv task does not report success when only unrelated task is finished afte
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 1, msg: '无可领取礼包' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: 'old-done', Title: '已完成旧任务', IsFinished: 1 }, { TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 0 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: 'old-done', Title: '已完成旧任务', IsFinished: 1 }, { TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 0 }] } } } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { result: 9, message: '' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: 'old-done', Title: '已完成旧任务', IsFinished: 1 }, { TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 0 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: 'old-done', Title: '已完成旧任务', IsFinished: 1 }, { TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 0 }] } } } },
],
});
assert.match(r.replies[0], /激励任务❌\(任务未完成\)/);
assert.match(r.replies[0], /激励任务❌\(部分任务未完成\)/);
assert.match(r.replies[0], /汇总:成功 0 \/ 失败 1 \/ 总计 1/);
});
test('adv task follows upstream final-item completion instead of submitted-id inference', () => {
test('adv task requires every upstream DailyBenefitModule entry finished after callbacks', () => {
const store = {
qdreader_cookie_json: JSON.stringify({ '12345': cookie }),
qdreader_user_bind_json: JSON.stringify({ '12345': 'user-a' }),
@@ -881,7 +896,7 @@ test('adv task follows upstream final-item completion instead of submitted-id in
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 1, msg: '无可领取礼包' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [
{ TaskId: 'target-a', Title: '看视频领福利A', IsFinished: 0 },
{ TaskId: 'target-b', Title: '看视频领福利B', IsFinished: 0 },
{ TaskId: '1165585369246138370', Title: '每日签到', IsFinished: 0 },
@@ -893,15 +908,15 @@ test('adv task follows upstream final-item completion instead of submitted-id in
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { result: 9, message: '' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [
{ TaskId: 'target-a', Title: '看视频领福利A', IsFinished: 0 },
{ TaskId: 'target-b', Title: '看视频领福利B', IsFinished: 0 },
{ TaskId: '1165585369246138370', Title: '每日签到', IsFinished: 1 },
] } } } },
],
});
assert.match(r.replies[0], /激励任务\(完成\)/);
assert.match(r.replies[0], /汇总:成功 1 \/ 失败 0 \/ 总计 1/);
assert.match(r.replies[0], /激励任务\(部分任务未完成\)/);
assert.match(r.replies[0], /汇总:成功 0 \/ 失败 1 \/ 总计 1/);
});
test('adv task iterates every unfinished upstream entry without local non-ad filtering', () => {
@@ -920,20 +935,22 @@ test('adv task iterates every unfinished upstream entry without local non-ad fil
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 1, msg: '无可领取礼包' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [
{ TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 0 },
{ TaskId: '1165585369246138370', Title: '每日签到', IsFinished: 0 }
] } } } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { result: 9, message: '' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [
{ statusCode: 200, body: { result: 9, message: '' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [
{ TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 1 },
{ TaskId: '1165585369246138370', Title: '每日签到', IsFinished: 0 }
{ TaskId: '1165585369246138370', Title: '每日签到', IsFinished: 1 }
] } } } },
],
});
assert.match(r.replies[0], /激励任务\(任务完成\)/);
assert.match(r.replies[0], /激励任务\(任务完成\)/);
assert.equal(r.calls.filter(c => /video\/adv\/finishWatch$/.test(c.url)).length, 2);
assert.ok(r.calls.some(c => /video\/adv\/finishWatch$/.test(c.url) && /1165585369246138370/.test(c.body)));
});
@@ -954,14 +971,14 @@ test('adv task accepts nested data result 9 with empty message from sign gateway
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 1, msg: '无可领取礼包' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 0 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 0 }] } } } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 200, data: { result: 9, message: '' } } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 1 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: '1165585369246138372', Title: '看视频领福利', IsFinished: 1 }] } } } },
],
});
assert.match(r.replies[0], /激励任务✅\(已完成\)/);
assert.match(r.replies[0], /激励任务✅\(任务已完成\)/);
assert.doesNotMatch(r.replies[0], /任务 1165585369246138372 失败/);
});
@@ -984,11 +1001,11 @@ test('finishWatch payload matches upstream lowercase taskId and full captcha fie
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 1, msg: '无可领取礼包' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: '1187767793786748928', Title: '激励碎片', IsFinished: 0 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: '1187767793786748928', Title: '激励碎片', IsFinished: 0 }] } } } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { result: 9, message: '' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: '1187767793786748928', Title: '激励碎片', IsFinished: 1 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: '1187767793786748928', Title: '激励碎片', IsFinished: 1 }] } } } },
],
});
const finishCall = r.calls.find(c => /video\/adv\/finishWatch$/.test(c.url));
@@ -1013,20 +1030,20 @@ test('adv task submits each unfinished upstream list item once before verificati
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 1, msg: '无可领取礼包' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: '1187767793786748928', Title: '激励碎片', IsFinished: 0, NeedCount: 3 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: '1187767793786748928', Title: '激励碎片', IsFinished: 0, NeedCount: 3 }] } } } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { result: 9, message: '' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: '1187767793786748928', Title: '激励碎片', IsFinished: 1, NeedCount: 3 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: '1187767793786748928', Title: '激励碎片', IsFinished: 1, NeedCount: 3 }] } } } },
],
});
assert.match(r.replies[0], /激励任务✅\(已完成\)/);
assert.match(r.replies[0], /激励任务✅\(任务已完成\)/);
const finishCalls = r.calls.filter(c => /video\/adv\/finishWatch$/.test(c.url));
assert.equal(finishCalls.length, 1);
assert.ok(finishCalls.every(c => /1187767793786748928/.test(c.body)));
});
test('adv task follows upstream completion when final list item is finished after callbacks', () => {
test('adv task follows upstream completion when every upstream list item is finished after callbacks', () => {
const store = {
qdreader_cookie_json: JSON.stringify({ '12345': cookie }),
qdreader_user_bind_json: JSON.stringify({ '12345': 'user-a' }),
@@ -1042,7 +1059,7 @@ test('adv task follows upstream completion when final list item is finished afte
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 1, msg: '无可领取礼包' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [
{ TaskId: 'target-a', Title: '看视频领福利A', IsFinished: 0 },
{ TaskId: 'target-b', Title: '看视频领福利B', IsFinished: 0 },
{ TaskId: '1165585369246138370', Title: '每日签到', IsFinished: 0 },
@@ -1054,14 +1071,14 @@ test('adv task follows upstream completion when final list item is finished afte
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { result: 9, message: '' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [
{ TaskId: 'target-a', Title: '看视频领福利A', IsFinished: 0 },
{ TaskId: 'target-b', Title: '看视频领福利B', IsFinished: 0 },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [
{ TaskId: 'target-a', Title: '看视频领福利A', IsFinished: 1 },
{ TaskId: 'target-b', Title: '看视频领福利B', IsFinished: 1 },
{ TaskId: '1165585369246138370', Title: '每日签到', IsFinished: 1 },
] } } } },
],
});
assert.match(r.replies[0], /激励任务✅\(已完成\)/);
assert.match(r.replies[0], /激励任务✅\(任务已完成\)/);
assert.match(r.replies[0], /汇总:成功 1 \/ 失败 0 \/ 总计 1/);
assert.equal(r.calls.filter(c => /video\/adv\/finishWatch$/.test(c.url)).length, 3);
});
@@ -1082,14 +1099,14 @@ test('adv task ignores count metadata and submits each unfinished upstream task
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 1, msg: '无可领取礼包' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: 'partial-task', Title: '看视频领福利', IsFinished: 0, Count: 1, NeedCount: 3 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: 'partial-task', Title: '看视频领福利', IsFinished: 0, Count: 1, NeedCount: 3 }] } } } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { result: 9, message: '' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [{ TaskId: 'partial-task', Title: '看视频领福利', IsFinished: 1, Count: 3, NeedCount: 3 }] } } } },
{ statusCode: 200, body: { code: 0, Data: { DailyBenefitModule: { TaskList: [{ TaskId: 'partial-task', Title: '看视频领福利', IsFinished: 1, Count: 3, NeedCount: 3 }] } } } },
],
});
assert.match(r.replies[0], /激励任务✅\(已完成\)/);
assert.match(r.replies[0], /激励任务✅\(任务已完成\)/);
const finishCalls = r.calls.filter(c => /video\/adv\/finishWatch$/.test(c.url));
assert.equal(finishCalls.length, 1);
assert.ok(finishCalls.every(c => /partial-task/.test(c.body)));
@@ -1112,10 +1129,10 @@ test('daily task follows upstream sequence: surprise task, one-ad task, then thr
{ statusCode: 200, body: { code: 1, msg: '无可领取礼包' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: {
CurrentTask: { TaskId: '1209756598013788162', Title: '惊喜福利任务', IsFinished: 0 },
PackageList: { TaskList: [
{ TaskId: '1165585369246138373', Title: '完成1个广告任务', IsFinished: 0 },
{ TaskId: '1165585369246138372', Title: '每日任务', IsFinished: 0, NeedCount: 3 },
SurpriseBenefit: { TaskId: '1209756598013788162', Title: '惊喜福利任务', IsFinished: 0 },
VideoRewardTab: { TaskList: [
{ TaskId: '1165585369246138373', Title: '完成1个广告任务得奖励', IsReceived: 0 },
{ TaskId: '1165585369246138372', Title: '完成3个广告任务得奖励', IsReceived: 0 },
] }
} } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
@@ -1130,12 +1147,12 @@ test('daily task follows upstream sequence: surprise task, one-ad task, then thr
{ statusCode: 200, body: { result: 9, message: '' } },
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { TaskList: [
{ TaskId: '1165585369246138373', Title: '完成1个广告任务', IsFinished: 1 },
{ TaskId: '1165585369246138372', Title: '每日任务', IsFinished: 1, NeedCount: 3 },
{ TaskId: '1165585369246138373', Title: '完成1个广告任务得奖励', IsReceived: 1 },
{ TaskId: '1165585369246138372', Title: '完成3个广告任务得奖励', IsReceived: 1 },
] } } } },
],
});
assert.match(r.replies[0], /每日任务✅\(已完成\)/);
assert.match(r.replies[0], /每日任务✅\(任务已完成\)/);
const bodies = r.calls.filter(c => /video\/adv\/finishWatch$/.test(c.url)).map(c => c.body);
assert.equal(bodies.length, 5);
assert.match(bodies[0], /1209756598013788162/);
@@ -1234,3 +1251,4 @@ test('stream uid message token matches upstream operator precedence and avoids p
assert.equal(JSON.parse(firstMessageSign.body).data.token, '24QAcr');
assert.notEqual(JSON.parse(firstMessageSign.body).data.token, '1903903219');
});