Skip to content

V3.4:合并悬空分支 + 收敛修复 55 条反馈中的高频缺陷(F1–F8,含独立对抗验证) - #58

Closed
ywdddddddddd wants to merge 1 commit into
chaolucky18:masterfrom
ywdddddddddd:release/v3.4
Closed

ywdddddddddd wants to merge 1 commit into
chaolucky18:masterfrom
ywdddddddddd:release/v3.4

Conversation

@ywdddddddddd

Copy link
Copy Markdown

V3.4:合并悬空分支 + 收敛式修复线上高频缺陷(F1–F8)

本 PR 做两件事:(1)把悬空的 v3_tampermonkey 分支合并进 master;(2)在 V3.3 基础上交付 V3.4,针对仓库里 55 条 issue/PR 中最高频的缺陷做收敛式修复,并为每条修复补上可复现的回归用例。


一、分支合并

GitHub compare API 实测的分支关系(非推测):

分支 与 master 的关系 处置
v1 ahead_by=0, behind_by=24 — 已被 master 完全包含 无需搬运
v2_old ahead_by=0, behind_by=9 — 已被 master 完全包含 无需搬运
v3_tampermonkey ahead_by=1, behind_by=5真实分叉 本次合并

git blob 级验证:v2_oldv3_tampermonkeyv2.js(77f7bcbf)、xuexitong.js(9c1e5b05)、.gitignore(041fb00d) 与 master 逐字节相同v3_tampermonkeyv3_optimized.js(a45d2559) 是 V3.0.0,早于 master 的 V3.3,合入会倒退。

因此只合并该分支的唯一独有产物并归档其文档,内容零丢失:

  • 新增 学习通自动刷课助手.user.js(V3.0.0 独立油猴版,自带可视化控制面板,7cc0bdb6)— 仅归档保留,同步到 V3.4,不在维护范围
  • 归档 docs/legacy/README-v3.0.0.mddocs/legacy/v3_optimized-v3.0.0.js
  • README.md 冲突按 master 版本裁决

合并后三个分支均已完全被 master 包含,不再有悬空内容。


二、修复清单

每条修复在 v3_optimized.js 内以 F编号(#issue) 注释标注依据。

# 修复 对应反馈
F1 导航死锁nextUnit() 置位 _nextUnitPending 后只在部分分支复位,「无视频安全停止 / 触顶重试 / 静音失败触顶 / 本课程已完成」之后所有切换被静默忽略。改为 try/finally + 10 处显式释放;destroy() 亦复位 #9 #24 #27 #37 #50
F2 小节内多视频只播第一个:下标解析收敛为唯一入口 _resolveCatalogPosition()(区分 active-node/active-parent/tracked),并引入视频任务点模型_getVideoTaskFrames/_getNextPendingVideoTaskIndex/_areAllVideoTasksComplete),逐个播完未完成任务点才进下一节 #14 #15 #24 #27 #37
F3 无视频/课件页卡死:仅在节点自带完成标记时可自动前进(缺一即判 false,绝不猜),连续前进受上限约束;新增任务点弹窗处理——点「去学习/去完成」回到未完成任务点,不点「下一节」硬闯,含冷却与每小节次数上限 #38 #42 #43 #50
F4 异常暂停与风控删除 _bindPageGuards(),不再在 document/window 上劫持 mouseout/mouseleave;恢复播放改为「非用户主动暂停 + 进度确实停滞 + 冷却 + 每小节预算」;接入 PR #56 的保活阶梯(7s 无进度 → pause/play → 2.5s 复检 → 回拨重播)与 play() 超时保护,且阶梯与恢复共用同一份次数预算,不放大抢播量;所有定时器统一登记、destroy() 清零 #19 #26 #32 #54 #55
F5 互动题弹窗卡死:命中弹窗后清掉待执行跳转、停止监控、拒绝 nextUnit()/play() 并提示手动完成,弹窗消失后自动恢复。不含任何自动作答 #29 #39 #42
F6 视频元素发现:选择器由 2 个扩展为 6 级;frame 搜索带深度与数量双上限;切小节/切回视频页/run()/destroy() 显式失效缓存,并检查 isConnected 以捕获 iframe 重载后的失效节点 #18 #52 #55
F7 启动与文档:就绪判定改为「#coursetree 存在已渲染 .posCatalog_select」;CDN 被拦截/目录缺失/run() 抛错均给出可操作提示;README 重写(链接全部有效、默认配置与代码逐项一致) #4 #5 #12 #16 #17 #23 #33 #47
F8 V1 空指针xuexitong.js:39querySelector('li[title="视频"]').click() 无判空,上报堆栈 main (<anonymous>:39:45) + 119:1 与该文件行号列号完全吻合。改为多选择器兜底 + 判空 + 可操作提示 #14 #15 #16 #17 #18

