31f7020190
- 登录要过 4 位图形验证码:readCaptcha 返回 data:image/png;base64,用 ddddocr 识别, 失败按登录页 #errorText 判断原因并最多重试 5 次 - 换票入口纠正:票按 ITLMS-xxx||ticketId 两段 GET /nts/loginToStoreByAccount, 之前直接带 ?ticket= 访问 courseRegister 是无效的 - requirements / pyproject 增加 ddddocr;文档同步实测结论
50 lines
5.5 KiB
Markdown
50 lines
5.5 KiB
Markdown
# 更新日志
|
||
|
||
## Unreleased
|
||
|
||
### 重构
|
||
|
||
- 前端从单文件 `static/index.html`(原生 JS)改为 `web/` 工程:React 19 + TypeScript + Vite + Tailwind CSS v4;Vite 直接输出到 `static/`,FastAPI 托管 `/` 与 `/assets`,运行 Python 不再需要 Node
|
||
- 新旧学习平台合并为「莞易学」:`jspx.dgjy.net`(登录入口)与 `study.dgjy.net`(学习入口)统一注册为 `Platform(id="guanyixue", label="莞易学")`,课程页代际(`legacy` / `spa`)由 `platforms/detect.py` 判断,平台内部按代际分发到 `jspx.py` / `study.py`
|
||
- `Platform` 新增 `entries`(登录 / 学习入口 URL 片段)与 `registry.detect()`;课程发现按入口识别平台,新增平台不再需要改引擎。新增 `GET /api/platforms` 供前端展示平台名
|
||
- 添加账号新增「学习平台」下拉(数据来自 `GET /api/platforms`);`accounts` 表新增 `platform` 字段(老库启动时自动补列),账号选定平台后,登录 / 刷新课程 / 发现课程分别走该平台的 `login` / `list_courses` / `discover`,学习与测验按 `course["platform"]` + `generation` 分发
|
||
- `Platform` 增加账号级可选入口:`session` / `dump_cookies` / `login` / `list_courses` / `discover` / `renew_session` / `profile`;引擎和路由按 `registry.get(account["platform"])` 取实现,接入第二个平台只需写一个模块
|
||
- 测验交卷从 `platform`(jspx / study)改为 `generation`(legacy / spa),接口返回 `platform="guanyixue"` + `generation`
|
||
- 代码改为标准 `src/` 包布局:业务代码全部在 `src/study_tool/`,根目录 `app.py` 只做启动壳(`python app.py`、`start.bat`、Dockerfile 都不用改);新增 `pyproject.toml`,`pip install -e .` 后可用 `study-tool` 命令
|
||
- 平台拆成插件包 `src/study_tool/platforms/`:`base.py` 定义 `Platform` 契约、`registry.py` 注册表;引擎按 `course["platform"]` 从注册表分发
|
||
- HTTP 接口收进 `routes/`(accounts / misc / logs),`docs/architecture.md` 说明分层、平台识别与新增平台的步骤
|
||
- 散落的 JS 脚本统一收进 `script/`:运行必需的 `des.js` / `desenc.js` 放 `script/`(`config.py` 的 `DESENC` 指向 `script/desenc.js`),不参与运行的 `dgjy-toolkit.user.js`、`study-axios.mjs` 移到 `script/reference/` 作参考
|
||
|
||
### 新增
|
||
|
||
- 新增平台「广东公需课」(`platforms/gdgxk.py`):`jsglpt.gds.edu.cn` 账号密码(base64)登录后换 ITLMS 票进 `jsxx.gds.edu.cn`,课程列表读 `/uc/store/courseRegister`;学习只跑 `updateViewTime1` 进度心跳(服务端按 `lastViewTime` 直接记账,不需要真播)。票按 `ITLMS-xxx||ticketId` 两段交给 `jsxx.gds.edu.cn/nts/loginToStoreByAccount`;登录要过 4 位图形验证码,用 ddddocr 离线识别并自动重试。配套 `script/capture-jsglpt.py`(抓包取证)与 `script/test-gdgxk.py`(接口自测)
|
||
- 统一日志源 `runtime.log()`:控制台、内存(`/api/log`)、SQLite(`/api/log/history`)同一份内容;新增右上角「系统日志」弹窗查看 `key=system` 的启动/设置类日志
|
||
- 设置保存、服务启动都写入统一日志;卡片「课程日志」和「系统日志」的「清空」会同时清内存和 SQLite
|
||
- 前端:卡片状态徽标、学习进度、课程勾选、卡片内实时日志、测验 / 设置 / 系统日志弹窗全部保留;新增平台名徽标与空态引导
|
||
|
||
### 修复
|
||
|
||
- 账号接口的错误分支引用未导入的 `JSONResponse`、删除账号引用未导入的 `RUNS` / `RUNS_LOCK`,登录失败 / 删除账号会 500:补齐导入
|
||
- `discover()` 引用未定义的 `detect_platform` / `has_study_marker` 导致课程发现 `NameError`:代际识别集中到 `platforms/detect.py`,两代页面共用同一套判断
|
||
- 系统设置里的大模型配置保存后重新打开会回到默认值:`save_settings` 写的是嵌套结构 `{llm, study}`,`load_settings` 却按顶层字段读,现在改成从 `llm` 子对象读取
|
||
- AI 答题整段同步等待导致浏览器 / 反代超时:`/api/quiz/answer` 改为流式(text/event-stream)分批返回,每批失败自动重试一次
|
||
- AI 答题解析不出 JSON 时直接判空:补 `max_tokens`、空内容 / 非 JSON 抛错重试,并支持从自由文本、截断 JSON 里抠答案,多选连写(`AC`)也能识别
|
||
- 控制台是 GBK 时日志里含 `⚠` 之类字符会让工作线程抛 `UnicodeEncodeError`:`runtime.log` 现在编码失败会自动降级
|
||
|
||
## v0.0.1
|
||
|
||
首个版本。
|
||
|
||
### 新增
|
||
|
||
- 学习方式配置:快速学习(只调 `period/study/log` 接口)/ 常规学习(开浏览器真播视频,1–5 路并发)
|
||
- 常规学习:每路独立无头浏览器,可见性补丁防暂停;平台按课节顺序放行时自动降为 1 路,并把被指定的课时提到队首
|
||
- 抓包模式:`POST /api/capture` 记录所有 XHR/fetch(不限域名),`window.open` 新开的标签页同样挂监听,结果落 `data/capture-*.json`
|
||
- 界面:系统设置新增「学习方式」(模式 + 并发数),卡片「更多」菜单新增「抓包 / 停止抓包」
|
||
|
||
### 修复
|
||
|
||
- 视频完成上报补齐学时台账 `study/log/detail/save`(stime/etime),完成包不再带 `lastProgressTime`
|
||
- 培训里的「课程」容器节点(periodType 10/13)不会自动完成:补一发 `isComplete`,并用 `PUT /course/front/calFinalScore` 重算课程完成计数
|
||
- 并发上报导致课程完成计数丢失(实测 14 个课时只记 11 个),现在每门课跑完自动重算
|