// ==UserScript== // @name 小雅辅助工具 // @namespace https://gitee.com/fieldlu/xy-script-assets // @version 3.7.3.5 // @description 小雅平台浏览器用户脚本:视频与文档处理、课件批量下载、作业统一导出(作答文档/手写归档,题目·答案·我的作答自由组合)与AI作答保存、讨论区互动等常用功能集成 // @author Confidential // @license GPL-3.0-or-later // @source https://gitee.com/fieldlu/xy-script-assets // @match https://*.ai-augmented.com/* // @noframes // @run-at document-start // @connect gitee.com // @connect * // @require https://cdn.jsdmirror.com/npm/docx@7.1.0/build/index.min.js // @require https://cdn.jsdmirror.com/npm/file-saver@2.0.5/dist/FileSaver.min.js // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @grant unsafeWindow // @icon https://www.ai-augmented.com/static/logo3.1dbbea8f.png // ==/UserScript== /* * 小雅辅助工具 — 开源协议与第三方声明 * * 本脚本采用 GPL-3.0-or-later 协议开源,许可证全文见 * https://gitee.com/fieldlu/xy-script-assets/blob/main/LICENSE * * 开发过程中引用了以下开源项目的部分代码,一并致谢: * - 小雅爬爬爬 作者 zygame1314 MIT License * - 小雅做做做 作者 zygame1314 MIT License * - 小雅自动刷 作者 Qy Apache License 2.0 * - 小雅粘粘粘 作者 Qy Apache License 2.0 * * 上述代码按其原始许可证授权,相应的版权与归属声明完整保留, * 许可证全文及详细声明见仓库内 LICENSE-MIT / LICENSE-APACHE / * THIRD_PARTY_NOTICES.md。署名或标注有误请提交 Issue。 * * 本脚本按「原样」提供,不附带任何明示或暗示的担保; * 使用产生的一切后果由使用者自行承担,请遵守所在学校、平台及当地法律法规。 */ (function () { 'use strict'; /* ================================================================ * 小雅辅助工具 (Xiaoya Assistant) — 架构总览 * ================================================================ * 运行环境:Tampermonkey / 油猴,@run-at document-start,@noframes * 目标平台:whut.ai-augmented.com(武汉理工「理工智课」教学平台) * * 整体结构(单 IIFE,内部按模块分区): * §0 原生 API 快照 —— 劫持前保存 fetch/XHR 原始引用 * §1 脚本更新模块 —— Gitee 版本清单比对与升级提示 * §2 隐身引擎(主世界) —— 页面可见性欺骗/音频静默/防后台节流 * §3 配置常量区 —— 全部具名常量(Object.freeze 冻结) * §4 领域状态 —— 六大业务域状态对象 * playState 播放挂机域(区域路由/引擎模式/跳转状态) * recState 学习记录域(计数器/会话时长) * guardState 防检测域(静音/伪装/看门狗) * discState 讨论区域(ID捕获/名单库/回复库) * dlState 下载域(文件列表/选择集/排序过滤) * settingsState 用户设置域(开关项/主题) * §5 学情概览模块(xyOverview 系 / xyCourseDashboard 系 / xyTodayPrompt 系) * §6 区域路由(switchToZone) 与页面扫描(runLowLevelScanner) * §7 课程目录与课件下载模块(dir 系 / dl 系 / download 系) * §8 刷课引擎(视频/文档挂机、自动提交、雷达跳转) * §9 防检测执行层(鼠标模拟/深度伪装/保活看门狗) * §10 讨论区模块(名单抓取/点赞/自动回复) * §11 作业答题模块(hw*:题目捕获/AI提示词/docx导出/答案回填) * §12 计划调度模块(调度队列 / optimizeScheduleOrder) * §13 UI 装配(createUI/ensureUI) 与反馈模块 * §14 手写纸引擎(XYHinote/XYLayout/XYPaper/XYExport + 笔顺库) * §15 统一导出模块(xyExp*:普通导出/笔记版导出合并入口,题目·标准答案· * 我的作答自由勾选 + 实时预览,Word/PDF/图片/.hinote,图片全模式嵌入) * * 关键设计决策: * - fetch/XHR 原型劫持用于被动截包(讨论区ID、作业题目), * 所有劫持链最终 apply 回原生引用,保证平台功能不受影响。 * - 主世界桥接:需要页面级 API(Aliplayer SDK)时通过 * unsafeWindow 共享队列通信,规避 TM 沙箱隔离。 * - VOD 视频(type=9 任务节点)的 quote_id 不是云盘资源 ID, * 必须经 play_auth → Aliplayer 换流取公网 mp4 直链。 * - 跨域媒体下载走 GM_xmlhttpRequest 特权通道绕过 CORS; * * 模块边界与构建(企业级工程化约定): * - 源码按 [MODULE] 区块组织(见 temp/xiaoya-build/build.js 打包器), * 支持 //!@depends 依赖声明、拓扑排序内联与 tree-shaking。 * - 视图层组件化:xyBuildPanelTemplate(纯模板)/ createUI(编排器)/ * xyBindPanelEvents(事件装配)三段式分离,各司一职。 * 同源云盘文件走原生 fetch 流式读取以支持进度与终止。 * ================================================================ */ const _hw_nativeFetch = window.fetch; const _hw_nativeXhrOpen = XMLHttpRequest.prototype.open; const _hw_nativeXhrSend = XMLHttpRequest.prototype.send; const SCRIPT_VERSION = typeof GM_info !== 'undefined' ? GM_info.script.version : '未知'; const domain = window.location.hostname; /* ================================================================ * 脚本更新模块 * ---------------------------------------------------------------- * 更新源为 Gitee 仓库 xy-script-assets 中的版本清单 JSON * (xy-script.latest.json),字段含 version / notes[] / changelogURL。 * 拉取流程:GM_xmlhttpRequest 绕过页面 CSP 直连 Gitee → * compareVersion 与当前 SCRIPT_VERSION 逐段比对 → * 有新版时面板按钮点亮并弹 toast,由用户确认后打开下载页。 * 清单 URL 携带时间戳查询参数规避 CDN/浏览器缓存,保证读到最新版。 * ================================================================ */ const SCRIPT_UPDATE = { infoURL: 'https://gitee.com/fieldlu/xy-script-assets/raw/main/xy-script.latest.json', downloadURL: 'https://gitee.com/fieldlu/xy-script-assets/raw/main/%E5%B0%8F%E9%9B%85%E8%BE%85%E5%8A%A9%E5%B7%A5%E5%85%B7%20.user.js', projectURL: 'https://gitee.com/fieldlu/xy-script-assets' }; /** * 语义化版本号比较器,用于判断 Gitee 清单版本是否新于本地版本。 * * 机制: * 1. 将两个版本串按「连续数字段」切分为数值数组('3.7.2.3' → [3,7,2,3], * 非数字字符一律视作分隔符,兼容 v 前缀、日期后缀等杂格式); * 2. 以较长的段数为准逐位比较,短的一方缺失位按 0 补齐(3.7 == 3.7.0); * 3. 首个不相等的位决定大小;全部相等返回 0。 * * @param {string|number} a - 待比较版本号(null/undefined 按 '0' 处理) * @param {string|number} b - 基准版本号 * @returns {number} a 较新返回 1;b 较新返回 -1;完全一致返回 0 * [DEEP-DOC] */ function compareVersion(a, b) { const pa = String(a || '0').split(/[^\d]+/).filter(Boolean).map(Number); const pb = String(b || '0').split(/[^\d]+/).filter(Boolean).map(Number); const len = Math.max(pa.length, pb.length, 1); for (let i = 0; i < len; i++) { const av = Number.isFinite(pa[i]) ? pa[i] : 0; const bv = Number.isFinite(pb[i]) ? pb[i] : 0; if (av !== bv) return av > bv ? 1 : -1; } return 0; } const xyUpdateState = { isLoaded: false, isChecking: false, info: null, error: '', hasNew: false }; let xyUpdateModal = null; /** * 关闭脚本更新弹窗。 * * 机制:先做双保险守卫——弹窗引用存在且仍挂在 document.body 上才继续; * 然后将遮罩 opacity 渐隐为 0、内部卡片 scale(0.95) 缩小(CSS transition * 负责 250ms 动画),300ms 后 remove() 移除节点,并清空模块级引用 * xyUpdateModal 以便下次 xyShowUpdateModal 能重新懒创建。 * * 副作用:DOM 移除 #xy-update-box 的最外层遮罩;重置模块状态变量。 * [DEEP-DOC] */ function xyCloseUpdateModal() { const modal = xyUpdateModal; if (!modal || !document.body.contains(modal)) return; const box = modal.querySelector('#xy-update-box'); modal.style.opacity = '0'; if (box) box.style.transform = 'scale(0.95)'; setTimeout(() => modal.remove(), 300); xyUpdateModal = null; } /** * 刷新面板头部「检查更新」按钮的三态外观。 * * 三态状态机: * - xyUpdateState.isChecking → 加 is-checking 类,文案「⏳ 检查中」 * - hasNew → 加 is-new 类,文案「🎉 有新版」 * - 其余 → 无高亮,文案「↻ 检查更新」 * * 容错:按钮不存在(面板未创建/被移除)时静默返回。每次调用都会先移除 * 全部状态类再按当前态添加,避免类名残留。 * [DEEP-DOC] */ function xyUpdateHeaderButton() { const btn = document.getElementById('xy-seg-update'); if (!btn) return; btn.classList.remove('is-new', 'is-checking'); if (xyUpdateState.isChecking) { btn.classList.add('is-checking'); btn.innerHTML = '⏳ 检查中'; } else if (xyUpdateState.hasNew) { btn.classList.add('is-new'); btn.innerHTML = '🎉 有新版'; } else { btn.innerHTML = '↻ 检查更新'; } } /** * 更新弹窗的内容渲染器(局部刷新,不重建容器)。 * * 渲染内容: * - 双卡片对照:当前版本(SCRIPT_VERSION)与最新版本大字展示; * 有新版时最新版卡片边框转绿色系以突出视觉焦点。 * - 状态行:检查中 / 错误信息(红)/ 已是最新 / 发现新版,四态互斥。 * - notes 数组存在时渲染更新日志