倍速与任务点(#2 #3 #6 #28 #31

服务端强制,非脚本可解。默认 playbackRate 由 1.5 改为 1.0,依据两份独立证据:平台 reportTimeInterval 每 60 秒上报一次时间、部分课程要求观看时长达到 100%,1.5 倍既容易导致学时不达标、也更容易触发反作弊(#28 #31)。本 PR 不加入任何倍速回写对抗或验证码绕过——那正是 #32/#54「反复暂停并弹验证码」的来源之一。README 已把该约束写成明确的已知限制,倍速仍可手动调高。


三、独立对抗验证发现并修复的缺陷

在独立验证阶段复现了一个 medium 缺陷并修复:_handleVideoEnded() 的自动跳转 setTimeout 未登记到统一账本,而 _handleVideoPlay / playCurrentIndex / _handleVideoLoaded 三处却在取消它 —— 取消失效。后果:视频结束后 1s 内若已进入下一小节,1.2s 后陈旧定时器会再次跳节,把刚打开的小节瞬间跳过。这正是 #9/#24/#27/#37/#50 那类「跳节」反馈的直接机制。

修复:该定时器改用 _schedule() 登记;新增 _cancelDelayedNextUnit()(取消 + 置空 + 复位 _handlingVideoEnd),6 个调用点,保证下一段视频结束仍能正常跳转一次。


四、有意不吸收的内容

来源 内容 原因
PR #53 自动选择选项并提交互动答题 属替用户作答考核题。只吸收其检测思路,不吸收作答与提交逻辑
PR #57 接入大模型自动完成章节测验 端点 api.deepseek.com、浏览器端 Bearer、题干内容出境、restore-local-configs.mjs 会把 apiKey 明文写回源码;且油猴端 @grant none 且全 PR 无 @connect,实际跑不通。verify-no-secrets.mjs 只打印不 exit(1),不构成门禁
PR #48 18 个文件的整体改写(含 chrome-extension) chrome-extension/v3_optimized.user.js 是第二份源码副本,违反「单一源码 + 构建脚本」约定(由 tests/verify-v3.mjs 强制);其测试是硬编码版本号的 includes() 字符串检查。但其功能思路已逐条吸收:多视频任务点模型、任务点弹窗、任务分类、跨域 frame 守卫、弹窗节流、jQuery 兼容——15 个函数在源码中带 // 思路移植自 PR #48 @CsuCook1e 署名
PR #22 / #34 仅针对 xuexitong.js(V1) 与 v2.js(V2) 的修复 改动点不适用于 v3_optimized.js;多视频计数思路已被 F2 覆盖
v3_tampermonkey 控制面板 createControlPanel 可视化面板 UI 增强而非缺陷修复;内联 onclick@grant/CSP 耦合、无 destroy。作为独立产物完整归档

五、给维护者的 PR 处置建议

PR 建议
#22 / #34 关闭(改动面向 V1/V2,思路已被 F2 覆盖)
#48 建议关闭并致谢;其功能思路已被本 PR 吸收(其分支与当前 master 冲突,无法直接合并)
#49 其就绪判定思路已被 F7 吸收,可关闭并致谢
#53 / #56 两者是互补而非替代(#56 产物中 autoAnswerInteraction 计数为 0)。诊断结论已被本 PR 保留;若维护者愿意接受自动作答,可作为独立分支另行评估
#57 不建议合并(见上表风险),建议作者补充 @connect + 门槛化 verify-no-secrets 后再议

六、验证方式

node scripts/build-userscript.mjs     # 由唯一源码生成油猴版
node tests/verify-v3.mjs              # 两入口逐字节同步 + 语法校验
node tests/regression.mjs             # 44 用例 / 192 断言
node tests/adversarial.mjs            # 49 用例 / 0 findings
node tests/verify-legacy-v1.mjs       # V1 静态断言 14 项

测试基于 jsdom,不联网(加载脚本前注入页面自带的 jQuery,避免触发 CDN);每个用例结束 destroy() 并断言定时器净零残留;对抗用例对源码做 SHA256 钉扎,运行期间源码被改写即判失败。

反向验证(证明用例不是「无论如何都通过」):把被测源码指向 V3.3,同一套用例 32/44 失败,其中 F1 直接复现导航死锁。


七、致谢

基于 chaolucky18/xuexitongScript@1f129f0d (master, V3.3)。

分支合并: GitHub compare 证实 v1(ahead 0/behind 24)、v2_old(ahead 0/behind 9) 已被 master
完全包含; v3_tampermonkey(ahead 1/behind 5) 真实分叉, 仅其独有产物被合并并归档。合并后三分支
均被 master 完全包含。

修复 F1-F8 (每条带 F编号+#issue 注释):
F1 导航死锁 / F2 小节内多视频 / F3 无视频课件页 / F4 异常暂停与风控 /
F5 互动题弹窗(仅检测不代答) / F6 视频元素发现 / F7 启动与文档 / F8 V1 空指针

独立对抗验证复现的 medium 缺陷已修复:
视频结束后自动跳转的 setTimeout 未登记到 _delayedNextUnitTimer, 而三处却在取消它 ->
取消失效, 陈旧定时器 1.2s 后会把刚打开的小节瞬间跳过。现改用 _schedule() 登记 +
新增 _cancelDelayedNextUnit() (6 个调用点, 复位 _handlingVideoEnd)。

验证:
regression 192/192 | adversarial 49/49 且 0 findings | verify-legacy-v1 14/14 | verify-v3 同步通过
反向验证: 同一套用例跑 V3.3 -> 32/44 失败, 证明用例非空转

有意不吸收: PR#53 自动作答 / PR#57 大模型答题 / PR#48 整体改写 / v3_tm 控制面板
思路来源署名: PR#48 @CsuCook1e、PR#53 @ooooooomg、PR#56 @Azuuimio
@ywdddddddddd
ywdddddddddd deleted the release/v3.4 branch September 12, 2026 02:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant