feat: 添加账号支持选择学习平台

账号新增 platform 字段,登录/刷新课程/发现课程按平台分发;同时把 JS 脚本收进 script/(目录规范调整)。
This commit is contained in:
study-tool
2026-10-30 01:13:47 +08:00
parent e8634a6317
commit 1a3347f7f9
29 changed files with 449 additions and 297 deletions
+21 -9
View File
@@ -10,7 +10,7 @@ src/study_tool/
__main__.py python -m study_tool 入口
app.py 组装:FastAPI、鉴权中间件、页面 / health、启动 main()
webapp.py FastAPI 实例(路由模块从这里注册,避免循环导入)
config.py 常量 / 环境变量 / 根目录定位(data、static、desenc.js)
config.py 常量 / 环境变量 / 根目录定位(data、static、script)
runtime.py 运行状态 RUNS + 统一日志 log()
store.py SQLite:账号 / 设置 / 日志 / 状态 / 缓存 / 快照
models.py HTTP 请求模型(Pydantic)
@@ -32,7 +32,8 @@ src/study_tool/
logs.py /api/log、/api/runs
web/ 前端源码(React 19 + TypeScript + Vite + Tailwind CSS v4)
static/ 前端构建产物(index.html + assets/ + favicon.svg,提交进仓库)
des*.js 服务端 DES 加密脚本(Node 调用)
script/ 服务端 JS 脚本:des.js、desenc.js(Node 调用)
script/reference/ 不参与运行的参考脚本:dgjy-toolkit.user.js、study-axios.mjs
```
## 分层
@@ -63,11 +64,20 @@ class Platform:
label: str # 日志 / 界面展示名,如「莞易学」
study: Callable # (key, s, d, **opts) -> None
entries: tuple[str, ...] # 登录入口 / 学习入口的 URL 片段
# 账号级能力:添加账号时选中的平台决定登录 / 刷新课程 / 发现课程走哪套实现
session: Callable # (cookies) -> requests.Session
dump_cookies: Callable # (session) -> [cookie]
login: Callable # (username, password) -> (session, user)
list_courses: Callable # (session) -> [course]
discover: Callable # (session, plan_id, project_id, name) -> 课程描述
renew_session: Callable # (session) -> bool,无密码续期
profile: Callable # (session) -> 显示名
```
`registry.detect(url, html)` 按 `entries` 命中平台;课程发现时把平台 id 写进
`course["platform"]`,把页面代际写进 `course["generation"]`(`legacy` / `spa`)。
引擎按平台分发,平台内部再按代际选择学习实现。
`registry.detect(url, html)` 按 `entries` 命中平台;「添加账号」时选择的平台写进
`accounts.platform`,之后登录 / 刷新课程 / 发现课程都用 `registry.get(account["platform"])`
取实现。课程发现时把平台 id 写进 `course["platform"]`,把页面代际写进
`course["generation"]`(`legacy` / `spa`);引擎按平台分发,平台内部再按代际选择学习实现。
`opts` 固定包含:`workers / cap / enable_quiz / enable_feedback / mode / parallel /
quiz_key / cookies / plan / project / name`。插件可以只取自己需要的。
@@ -100,16 +110,18 @@ quiz_key / cookies / plan / project / name`。插件可以只取自己需要的
PLATFORM = registry.register(Platform(
id="<平台 id>", label="展示名", study=_study,
entries=("<登录入口域名>", "<学习入口域名>"),
session=<new_session>, dump_cookies=<dump_cookies>, login=<login>,
list_courses=<list_courses>, discover=<discover>,
))
```
2. 在 `platforms/__init__.py` 的 `load_builtin()` 里加一行 `from study_tool.platforms import <名字>`。
3. 平台自己的登录 / 发现流程把 `course["platform"]` 写成该 id 后,引擎自动分发;
`registry.detect()` 用登录 / 学习入口识别平台,不需要改前端。
3. 平台注册后会自动出现在「添加账号」的平台下拉框;账号选了该平台,登录 / 刷新课程 /
发现课程 / 学习都走它的实现,不需要改路由或前端。
现阶段登录与课程发现仍由莞易学模块承担(SSO 只有一套);接入第二个平台时,
在账号登录 / 发现入口按 `Platform.entries` 命中结果选择对应实现即可。
现阶段登录与课程发现由莞易学模块承担(SSO 只有一套);`accounts.platform` 已经是平台分发的
依据,接入第二个平台时在 `platforms/<平台>.py` 里实现上面的入口即可。
## 前端