refactor(plugins): 莞易学迁到 pugins/guanyixue
- platforms/guanyixue.py → pugins/guanyixue/main.py - jspx.py / study.py / detect.py 一并搬进插件目录,插件自包含: 热重载会把实现模块一起重新 import,不再是半截插件 - 导入路径改成 study_tool.pugins.guanyixue.*;quiz.py 两处引用同步更新 - platforms/__init__.py 只剩运行时,load_builtin() 只调 load_plugins() - 新增 pugins/guanyixue/pugin.json(id / title / name) - 同步 AGENTS.md、docs/architecture.md、docs/pugin.md、docs/OPTIMIZATION.md
This commit is contained in:
@@ -31,7 +31,7 @@
|
|||||||
## 代码结构 / 平台插件
|
## 代码结构 / 平台插件
|
||||||
|
|
||||||
- 业务代码都在 `src/study_tool/` 包里;根目录只放启动壳 `app.py`、`pyproject.toml`、`static/`、`data/`、`script/` 这类运行时资源。散落的 JS 脚本统一收进 `script/`,不参与运行的参考脚本放 `script/reference/`。
|
- 业务代码都在 `src/study_tool/` 包里;根目录只放启动壳 `app.py`、`pyproject.toml`、`static/`、`data/`、`script/` 这类运行时资源。散落的 JS 脚本统一收进 `script/`,不参与运行的参考脚本放 `script/reference/`。
|
||||||
- 平台代码有两个落点:插件式平台放 `src/study_tool/pugins/<名字>/`(`pugin.json` 只放 `id` / `title` / `name` 注册信息,`main.py` 放 `Platform` 子类,`load_plugins()` 扫目录 import,新增插件不用改任何 Python 代码;`GET /api/plugins` 看清单,`POST /api/plugins/{name}/enable|disable` 启停,`POST /api/plugins/reload` 热重载);跟共享实现模块关系紧密的平台放 `src/study_tool/platforms/<名字>.py` 并在 `load_builtin()` 里 import。能力只能通过「在子类里实现同名方法」绑定,禁止再写 `Platform(id=..., study=..., session=...)` 这种逐项传函数的注册;模块末尾 `PLATFORM = registry.register(<子类>())`,一个平台只注册一次。同一平台的不同页面代际可以拆成实现模块(如莞易学的 `jspx.py` / `study.py`),由平台模块按 `course["generation"]` 分发。
|
- 平台实现只能放在 `src/study_tool/pugins/<名字>/`:`pugin.json` 只放 `id` / `title` / `name` 注册信息,`main.py` 放 `Platform` 子类,实现复杂的再拆 `jspx.py` / `study.py` 等同目录模块;`load_plugins()` 扫目录 import,新增插件不用改任何 Python 代码(`GET /api/plugins` 看清单,`POST /api/plugins/{name}/enable|disable` 启停,`POST /api/plugins/reload` 热重载)。`src/study_tool/platforms/` 只放运行时(`base` / `contract` / `errors` / `registry`),不再放具体平台。能力只能通过「在子类里实现同名方法」绑定,禁止再写 `Platform(id=..., study=..., session=...)` 这种逐项传函数的注册;模块末尾 `PLATFORM = registry.register(<子类>())`,一个平台只注册一次。同一平台的不同页面代际拆成插件目录内的实现模块,由平台模块按 `course["generation"]` 分发。
|
||||||
- 新增平台的标准步骤:建 `pugins/<名字>/`,写 `pugin.json`(`id` / `title` / `name`)和 `main.py`(`class X(Platform)`,声明 `id` / `label` / `entries`,实现 `study(self, key, s, d, **opts)`,需要登录 / 课程列表 / 发现时再实现 `session` / `dump_cookies` / `login` / `list_courses` / `discover` / `renew_session` / `profile` 对应方法,没有的阶段不写,末尾 `PLATFORM = registry.register(X())`)→ 启动即可,不用改 `load_builtin()`、`engine.py`、`routes/`、前端。
|
- 新增平台的标准步骤:建 `pugins/<名字>/`,写 `pugin.json`(`id` / `title` / `name`)和 `main.py`(`class X(Platform)`,声明 `id` / `label` / `entries`,实现 `study(self, key, s, d, **opts)`,需要登录 / 课程列表 / 发现时再实现 `session` / `dump_cookies` / `login` / `list_courses` / `discover` / `renew_session` / `profile` 对应方法,没有的阶段不写,末尾 `PLATFORM = registry.register(X())`)→ 启动即可,不用改 `load_builtin()`、`engine.py`、`routes/`、前端。
|
||||||
- 引擎、路由、前端都不允许直接 import 某个具体平台模块;需要平台能力时用 `registry.get(course["platform"])`;账号级操作(登录 / 刷新课程 / 发现课程 / 会话)按 `accounts.platform` 用 `registry.get()` 取 `Platform` 上的 `session` / `dump_cookies` / `login` / `list_courses` / `discover` / `renew_session` / `profile`;「添加账号」的平台下拉来自 `GET /api/platforms`。
|
- 引擎、路由、前端都不允许直接 import 某个具体平台模块;需要平台能力时用 `registry.get(course["platform"])`;账号级操作(登录 / 刷新课程 / 发现课程 / 会话)按 `accounts.platform` 用 `registry.get()` 取 `Platform` 上的 `session` / `dump_cookies` / `login` / `list_courses` / `discover` / `renew_session` / `profile`;「添加账号」的平台下拉来自 `GET /api/platforms`。
|
||||||
- 前端源码在 `web/`(React + TypeScript + Vite + Tailwind CSS),构建产物输出到 `static/` 并提交进仓库;改完前端必须执行 `cd web && pnpm build`,不要直接改 `static/` 里的产物。
|
- 前端源码在 `web/`(React + TypeScript + Vite + Tailwind CSS),构建产物输出到 `static/` 并提交进仓库;改完前端必须执行 `cd web && pnpm build`,不要直接改 `static/` 里的产物。
|
||||||
|
|||||||
@@ -23,6 +23,24 @@
|
|||||||
3. `.env` 改 `PORT=8849` 重启 → 实际监听 8849;命令行 `set PORT=8850` 再启动应压过 `.env`。
|
3. `.env` 改 `PORT=8849` 重启 → 实际监听 8849;命令行 `set PORT=8850` 再启动应压过 `.env`。
|
||||||
4. `.env` 里 `BIND_ADDR=127.0.0.1` → 只绑本机;改 `0.0.0.0` → 同网段可访问。
|
4. `.env` 里 `BIND_ADDR=127.0.0.1` → 只绑本机;改 `0.0.0.0` → 同网段可访问。
|
||||||
|
|
||||||
|
## 莞易学迁到插件目录
|
||||||
|
|
||||||
|
**状态**:已实现,待实测确认。
|
||||||
|
|
||||||
|
### 做了什么
|
||||||
|
|
||||||
|
- `platforms/guanyixue.py` → `pugins/guanyixue/main.py`;`jspx.py` / `study.py` / `detect.py`
|
||||||
|
一并搬进 `pugins/guanyixue/`,插件自包含,热重载能覆盖全部实现模块。
|
||||||
|
- 导入路径改成 `study_tool.pugins.guanyixue.*`;`quiz.py` 里对 `jspx` / `study` 的引用同步更新。
|
||||||
|
- `platforms/__init__.py` 只剩运行时,`load_builtin()` 只调 `load_plugins()`。
|
||||||
|
- 新增 `pugins/guanyixue/pugin.json`(id / title / name)。
|
||||||
|
|
||||||
|
### 怎么测
|
||||||
|
|
||||||
|
1. `GET /api/plugins` 列出 `gdgxk` 与 `guanyixue`,两者 enabled / loaded 都是 true。
|
||||||
|
2. 莞易学:刷新课程 → 发现课程 → 开始学习(旧版 / 新版各一次);测验弹窗照常。
|
||||||
|
3. 插件弹窗里对 guanyixue 点「重载」后再跑一次学习,行为不变。
|
||||||
|
|
||||||
## 插件热加载 + 启用/停用清单
|
## 插件热加载 + 启用/停用清单
|
||||||
|
|
||||||
**状态**:已实现,待实测确认。
|
**状态**:已实现,待实测确认。
|
||||||
|
|||||||
+23
-15
@@ -24,15 +24,21 @@ src/study_tool/
|
|||||||
contract.py 生命周期 ↔ 槽位 ↔ 能力名映射
|
contract.py 生命周期 ↔ 槽位 ↔ 能力名映射
|
||||||
errors.py SessionExpired(平台层错误类型)
|
errors.py SessionExpired(平台层错误类型)
|
||||||
registry.py 注册表:register / get / detect / all
|
registry.py 注册表:register / get / detect / all
|
||||||
detect.py 页面代际识别(legacy 旧版 / spa 新版)
|
|
||||||
guanyixue.py 莞易学平台:合并 jspx 登录入口与 study 学习入口
|
|
||||||
jspx.py 莞易学旧版:会话 / 登录 / 课程抓取 / 旧版学习流程
|
|
||||||
study.py 莞易学新版 SPA:StudyClient / 接口学习 / 视频流程
|
|
||||||
pugins/ 插件式平台(加载器扫目录,新增插件不改代码)
|
pugins/ 插件式平台(加载器扫目录,新增插件不改代码)
|
||||||
__init__.py load_plugins / discover / set_enabled / reload(启停 + 热重载)
|
__init__.py load_plugins / discover / set_enabled / reload(启停 + 热重载)
|
||||||
gdgxk/
|
gdgxk/
|
||||||
pugin.json 注册信息:id / title / name(只放元数据)
|
pugin.json 注册信息:id / title / name(只放元数据)
|
||||||
main.py 广东公需课:SSO 换票 + 视频进度心跳
|
main.py 广东公需课:Platform 子类(登录 / 课程 / 学习 / 续期)
|
||||||
|
utils/http.py 域名 / UA / XHR 上报封装与 SessionExpired
|
||||||
|
utils/login.py base64 账号密码 + 图形验证码 + ITLMS 换票
|
||||||
|
utils/course.py 课程列表卡片 / 学习页上报参数 / 进度页活动清单
|
||||||
|
utils/learn.py 活动页打开 → 注册播放 → 1x 心跳上报
|
||||||
|
guanyixue/
|
||||||
|
pugin.json 注册信息:id / title / name
|
||||||
|
main.py 莞易学:Platform 子类,按 generation 分发
|
||||||
|
jspx.py 旧版页面:会话 / 登录 / 课程抓取 / 旧版学习流程
|
||||||
|
study.py 新版 SPA:StudyClient / 接口学习 / 视频流程
|
||||||
|
detect.py 页面代际识别(legacy 旧版 / spa 新版)
|
||||||
routes/ HTTP 接口
|
routes/ HTTP 接口
|
||||||
accounts.py 账号 / 登录 / 登录记录
|
accounts.py 账号 / 登录 / 登录记录
|
||||||
misc.py 课程 / 发现 / 学习 / 停止 / 抓包 / 快照 / 平台列表
|
misc.py 课程 / 发现 / 学习 / 停止 / 抓包 / 快照 / 平台列表
|
||||||
@@ -112,25 +118,26 @@ quiz_key / cookies / plan / project / name`。插件可以只取自己需要的
|
|||||||
### 内置:莞易学
|
### 内置:莞易学
|
||||||
|
|
||||||
`jspx.dgjy.net`(登录入口)和 `study.dgjy.net`(学习入口)是同一个平台,统一注册为
|
`jspx.dgjy.net`(登录入口)和 `study.dgjy.net`(学习入口)是同一个平台,统一注册为
|
||||||
`id=guanyixue`、`label=莞易学`。两代课程页:
|
`id=guanyixue`、`label=莞易学`,实现在 `pugins/guanyixue/`。两代课程页:
|
||||||
|
|
||||||
- `platforms/jspx.py`:旧版页面(`tier-tree-one` / `tier3`),负责会话、登录、课程抓取,
|
- `jspx.py`:旧版页面(`tier-tree-one` / `tier3`),负责会话、登录、课程抓取,
|
||||||
以及旧版学习流程(`_study_builtin`:反馈表 + 测验 + 刷课件)。
|
以及旧版学习流程(`_study_builtin`:反馈表 + 测验 + 刷课件)。
|
||||||
- `platforms/study.py`:新版 Vue SPA,`StudyClient` + `/train/course/front/*` 接口,
|
- `study.py`:新版 Vue SPA,`StudyClient` + `/train/course/front/*` 接口,
|
||||||
以及新版学习流程(`run_study_course`:接口上报 / 真播视频)。
|
以及新版学习流程(`run_study_course`:接口上报 / 真播视频)。
|
||||||
- `platforms/guanyixue.py`:注册平台并按 `course["generation"]` 分发;
|
- `main.py`:注册平台并按 `course["generation"]` 分发;`detect.py` 只判断页面代际,
|
||||||
`platforms/detect.py` 只判断页面代际,不判断平台归属。
|
不判断平台归属。
|
||||||
|
|
||||||
### 内置:广东公需课
|
### 内置:广东公需课
|
||||||
|
|
||||||
`id=gdgxk`,`pugins/gdgxk/main.py` 实现(插件目录,`pugin.json` 只放 id / title / name):
|
`id=gdgxk`,`pugins/gdgxk/` 实现(插件目录,`pugin.json` 只放 id / title / name,`main.py`
|
||||||
|
只放 `Platform` 子类,登录 / 解析 / 心跳工具在 `utils/`):
|
||||||
在 `jsglpt.gds.edu.cn` 登录(账号、密码
|
在 `jsglpt.gds.edu.cn` 登录(账号、密码
|
||||||
都是 base64),再用 `ssoItlmsGxkTicket.action` 换票进 `jsxx.gds.edu.cn`;视频按真实
|
都是 base64),再用 `ssoItlmsGxkTicket.action` 换票进 `jsxx.gds.edu.cn`;视频按真实
|
||||||
流逝时间上报 `updateViewTime1`。没有测验 / 反馈表,所以不实现对应能力。
|
流逝时间上报 `updateViewTime1`。没有测验 / 反馈表,所以不实现对应能力。
|
||||||
|
|
||||||
### 新增一个平台
|
### 新增一个平台
|
||||||
|
|
||||||
1. 新建 `src/study_tool/platforms/<名字>.py`:
|
1. 新建 `src/study_tool/pugins/<名字>/`,写 `pugin.json`(`id` / `title` / `name`)和 `main.py`:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from study_tool.platforms import registry
|
from study_tool.platforms import registry
|
||||||
@@ -158,13 +165,14 @@ quiz_key / cookies / plan / project / name`。插件可以只取自己需要的
|
|||||||
|
|
||||||
平台确实没有的阶段不要写,保持基类的 `None`,引擎按能力判断走不走那个分支。
|
平台确实没有的阶段不要写,保持基类的 `None`,引擎按能力判断走不走那个分支。
|
||||||
|
|
||||||
2. 在 `platforms/__init__.py` 的 `load_builtin()` 里加一行 `from study_tool.platforms import <名字>`。
|
2. 不用改任何代码:`load_plugins()` 扫目录时会自动 import 这个插件。实现复杂时可以像
|
||||||
|
`pugins/guanyixue/` 那样在同一目录再拆 `jspx.py` / `study.py` 等实现模块。
|
||||||
|
|
||||||
3. 平台注册后会自动出现在「添加账号」的平台下拉框;账号选了该平台,登录 / 刷新课程 /
|
3. 平台注册后会自动出现在「添加账号」的平台下拉框;账号选了该平台,登录 / 刷新课程 /
|
||||||
发现课程 / 学习都走它的实现,不需要改路由或前端。
|
发现课程 / 学习都走它的实现,不需要改路由或前端。
|
||||||
|
|
||||||
已内置莞易学(`guanyixue`)和广东公需课(`gdgxk`);`accounts.platform` 是平台分发依据,
|
已内置莞易学(`guanyixue`)和广东公需课(`gdgxk`),都在 `pugins/` 下;`accounts.platform` 是
|
||||||
接入新平台只需在 `platforms/<平台>.py` 实现对应阶段的槽位,引擎与路由不用改。
|
平台分发依据,接入新平台只需建一个插件目录,引擎与路由不用改。
|
||||||
|
|
||||||
## 前端
|
## 前端
|
||||||
|
|
||||||
|
|||||||
+11
-7
@@ -82,7 +82,8 @@ src/study_tool/pugins/
|
|||||||
<名字>/
|
<名字>/
|
||||||
pugin.json 注册信息:id / title / name(不写能力绑定)
|
pugin.json 注册信息:id / title / name(不写能力绑定)
|
||||||
main.py class <名字>(Platform)
|
main.py class <名字>(Platform)
|
||||||
gdgxk/ 广东公需课:pugin.json + main.py
|
gdgxk/ 广东公需课:pugin.json + main.py + utils/(拆开的实现模块)
|
||||||
|
guanyixue/ 莞易学:pugin.json + main.py + jspx.py / study.py / detect.py
|
||||||
```
|
```
|
||||||
|
|
||||||
约定:
|
约定:
|
||||||
@@ -139,8 +140,7 @@ quiz_key / cookies / plan / project / name`,插件只取自己需要的。
|
|||||||
和 `main.py`(按上面的骨架写 `class <名字>(Platform)`)。
|
和 `main.py`(按上面的骨架写 `class <名字>(Platform)`)。
|
||||||
2. `main.py` 末尾 `PLATFORM = registry.register(<名字>())`。
|
2. `main.py` 末尾 `PLATFORM = registry.register(<名字>())`。
|
||||||
3. 不需要改 `load_builtin()`、路由或前端 —— 加载器扫目录时自动 import 各插件。
|
3. 不需要改 `load_builtin()`、路由或前端 —— 加载器扫目录时自动 import 各插件。
|
||||||
跟 `jspx` / `study` 这类共享实现模块关系紧密的平台,仍可以放 `platforms/<名字>.py`,
|
实现复杂时可以在同一目录再拆 `jspx.py` / `study.py` 这类实现模块(见 `guanyixue/`)。
|
||||||
在 `load_builtin()` 里加一行 import。
|
|
||||||
4. 启动服务,`GET /api/platforms` 应出现该平台。
|
4. 启动服务,`GET /api/platforms` 应出现该平台。
|
||||||
5. 联调顺序:`/api/login` → `/api/courses` → `/api/discover` → `/api/study`。
|
5. 联调顺序:`/api/login` → `/api/courses` → `/api/discover` → `/api/study`。
|
||||||
|
|
||||||
@@ -153,8 +153,10 @@ quiz_key / cookies / plan / project / name`,插件只取自己需要的。
|
|||||||
平台私有的重登逻辑改成 `_relogin` 这类私有方法。
|
平台私有的重登逻辑改成 `_relogin` 这类私有方法。
|
||||||
3. 加类属性 `id` / `label` / `entries`,删掉模块末尾的逐项注册。
|
3. 加类属性 `id` / `label` / `entries`,删掉模块末尾的逐项注册。
|
||||||
4. 模块末尾改成 `PLATFORM = registry.register(<类名>())`。
|
4. 模块末尾改成 `PLATFORM = registry.register(<类名>())`。
|
||||||
5. 逐个验证槽位行为与迁移前一致;同一平台的两个代际由 `study` 里按
|
5. 实现模块(`jspx.py` / `study.py` / `detect.py`)一起搬进 `pugins/<名字>/`,目录内互相
|
||||||
`course["generation"]` 分发(参见 `guanyixue.py`)。
|
引用改成 `study_tool.pugins.<名字>.xxx`;外部(如 `quiz.py`)引用同步改路径。
|
||||||
|
6. 逐个验证槽位行为与迁移前一致;同一平台的两个代际由 `study` 里按
|
||||||
|
`course["generation"]` 分发(参见 `pugins/guanyixue/main.py`)。
|
||||||
|
|
||||||
## 硬约束
|
## 硬约束
|
||||||
|
|
||||||
@@ -197,5 +199,7 @@ quiz_key / cookies / plan / project / name`,插件只取自己需要的。
|
|||||||
`course["platform"]` 分发;平台用自由函数 + 逐项注册;学习流程仍在引擎。
|
`course["platform"]` 分发;平台用自由函数 + 逐项注册;学习流程仍在引擎。
|
||||||
3. 契约补全:`contract.py` 推导 `capabilities`;`SessionExpired` 移到 `platforms/errors.py`;
|
3. 契约补全:`contract.py` 推导 `capabilities`;`SessionExpired` 移到 `platforms/errors.py`;
|
||||||
各平台学习流程从引擎搬回平台模块(`engine.py` 只剩账号级编排)。
|
各平台学习流程从引擎搬回平台模块(`engine.py` 只剩账号级编排)。
|
||||||
4. 类式(当前):`Platform` 变成普通基类,平台写成子类(类属性 + 方法),
|
4. 类式:`Platform` 变成普通基类,平台写成子类(类属性 + 方法),禁止逐项传函数注册。
|
||||||
禁止逐项传函数注册;`gdgxk` 与 `guanyixue` 已完成迁移。
|
5. 插件目录(当前):平台全部迁到 `pugins/<名字>/`(`pugin.json` + `main.py`,实现复杂的
|
||||||
|
再拆 `jspx.py` / `study.py` 等),`load_plugins()` 扫目录加载,支持启停与热重载;
|
||||||
|
`gdgxk`、`guanyixue` 都已完成迁移。
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
"""平台包。
|
"""平台包。
|
||||||
|
|
||||||
平台实现有两个落点,写法和契约完全一样(`Platform` 子类 + 注册一次):
|
这里放平台**运行时**:`Platform` 契约(`base.py`)、能力映射(`contract.py`)、
|
||||||
|
错误类型(`errors.py`)、注册表(`registry.py`)。
|
||||||
|
|
||||||
- `pugins/<名字>/`:插件式平台(`pugin.json` + `main.py`),由 `study_tool.pugins.load_plugins()`
|
平台实现都放在插件目录 `pugins/<名字>/`(`pugin.json` + `main.py`,可以再拆实现模块),
|
||||||
扫描加载,新增插件不需要改这里的任何代码;
|
由 `study_tool.pugins.load_plugins()` 扫描加载;新增或迁移插件都不用改这里的代码。
|
||||||
- `platforms/<名字>.py`:跟共享实现模块(`jspx.py` / `study.py`)关系紧密的平台,直接在
|
要是有多个插件共用的实现模块,才放回本目录。
|
||||||
`load_builtin()` 里 import。
|
|
||||||
|
|
||||||
路由 / 引擎不用改 —— 它们只认 `course["platform"]`。
|
路由 / 引擎不用改 —— 它们只认 `course["platform"]`。
|
||||||
"""
|
"""
|
||||||
@@ -14,7 +14,6 @@ from study_tool.platforms.base import Platform # noqa: F401
|
|||||||
|
|
||||||
|
|
||||||
def load_builtin():
|
def load_builtin():
|
||||||
"""导入内置平台与 `pugins/` 下的插件,触发注册。幂等,app 启动时调用一次。"""
|
"""加载 `pugins/` 下的全部插件(导入即注册)。幂等,app 启动时调用一次。"""
|
||||||
from study_tool.platforms import guanyixue # noqa: F401
|
|
||||||
from study_tool.pugins import load_plugins
|
from study_tool.pugins import load_plugins
|
||||||
load_plugins()
|
load_plugins()
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
"""莞易学插件:`main.py` 注册平台,`jspx.py` 旧版页面、`study.py` 新版 SPA、`detect.py` 代际识别。"""
|
||||||
@@ -15,7 +15,7 @@ from bs4 import BeautifulSoup
|
|||||||
|
|
||||||
from study_tool.config import *
|
from study_tool.config import *
|
||||||
from study_tool.platforms import registry
|
from study_tool.platforms import registry
|
||||||
from study_tool.platforms.detect import detect_generation, has_study_marker
|
from study_tool.pugins.guanyixue.detect import detect_generation, has_study_marker
|
||||||
from study_tool.runtime import RUNS, RUNS_LOCK, log, set_state
|
from study_tool.runtime import RUNS, RUNS_LOCK, log, set_state
|
||||||
|
|
||||||
# ------------------------------------------------------------------------ crypto
|
# ------------------------------------------------------------------------ crypto
|
||||||
@@ -301,7 +301,7 @@ def ensure_study_session(s, force=False):
|
|||||||
-> {"result":{"url":".../training","token":"<jwt>"}} # 这才是 Middle-Token
|
-> {"result":{"url":".../training","token":"<jwt>"}} # 这才是 Middle-Token
|
||||||
成功标准只有一个:cookie 里出现 study.dgjy.net 的 Middle-Token。
|
成功标准只有一个:cookie 里出现 study.dgjy.net 的 Middle-Token。
|
||||||
"""
|
"""
|
||||||
from study_tool.platforms.study import _study_token
|
from study_tool.pugins.guanyixue.study import _study_token
|
||||||
if force:
|
if force:
|
||||||
for c in list(s.cookies):
|
for c in list(s.cookies):
|
||||||
if c.name == "Middle-Token":
|
if c.name == "Middle-Token":
|
||||||
@@ -369,7 +369,7 @@ def _fetch_train_token(s):
|
|||||||
|
|
||||||
def _exchange_code(s, code):
|
def _exchange_code(s, code):
|
||||||
"""code -> Middle-Token。前端是 POST /mod/gjt/login/<code>,再取 gyx 培训 token。"""
|
"""code -> Middle-Token。前端是 POST /mod/gjt/login/<code>,再取 gyx 培训 token。"""
|
||||||
from study_tool.platforms.study import _study_token
|
from study_tool.pugins.guanyixue.study import _study_token
|
||||||
paths = ("/mod/gjt/login/%s", "/train/mod/gjt/login/%s")
|
paths = ("/mod/gjt/login/%s", "/train/mod/gjt/login/%s")
|
||||||
for path in paths:
|
for path in paths:
|
||||||
try:
|
try:
|
||||||
@@ -557,7 +557,7 @@ def discover(s, plan, project, name=""):
|
|||||||
|
|
||||||
def _discover_once(s, plan, project, name=""):
|
def _discover_once(s, plan, project, name=""):
|
||||||
# study.py 反向 import 本模块,模块级 import 会成环,用到时再取
|
# study.py 反向 import 本模块,模块级 import 会成环,用到时再取
|
||||||
from study_tool.platforms.study import (StudyClient, discover_study, extract_study_token,
|
from study_tool.pugins.guanyixue.study import (StudyClient, discover_study, extract_study_token,
|
||||||
extract_train_id, save_snapshot,
|
extract_train_id, save_snapshot,
|
||||||
study_resolve_train_id)
|
study_resolve_train_id)
|
||||||
url = "%s/train/trainee/courseStudyMain.action?planId=%s&projectId=%s&trainRole=0" % (JSPX, plan, project)
|
url = "%s/train/trainee/courseStudyMain.action?planId=%s&projectId=%s&trainRole=0" % (JSPX, plan, project)
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
`course["generation"]`(legacy / spa),由 `study` 分发到对应实现。
|
`course["generation"]`(legacy / spa),由 `study` 分发到对应实现。
|
||||||
新增其他平台时,照本文件写一个 `Platform` 子类并在 `entries` 声明登录 / 学习入口。
|
新增其他平台时,照本文件写一个 `Platform` 子类并在 `entries` 声明登录 / 学习入口。
|
||||||
"""
|
"""
|
||||||
from study_tool.platforms import jspx, registry, study
|
from study_tool.platforms import registry
|
||||||
|
from study_tool.pugins.guanyixue import jspx, study
|
||||||
from study_tool.platforms.base import Platform
|
from study_tool.platforms.base import Platform
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "guanyixue",
|
||||||
|
"title": "莞易学(东莞市教师培训平台)",
|
||||||
|
"name": "guanyixue"
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ from bs4 import BeautifulSoup
|
|||||||
|
|
||||||
from study_tool import store
|
from study_tool import store
|
||||||
from study_tool.config import *
|
from study_tool.config import *
|
||||||
from study_tool.platforms.jspx import *
|
from study_tool.pugins.guanyixue.jspx import *
|
||||||
from study_tool.runtime import RUNS, log, set_state
|
from study_tool.runtime import RUNS, log, set_state
|
||||||
|
|
||||||
# ------------------------------------------------------- 新版平台:页面识别/提取
|
# ------------------------------------------------------- 新版平台:页面识别/提取
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ from study_tool.config import *
|
|||||||
from study_tool.llm import *
|
from study_tool.llm import *
|
||||||
from study_tool.models import *
|
from study_tool.models import *
|
||||||
from study_tool.platforms import registry
|
from study_tool.platforms import registry
|
||||||
from study_tool.platforms.jspx import new_session, parse_ids
|
from study_tool.pugins.guanyixue.jspx import new_session, parse_ids
|
||||||
from study_tool.platforms.study import StudyClient
|
from study_tool.pugins.guanyixue.study import StudyClient
|
||||||
from study_tool.runtime import log
|
from study_tool.runtime import log
|
||||||
|
|
||||||
# ------------------------------------------------------------------ quiz
|
# ------------------------------------------------------------------ quiz
|
||||||
|
|||||||
Reference in New Issue
Block a user