fix(qdreader): match upstream finishWatch payload
This commit is contained in:
@@ -733,3 +733,25 @@ cmp -s plugins/qdreader/qdreader_sign_autman.js js/qdreader_sign_autman.js
|
|||||||
- 明确默认只跑安全签到 + 领取奖励;可选任务需要在 `启点账号 → 账号任务配置` 按账号开启。
|
- 明确默认只跑安全签到 + 领取奖励;可选任务需要在 `启点账号 → 账号任务配置` 按账号开启。
|
||||||
- 明确查询结果从归档判断,不要把清空近期日志误解释成没运行。
|
- 明确查询结果从归档判断,不要把清空近期日志误解释成没运行。
|
||||||
- 给出测试、commit、push、raw 验证结果,避免只说“应该可以”。
|
- 给出测试、commit、push、raw 验证结果,避免只说“应该可以”。
|
||||||
|
|
||||||
|
### 10.6 QDReader 原项目接口转写:字段大小写必须逐项核对
|
||||||
|
|
||||||
|
2026-05 复核启点激励任务时发现:原脚本能完成、插件不能完成的根因不是任务流程,而是 `finishWatchAdv` 的 POST payload 被转写错了字段名。上游提交字段为:
|
||||||
|
|
||||||
|
```text
|
||||||
|
taskId=<TaskId>&BanId=0&BanMessage=&CaptchaAId=&CaptchaURL=&CaptchaType=0&Challenge=&Gt=&NewCaptcha=0&Offline=0&PhoneNumber=&SessionKey=
|
||||||
|
```
|
||||||
|
|
||||||
|
插件曾误写成:
|
||||||
|
|
||||||
|
```text
|
||||||
|
TaskId=<TaskId>&BanId=0&BanMessage=&Challenge=&CaptchaType=0&Fee=&Gif=&Gt=&NewCaptcha=0&Offline=0&PhoneTicket=&SessionKey=
|
||||||
|
```
|
||||||
|
|
||||||
|
注意点:
|
||||||
|
|
||||||
|
- `taskId` 是小写 `t`,不是 `TaskId`。
|
||||||
|
- 必须保留上游的空字段 `CaptchaAId`、`CaptchaURL`、`PhoneNumber`。
|
||||||
|
- 不要凭字段含义替换成 `Fee`、`Gif`、`PhoneTicket`。
|
||||||
|
- 复刻上游混淆脚本时,除流程外还要用测试断言实际请求 `body` 的完整字符串,避免只断言 URL/次数导致参数漂移漏检。
|
||||||
|
- QDReader 激励/每日任务都共用 `finishWatchAdv`,修改 payload 时必须覆盖两类任务测试。
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
//[author: Hermes]
|
//[author: Hermes]
|
||||||
//[service: BOSS]
|
//[service: BOSS]
|
||||||
//[class: 工具类]
|
//[class: 工具类]
|
||||||
//[version: 2.10.8]
|
//[version: 2.10.9]
|
||||||
//[platform: web,qq,wx,tg,tb,fs,we]
|
//[platform: web,qq,wx,tg,tb,fs,we]
|
||||||
//[public: false]
|
//[public: false]
|
||||||
//[price: 0]
|
//[price: 0]
|
||||||
@@ -276,7 +276,7 @@ function contentText() {
|
|||||||
}
|
}
|
||||||
function usage() {
|
function usage() {
|
||||||
return [
|
return [
|
||||||
"启点读书签到插件 v2.10.8",
|
"启点读书签到插件 v2.10.9",
|
||||||
"【一级菜单】",
|
"【一级菜单】",
|
||||||
"账号管理:启点账号",
|
"账号管理:启点账号",
|
||||||
"执行查询:启点查询",
|
"执行查询:启点查询",
|
||||||
@@ -593,7 +593,7 @@ function nested(obj, path) {
|
|||||||
return cur
|
return cur
|
||||||
}
|
}
|
||||||
function makeVideoPayload(taskId) {
|
function makeVideoPayload(taskId) {
|
||||||
return { TaskId: String(taskId || ""), BanId: "0", BanMessage: "", Challenge: "", CaptchaType: "0", Fee: "", Gif: "", Gt: "", NewCaptcha: "0", Offline: "0", PhoneTicket: "", SessionKey: "" }
|
return { taskId: String(taskId || ""), BanId: "0", BanMessage: "", CaptchaAId: "", CaptchaURL: "", CaptchaType: "0", Challenge: "", Gt: "", NewCaptcha: "0", Offline: "0", PhoneNumber: "", SessionKey: "" }
|
||||||
}
|
}
|
||||||
function field(obj, names, def) {
|
function field(obj, names, def) {
|
||||||
for (var i = 0; i < names.length; i++) if (obj && obj[names[i]] !== undefined && obj[names[i]] !== null) return obj[names[i]]
|
for (var i = 0; i < names.length; i++) if (obj && obj[names[i]] !== undefined && obj[names[i]] !== null) return obj[names[i]]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
//[author: Hermes]
|
//[author: Hermes]
|
||||||
//[service: BOSS]
|
//[service: BOSS]
|
||||||
//[class: 工具类]
|
//[class: 工具类]
|
||||||
//[version: 2.10.8]
|
//[version: 2.10.9]
|
||||||
//[platform: web,qq,wx,tg,tb,fs,we]
|
//[platform: web,qq,wx,tg,tb,fs,we]
|
||||||
//[public: false]
|
//[public: false]
|
||||||
//[price: 0]
|
//[price: 0]
|
||||||
@@ -276,7 +276,7 @@ function contentText() {
|
|||||||
}
|
}
|
||||||
function usage() {
|
function usage() {
|
||||||
return [
|
return [
|
||||||
"启点读书签到插件 v2.10.8",
|
"启点读书签到插件 v2.10.9",
|
||||||
"【一级菜单】",
|
"【一级菜单】",
|
||||||
"账号管理:启点账号",
|
"账号管理:启点账号",
|
||||||
"执行查询:启点查询",
|
"执行查询:启点查询",
|
||||||
@@ -593,7 +593,7 @@ function nested(obj, path) {
|
|||||||
return cur
|
return cur
|
||||||
}
|
}
|
||||||
function makeVideoPayload(taskId) {
|
function makeVideoPayload(taskId) {
|
||||||
return { TaskId: String(taskId || ""), BanId: "0", BanMessage: "", Challenge: "", CaptchaType: "0", Fee: "", Gif: "", Gt: "", NewCaptcha: "0", Offline: "0", PhoneTicket: "", SessionKey: "" }
|
return { taskId: String(taskId || ""), BanId: "0", BanMessage: "", CaptchaAId: "", CaptchaURL: "", CaptchaType: "0", Challenge: "", Gt: "", NewCaptcha: "0", Offline: "0", PhoneNumber: "", SessionKey: "" }
|
||||||
}
|
}
|
||||||
function field(obj, names, def) {
|
function field(obj, names, def) {
|
||||||
for (var i = 0; i < names.length; i++) if (obj && obj[names[i]] !== undefined && obj[names[i]] !== null) return obj[names[i]]
|
for (var i = 0; i < names.length; i++) if (obj && obj[names[i]] !== undefined && obj[names[i]] !== null) return obj[names[i]]
|
||||||
|
|||||||
@@ -966,6 +966,37 @@ test('adv task accepts nested data result 9 with empty message from sign gateway
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
test('finishWatch payload matches upstream lowercase taskId and full captcha field names', () => {
|
||||||
|
const store = {
|
||||||
|
qdreader_cookie_json: JSON.stringify({ '12345': cookie }),
|
||||||
|
qdreader_user_bind_json: JSON.stringify({ '12345': 'user-a' }),
|
||||||
|
qdreader_task_pref_json: JSON.stringify({ '12345': { adv: true } }),
|
||||||
|
};
|
||||||
|
const r = runPlugin({
|
||||||
|
content: '启点签到',
|
||||||
|
store,
|
||||||
|
userId: 'user-a',
|
||||||
|
requests: [
|
||||||
|
{ 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: 1, msg: '无可领取礼包' } },
|
||||||
|
{ body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } },
|
||||||
|
{ statusCode: 200, body: { code: 0, Data: { VideoRewardTab: { 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 }] } } } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const finishCall = r.calls.find(c => /video\/adv\/finishWatch$/.test(c.url));
|
||||||
|
assert.ok(finishCall, 'finishWatch request should be issued');
|
||||||
|
assert.equal(finishCall.body, 'taskId=1187767793786748928&BanId=0&BanMessage=&CaptchaAId=&CaptchaURL=&CaptchaType=0&Challenge=&Gt=&NewCaptcha=0&Offline=0&PhoneNumber=&SessionKey=');
|
||||||
|
assert.doesNotMatch(finishCall.body, /TaskId=/);
|
||||||
|
assert.doesNotMatch(finishCall.body, /Fee=|Gif=|PhoneTicket=/);
|
||||||
|
});
|
||||||
test('adv task submits each unfinished upstream list item once before verification', () => {
|
test('adv task submits each unfinished upstream list item once before verification', () => {
|
||||||
const store = {
|
const store = {
|
||||||
qdreader_cookie_json: JSON.stringify({ '12345': cookie }),
|
qdreader_cookie_json: JSON.stringify({ '12345': cookie }),
|
||||||
|
|||||||
Reference in New Issue
Block a user