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:
study-tool
2026-10-31 16:18:45 +08:00
parent 8e8d6b83f1
commit 491fd08c1e
11 changed files with 74 additions and 38 deletions
+1 -1
View File
@@ -31,7 +31,7 @@
## 代码结构 / 平台插件
- 业务代码都在 `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/`、前端。
- 引擎、路由、前端都不允许直接 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/` 里的产物。