bb-sync 2.2.0__tar.gz → 2.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. {bb_sync-2.2.0 → bb_sync-2.3.0}/.gitignore +5 -0
  2. bb_sync-2.3.0/AGENTS.md +50 -0
  3. {bb_sync-2.2.0 → bb_sync-2.3.0}/CHANGELOG.md +34 -0
  4. {bb_sync-2.2.0 → bb_sync-2.3.0}/CONTRIBUTING.md +23 -4
  5. {bb_sync-2.2.0 → bb_sync-2.3.0}/PKG-INFO +73 -42
  6. bb_sync-2.3.0/README.md +253 -0
  7. bb_sync-2.3.0/docs/architecture.md +91 -0
  8. bb_sync-2.3.0/docs/images/run-plan.png +0 -0
  9. bb_sync-2.3.0/docs/images/run-summary.png +0 -0
  10. {bb_sync-2.2.0 → bb_sync-2.3.0}/docs/scripting.md +1 -1
  11. bb_sync-2.3.0/docs/testing.md +68 -0
  12. bb_sync-2.3.0/openspec/changes/archive/.gitkeep +0 -0
  13. bb_sync-2.3.0/openspec/changes/archive/2026-11-04-due-item-source-conflicts/.openspec.yaml +2 -0
  14. bb_sync-2.3.0/openspec/changes/archive/2026-11-04-due-item-source-conflicts/design.md +99 -0
  15. bb_sync-2.3.0/openspec/changes/archive/2026-11-04-due-item-source-conflicts/proposal.md +59 -0
  16. bb_sync-2.3.0/openspec/changes/archive/2026-11-04-due-item-source-conflicts/specs/announcement-due-extraction/spec.md +59 -0
  17. bb_sync-2.3.0/openspec/changes/archive/2026-11-04-due-item-source-conflicts/specs/due-item-reconciliation/spec.md +67 -0
  18. bb_sync-2.3.0/openspec/changes/archive/2026-11-04-due-item-source-conflicts/tasks.md +39 -0
  19. bb_sync-2.3.0/openspec/config.yaml +32 -0
  20. bb_sync-2.3.0/openspec/specs/.gitkeep +0 -0
  21. bb_sync-2.3.0/openspec/specs/announcement-due-extraction/spec.md +58 -0
  22. bb_sync-2.3.0/openspec/specs/due-item-reconciliation/spec.md +71 -0
  23. {bb_sync-2.2.0 → bb_sync-2.3.0}/pyproject.toml +1 -1
  24. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/blackboard/models.py +9 -2
  25. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/blackboard/scraper.py +45 -10
  26. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/commands/course.py +1 -1
  27. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/commands/due.py +3 -3
  28. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/commands/run.py +3 -3
  29. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/core/doctor.py +2 -1
  30. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/core/due.py +103 -11
  31. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/core/service.py +5 -1
  32. {bb_sync-2.2.0 → bb_sync-2.3.0}/tests/test_units.py +377 -1
  33. {bb_sync-2.2.0 → bb_sync-2.3.0}/uv.lock +1 -1
  34. bb_sync-2.2.0/AGENTS.md +0 -148
  35. bb_sync-2.2.0/README.md +0 -222
  36. {bb_sync-2.2.0 → bb_sync-2.3.0}/.github/workflows/ci.yml +0 -0
  37. {bb_sync-2.2.0 → bb_sync-2.3.0}/.github/workflows/release.yml +0 -0
  38. {bb_sync-2.2.0 → bb_sync-2.3.0}/.pre-commit-config.yaml +0 -0
  39. {bb_sync-2.2.0 → bb_sync-2.3.0}/LICENSE +0 -0
  40. {bb_sync-2.2.0 → bb_sync-2.3.0}/config.yaml +0 -0
  41. {bb_sync-2.2.0 → bb_sync-2.3.0}/docs/config.md +0 -0
  42. {bb_sync-2.2.0 → bb_sync-2.3.0}/scripts/debug_course.py +0 -0
  43. {bb_sync-2.2.0 → bb_sync-2.3.0}/scripts/debug_courses.py +0 -0
  44. {bb_sync-2.2.0 → bb_sync-2.3.0}/scripts/debug_login.py +0 -0
  45. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/__init__.py +0 -0
  46. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/__main__.py +0 -0
  47. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/blackboard/__init__.py +0 -0
  48. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/blackboard/downloader.py +0 -0
  49. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/blackboard/login.py +0 -0
  50. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/browser/__init__.py +0 -0
  51. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/browser/launcher.py +0 -0
  52. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/cli.py +0 -0
  53. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/commands/__init__.py +0 -0
  54. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/commands/auth.py +0 -0
  55. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/commands/browser.py +0 -0
  56. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/commands/config.py +0 -0
  57. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/commands/doctor.py +0 -0
  58. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/context.py +0 -0
  59. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/core/__init__.py +0 -0
  60. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/core/config.py +0 -0
  61. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/core/config_store.py +0 -0
  62. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/core/errors.py +0 -0
  63. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/core/help.py +0 -0
  64. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/core/output.py +0 -0
  65. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/core/update.py +0 -0
  66. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/creds.py +0 -0
  67. {bb_sync-2.2.0 → bb_sync-2.3.0}/src/bb_sync/paths.py +0 -0
  68. {bb_sync-2.2.0 → bb_sync-2.3.0}/tests/conftest.py +0 -0
  69. {bb_sync-2.2.0 → bb_sync-2.3.0}/tests/test_cli_e2e.py +0 -0
  70. {bb_sync-2.2.0 → bb_sync-2.3.0}/tests/test_update_e2e.py +0 -0
@@ -18,3 +18,8 @@ debug_*.txt
18
18
  # 个人工作区与课程资料(课程资料属版权内容,禁止公开)
19
19
  .workbuddy/
20
20
  courses/
21
+
22
+ # 本地 AI / 工作流工具目录(个人环境,不入库)。openspec/ 不在此列:
23
+ # 它保存项目的 specs 与 change 归档,属于该跟代码一起版本化的规划产物。
24
+ .claude/
25
+ .pi/
@@ -0,0 +1,50 @@
1
+ # AGENTS.md
2
+
3
+ 给 AI 编码代理的最小必要上下文。展开细节按需查阅:
4
+ [architecture.md](docs/architecture.md)(目录与实现约定)、[testing.md](docs/testing.md)(测试与门禁)、
5
+ [CONTRIBUTING.md](CONTRIBUTING.md)(开发流程、风格、发布)。
6
+
7
+ ## 项目速览
8
+
9
+ - Blackboard 课程资源同步 CLI:登录港中深 `bb.cuhk.edu.cn`(ADFS SSO),把课件 / 作业 / 指导
10
+ 增量下载到课程目录,公告存 `announcements.md`,全部待办汇总到 `due.md`。
11
+ - **只适配** `bb.cuhk.edu.cn` 及其 ADFS 登录流程;不要为其他站点引入通用化假设。
12
+ - 目标平台 Windows 10/11(PowerShell)与 macOS(Intel / Apple Silicon,zsh / bash);
13
+ Python ≥3.11,技术栈 Typer + Click、pydantic v2、PyYAML、rich、keyring、Playwright。
14
+ - 代码注释、docstring、提交信息、文档一律中文;命令与路径示例同时覆盖 PowerShell 与 zsh / bash。
15
+
16
+ ## 五条不能破的红线
17
+
18
+ 1. **输出分流**:结果走 stdout、诊断走 stderr,一律经 `core.output.Console`;禁止 `print`,
19
+ 不要打开 Rich markup(诊断里满是 `[new]`、`[作业]` 这类方括号)。`--json` 时 stdout 只有一个 JSON 文档。
20
+ 2. **错误语义化**:可预期错误抛 `BbSyncError` 子类(`core/errors.py`),退出码由自带的 `exit_code`
21
+ 决定;不要裸 `sys.exit(1)` 或临时整数。
22
+ 3. **冷启动**:`cli.py` / `context.py` / `commands/__init__.py` 顶层不得导入 playwright、pydantic、rich;
23
+ 命令模块靠 `LazyGroup` 延迟导入,`--version` / `--help` 必须快速返回。
24
+ 4. **配置**:CLI > `BB_SYNC_<KEY>` > config.yaml > 内置默认;`config set/unset` 必须走
25
+ `core/config_store.py` 的行级编辑,保留注释与未知键,不要整份 YAML 重写。
26
+ 5. **浏览器**:只驱动本机已装的 Chrome / Edge(分离进程 + CDP + 自有 profile),不引入 Node / npm
27
+ 或任何需联网下载的运行时;默认跑完即关,关闭只走 CDP `Browser.close`,绝不读写用户的日常 profile。
28
+
29
+ ## 常用命令
30
+
31
+ ```shell
32
+ uv sync # 安装依赖(含 dev 组)
33
+ uv run bb-sync --help # 从源码运行 CLI
34
+ uv run pytest # 单元 + CLI 端到端,默认全离线
35
+ uv run ruff check . # 静态检查;格式化检查用 ruff format --check .
36
+ uv run pyright # 类型检查
37
+ ```
38
+
39
+ 改动提交前 `pytest` / `ruff check` / `ruff format --check` / `pyright` 必须全绿;
40
+ 纯文档改动至少自查命令示例。测试与检查完全离线,只有真实 `run` / `doctor` 才需要浏览器和凭据。
41
+
42
+ ## 文档地图
43
+
44
+ | 想知道 | 看 |
45
+ | --- | --- |
46
+ | 目录结构、模块职责、五条红线的细节与理由 | [docs/architecture.md](docs/architecture.md) |
47
+ | 测试分层、`conftest` 隔离、CI、真实站点手工验证 | [docs/testing.md](docs/testing.md) |
48
+ | 代码风格、提交信息、版本与发布 | [CONTRIBUTING.md](CONTRIBUTING.md) |
49
+ | 配置项与 `--json` 输出结构 | [docs/config.md](docs/config.md)、[docs/scripting.md](docs/scripting.md) |
50
+ | 安装与用户侧用法 | [README.md](README.md) |
@@ -2,6 +2,40 @@
2
2
 
3
3
  本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
4
4
 
5
+ ## [2.3.0] — 2026-11-04
6
+
7
+ ### 修复
8
+
9
+ - **公告里没有编号的作业名也能认出**:此前作业名规则要求 `HW4` / `Assignment 2`
10
+ 这类带编号写法,CSC5010 的 `Homework on Probabilistic Reasoning`(截止
11
+ 2026-11-15)整条被静默丢弃。现在接受「作业词 + 可选编号 + on / about 主题」的
12
+ 写法,守卫改为「标题或截止行相邻行含作业词」;`Week 4 Materials Uploaded` 这类
13
+ 没有作业语境的日期仍然不收录。
14
+ - **To Do 与公告叫法不一致时不再静默丢弃**:Blackboard 把 HW4 的作业容器命名成
15
+ `Assignment 5`,与同一天公告的 `Homework assignment 4` 冲突,旧版按「To Do 优先」
16
+ 直接丢弃公告条目。现在保留 To Do 的日期与类型,把公告标题记为该条目的别名,
17
+ `due.md` 渲染成 `Assignment 5(公告称 Homework assignment 4)`,文件头部解释括号含义。
18
+ - **同一编号的两种写法不再重复成两条**:`HW4` 与 `Homework assignment 4` 的主题词
19
+ 集合没有交集,旧版判不成同一件事,同一天会列两条;现在补充「同为作业类说法且
20
+ 编号相同」的判定。
21
+ - **分歧提示补全到待办明细**:`bb-sync due` 与 `bb-sync run` 的汇总会打印
22
+ 「发现 N 处来源分歧」,`run` 的明细行与 `due.md` 共用同一套标题渲染,直接显示
23
+ `Assignment 5(公告称 Homework assignment 4)`,不必再回 `due.md` 对照。
24
+
25
+ ### 变更
26
+
27
+ - `due.md` 行格式:带来源分歧的条目会在标题后追加 `(公告称 …)`,文件头部相应多一行说明。
28
+ - `--json` 的 `items` 元素新增 `aliases` 字段(无分歧时为空数组)。
29
+
30
+ ## [2.2.1] — 2026-11-02
31
+
32
+ ### 修复
33
+
34
+ - **`doctor` 网络检查不再建议连接学校 VPN**:`bb.cuhk.edu.cn` 校外可以直接访问,
35
+ 原提示「校外使用需要先连接学校 VPN」会把网络问题误导向 VPN,连上后仍失败反而
36
+ 更难判断。现在改为提示检查本机网络,说明系统代理无法转发 HTTPS 时先关代理重试,
37
+ 并给出 `bb-sync doctor --skip-network` 作为跳过检查的方式;README 排障条目同步更新。
38
+
5
39
  ## [2.2.0] — 2026-10-31
6
40
 
7
41
  ### 修复
@@ -1,6 +1,7 @@
1
1
  # 参与开发
2
2
 
3
3
  本文面向修改 bb-sync 源码的开发者。普通安装与使用请先阅读 [README.md](README.md)。
4
+ 实现约定见 [docs/architecture.md](docs/architecture.md),测试细节见 [docs/testing.md](docs/testing.md)。
4
5
 
5
6
  ## 开发环境
6
7
 
@@ -41,24 +42,42 @@ uv run pyright
41
42
 
42
43
  - `tests/test_units.py`:纯逻辑单元测试,覆盖配置分层与行级编辑、文件名和分类推断、异常与退出码映射等。
43
44
  - `tests/test_cli_e2e.py`:把完整命令链跑在进程内的端到端测试,覆盖命令行契约、退出码、stdout/stderr 分流和配置读写。
45
+ - `tests/test_update_e2e.py`:自动更新提示的通道行为。
44
46
 
45
- 测试环境通过 `tests/conftest.py` 隔离 `BB_SYNC_HOME`、工作目录和系统钥匙串,不应访问真实网站、下载文件或读取真实凭据。
47
+ 测试环境通过 `tests/conftest.py` 隔离 `BB_SYNC_HOME`、工作目录、系统钥匙串和浏览器 profile 路径,
48
+ 不应访问真实网站、下载文件或读取真实凭据,也不应真的拉起浏览器进程。fixture 清单与测试相关坑见
49
+ [docs/testing.md](docs/testing.md)。
46
50
 
47
51
  ## CI
48
52
 
49
- `.github/workflows/ci.yml` 在 push 和 PR 时运行(Ubuntu 与 macOS):
53
+ `.github/workflows/ci.yml` 在 push 和 PR 时运行:
50
54
 
51
55
  - Ruff lint;
52
56
  - Ruff format check;
53
57
  - Pyright;
54
58
  - pytest;
55
- - 干净容器中的安装冒烟测试。
59
+
60
+ 以上四项跑在 Ubuntu、macOS 与 Windows 三平台矩阵上;另有干净容器里的安装冒烟测试(Ubuntu)。
56
61
 
57
62
  启动浏览器、登录 Blackboard 和真实下载不属于默认离线测试范围。修改相关逻辑时,请在本地补充可重复的手工验证步骤。
58
63
 
64
+ ## 代码风格
65
+
66
+ - 格式与静态检查统一由工具把关:ruff(line-length 100、目标 py311、`known-first-party = ["bb_sync"]`)
67
+ 与 ruff format;pyright 用 `standard` 模式且必须零报错。
68
+ - 注释 / docstring 用中文,解释职责与「为什么」;模块 docstring 说明该模块的关键约束。
69
+ - 全面类型标注,模块头统一 `from __future__ import annotations`。
70
+ - 面向用户的错误信息要带可操作的 hint(下一步敲什么命令)。
71
+
59
72
  ## 提交习惯
60
73
 
61
- - 提交信息使用 `feat|fix|docs|refactor|test|chore(范围): 摘要`;
74
+ - 提交信息使用中文,格式 `feat|fix|docs|refactor|test|chore(范围): 摘要`;
62
75
  - 一个提交只处理一件事;
63
76
  - 不提交密钥、`.env`、浏览器 profile、课程文件、构建产物或其他生成物;
64
77
  - 只暂存本次改动相关的文件。
78
+
79
+ ## 发布
80
+
81
+ - 版本号写在 `pyproject.toml`,发布前在本地跑完整四件套(见上文「常用检查」);
82
+ - 打 `v*` tag 触发 `.github/workflows/release.yml`:发布会校验 wheel 文件名与 tag 一致,
83
+ 并同步更新 `CHANGELOG.md`。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: bb-sync
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: 港中深(CUHK-Shenzhen)Blackboard 课件下载与课程资源自动同步:登录 ADFS SSO,增量下载课件/作业/指导、公告与待办
5
5
  Project-URL: Homepage, https://github.com/asdukw/cuhk-shenzhen-blackboard-sync
6
6
  Project-URL: Repository, https://github.com/asdukw/cuhk-shenzhen-blackboard-sync
@@ -53,7 +53,7 @@ Description-Content-Type: text/markdown
53
53
 
54
54
  **港中深(香港中文大学·深圳 / CUHK-Shenzhen / CUHKSZ)Blackboard 课件下载与课程资源自动同步 CLI**
55
55
 
56
- 登录 `bb.cuhk.edu.cn`,把课件、作业和指导增量下载到本地,把公告和全部课程的待办整理成 Markdown。重复运行时会跳过已经下载的文件。
56
+ 登录 `bb.cuhk.edu.cn`,把课件、作业和指导 / 实验(tutorial / lab)增量下载到本地,把公告和全部课程的待办整理成 Markdown。重复运行时会跳过已经下载的文件。
57
57
 
58
58
  *Blackboard course material sync CLI for CUHK-Shenzhen students.*
59
59
 
@@ -70,15 +70,24 @@ Description-Content-Type: text/markdown
70
70
 
71
71
  Blackboard 上的东西散在「课程内容」「作业」「公告」几个入口,一学期下来几十上百个文件,靠手动点、手动记截止日期很容易漏。bb-sync 把这些收进本地一个目录:
72
72
 
73
- - 课件、作业、指导按课程归好类,重跑只下新增的;
74
- - 每门课的公告存成一份 `announcements.md`;
75
- - 全部课程的待办汇总成一份 `due.md`,按「已逾期 → 今天 → 明天 → 未来 7 天 → 之后」排好序,公告里带日期的课堂测验、考试和作业截止时间也一并计入;每条待办都是可勾选的任务列表(`- [ ]`),做完勾上 `- [x]`,下次同步会保留完成状态。
73
+ - 课件、作业、指导按课程归好类。重跑只下新增的,结束时逐条列出本轮真正新下载的文件。
74
+ - 有公告的课程会生成一份 `announcements.md`。没有公告的课程不生成,`bb-sync due` 也不写这个文件。
75
+ - 全部课程的待办汇总成一份 `due.md`,按「已逾期 → 今天 → 明天 → 未来 7 天 → 之后 → 日期未知 → 已过期事件」排好序。公告里带日期的课堂测验、考试和作业截止时间也一并计入。每条待办都是可勾选的任务列表(`- [ ]`),做完勾上 `- [x]`,下次同步保留完成状态。
76
+ - To Do 名称与公告写法对不上时(例如教务把 HW4 的作业容器命名成 `Assignment 5`),条目会渲染成 `Assignment 5(公告称 Homework assignment 4)`,两个来源的名字都保留,不静默二选一。
76
77
 
77
- 它**不做**这些:不回传作业、不代签到、不抓成绩、不绕过任何权限——看到的就是你账号里本来能看到的。
78
+ 它不回传作业、不代签到、不抓成绩,也绕不过任何权限。看到的就是你账号里本来能看到的。
78
79
 
79
80
  ## 长什么样
80
81
 
81
- 下面是示例输出(课程名和文件名为虚构,链接已缩写为 `…`,实际每条都带回到对应 Blackboard 课程页的链接)。
82
+ `bb-sync run` 的真实输出分三段。先启动后台浏览器、登录、列出课程,再打印一份「同步计划」,写明每个课程代码会落到哪个本地目录:
83
+
84
+ ![bb-sync run 的同步计划:登录成功后列出 7 门课程到本地目录的映射](docs/images/run-plan.png)
85
+
86
+ 跑完是汇总,说明这轮新下载了什么、跳过了多少已存在的文件。最后是逐条待办明细,逾期的红色,测验和考试带类型标签:
87
+
88
+ ![bb-sync run 的汇总、新下载明细与待办明细](docs/images/run-summary.png)
89
+
90
+ 下面的文本示例可以直接复制。课程名和文件名是虚构的,链接缩写为 `…`,实际每条都指回对应的 Blackboard 课程页。
82
91
 
83
92
  `due.md`:
84
93
 
@@ -86,31 +95,34 @@ Blackboard 上的东西散在「课程内容」「作业」「公告」几个入
86
95
  # Blackboard 待办
87
96
 
88
97
  > 更新时间:2026-10-14 21:03(本地时间)
89
- > 已检查 5 门课程,发现 7 项待办;按优先级和截止日期排列。
90
- > 其中公告里的测验 1 项、考试 1 项已一并作为待办列出。
98
+ > 已检查 5 门课程,发现 8 项待办;按优先级和截止日期排列。
99
+ > 其中公告里的测验 1 项、考试 1 项、作业 1 项已一并作为待办列出。
91
100
  > 另有 1 项公告里的测验/考试日期已过,列在最后仅供回看。
101
+ > 完成一项就在前面打勾(`- [ ]` → `- [x]`),下次同步会保留完成状态。
102
+ > 括号里的「公告称 …」表示 To Do 名称与公告写法对不上,两个名字都来自 Blackboard。
92
103
 
93
104
  ## 已逾期(1)
94
105
 
95
- - **2026-10-12**(逾期 2 天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 作业 3 实验报告
106
+ - [ ] **2026-10-12**(逾期 2 天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 作业 3 实验报告
96
107
 
97
108
  ## 今天(1)
98
109
 
99
- - **2026-10-14**(今天) — [MAT1001](https://bb.cuhk.edu.cn/…) — 习题 5
110
+ - [ ] **2026-10-14**(今天) — [MAT1001](https://bb.cuhk.edu.cn/…) — 习题 5
100
111
 
101
112
  ## 明天(1)
102
113
 
103
- - **2026-10-15**(明天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 【测验】Quiz 2
114
+ - [ ] **2026-10-15**(明天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 【测验】Quiz 2
104
115
 
105
- ## 未来 7 天(3)
116
+ ## 未来 7 天(4)
106
117
 
107
- - **2026-10-17**(还有 3 天) — [ENG1001](https://bb.cuhk.edu.cn/…) — Essay 1 初稿
108
- - **2026-10-20**(还有 6 天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 作业 4
109
- - **2026-10-21**(还有 7 天) — [MAT1001](https://bb.cuhk.edu.cn/…) — 【考试】期中考试
118
+ - [x] **2026-10-17**(还有 3 天) — [ENG1001](https://bb.cuhk.edu.cn/…) — Essay 1 初稿
119
+ - [ ] **2026-10-18**(还有 4 天) — [DDA5002](https://bb.cuhk.edu.cn/…) — Assignment 5(公告称 Homework assignment 4)
120
+ - [ ] **2026-10-20**(还有 6 天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 【作业】HW4
121
+ - [ ] **2026-10-21**(还有 7 天) — [MAT1001](https://bb.cuhk.edu.cn/…) — 【考试】期中考试
110
122
 
111
123
  ## 已过期事件(1)
112
124
 
113
- - **2026-10-08**(已过 6 天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 【测验】Quiz 1
125
+ - [ ] **2026-10-08**(已过 6 天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 【测验】Quiz 1
114
126
  ````
115
127
 
116
128
  下载目录:
@@ -135,7 +147,7 @@ Blackboard 上的东西散在「课程内容」「作业」「公告」几个入
135
147
 
136
148
  ## 安装
137
149
 
138
- 需要 uv 和 Chrome 或 Edge。bb-sync 会自动探测常见安装位置,Windows 自带的 Edge 直接可用。
150
+ 需要 Git 和 Chrome 或 Edge。安装 bb-sync 有两个办法:uv 会自己准备兼容的 Python 3.11+ 并隔离安装,不需要预先装 Python;已经装了 Python 3.11+ 的话也可以直接用 pip。浏览器会探测常见安装位置,Windows 自带的 Edge 直接可用。
139
151
 
140
152
  ### Windows
141
153
 
@@ -146,9 +158,7 @@ winget install --id Git.Git -e
146
158
  powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
147
159
  ```
148
160
 
149
- (Git 只在「从 GitHub 安装」时需要,走 PyPI 安装可以跳过。)
150
-
151
- Windows 自带的 Edge 即可使用;也可以自行安装 Google Chrome。
161
+ 也可以自己装 Google Chrome。
152
162
 
153
163
  ### macOS
154
164
 
@@ -163,7 +173,7 @@ brew install --cask google-chrome
163
173
 
164
174
  ### 安装 bb-sync(Windows / macOS 相同)
165
175
 
166
- **重开终端**后执行:
176
+ 用 uv 安装,重开终端后执行:
167
177
 
168
178
  ```bash
169
179
  uv tool install bb-sync
@@ -176,7 +186,15 @@ bb-sync doctor
176
186
  uv tool install git+https://github.com/asdukw/cuhk-shenzhen-blackboard-sync
177
187
  ```
178
188
 
179
- `bb-sync doctor` 用于检查环境;刚安装时凭据显示“未配置”、浏览器后端显示“未运行”都是正常的。如果提示找不到 `bb-sync`,执行 `uv tool update-shell` 后重开终端。校外使用 Blackboard 时,可能需要先连接学校 VPN。
189
+ 已经装了 Python 3.11 或更新版本时,改用 pip 也行,这条路不需要 uv:
190
+
191
+ ```bash
192
+ pip install --user bb-sync
193
+ ```
194
+
195
+ macOS 上一般用 `pip3 install --user bb-sync`。pip 把命令装进 Python 自己的脚本目录;提示找不到 `bb-sync` 就用 `python -m bb_sync`,例如 `python -m bb_sync doctor`,或者改用 `pipx install bb-sync`。
196
+
197
+ `bb-sync doctor` 检查环境。刚安装时凭据显示「未配置」、浏览器后端显示「未运行」,都正常。uv 装的如果提示找不到 `bb-sync`,执行 `uv tool update-shell`,再重开终端。
180
198
 
181
199
  ## 首次使用
182
200
 
@@ -188,7 +206,7 @@ bb-sync auth login
188
206
 
189
207
  密码会保存在 Windows 凭据管理器或 macOS 钥匙串,不会写入配置文件。macOS 首次访问时可能弹出钥匙串授权提示,选择允许即可。
190
208
 
191
- 第一次同步请显示浏览器,便于完成登录、MFA 或验证码:
209
+ 第一次同步如果想看到登录过程(或手动完成验证码),可以用有头模式:
192
210
 
193
211
  ```bash
194
212
  bb-sync run --headed
@@ -200,9 +218,9 @@ bb-sync run --headed
200
218
  bb-sync run
201
219
  ```
202
220
 
203
- 浏览器默认在**后台无窗口**运行,**跑完自动关闭**,不会在你机器上留下进程。登录态存在 `~/.bb-sync/.browser-profile/` 下、跨次运行保留,所以不必每次登录。
221
+ 浏览器默认在后台运行,没有窗口,跑完自动关闭,不在你机器上留下进程。登录状态保存在 `~/.bb-sync/.browser-profile/` 下,跨次运行保留,所以不必每次登录。
204
222
 
205
- 需要把窗口留在屏幕上时(手动过 MFA、或想连续跑几条命令)加 `--keep-open`,之后再 `bb-sync browser stop` 关闭。
223
+ 想让窗口在命令结束后留在屏幕上(例如连续跑几条命令、观察页面),用 `--headed --keep-open`,之后用 `bb-sync browser stop` 关闭。
206
224
 
207
225
  ## 文件位置
208
226
 
@@ -215,9 +233,14 @@ bb-sync run
215
233
 
216
234
  - 课件 → `lectures/`
217
235
  - 作业 → `assignments/`
218
- - 指导 / 实验 → `tutorials/`
219
- - 公告 → `announcements.md`
220
- - 全部课程待办 → `due.md`(按优先级排列;公告里带日期的课堂测验、考试和作业截止时间也计入,考完的测验 / 考试归入最后的「已过期事件」并保留 7 天;每条待办带 `- [ ]` 复选框,勾选状态跨次同步保留;内容没变化时不重写,没有待办时显示 Congratulations)
236
+ - 指导 / 实验(tutorial / lab) → `tutorials/`
237
+ - 公告 → `announcements.md`(没有公告的课程不会生成)
238
+
239
+ 课程根目录还会生成 `due.md`:
240
+
241
+ - 按「已逾期 → 今天 → 明天 → 未来 7 天 → 之后 → 日期未知 → 已过期事件」排序。公告里带日期的课堂测验、考试和作业截止时间也计入。
242
+ - 每条待办带 `- [ ]` 复选框,勾选状态跨次同步保留。考完的测验和考试归入最后的「已过期事件」,保留 7 天。
243
+ - 「更新时间」只在待办内容变化时刷新。内容没变就不重写;没有待办时显示 Congratulations。
221
244
 
222
245
  要修改下载目录:
223
246
 
@@ -232,41 +255,49 @@ Windows 也可以使用 `bb-sync config set root "D:/University/courses"`。更
232
255
  | 命令 | 作用 |
233
256
  | --- | --- |
234
257
  | `bb-sync run` | 增量同步全部课程并更新 `due.md` |
235
- | `bb-sync run --headed` | 显示浏览器,适合首次登录或 MFA |
236
- | `bb-sync run --course CSC5010` | 只同步指定课程,可重复使用 |
258
+ | `bb-sync run --headed` | 显示浏览器,适合首次登录或观察登录过程 |
259
+ | `bb-sync run --course CSC5010` | 只同步指定课程,可重复使用(`due.md` 也只保留这些课程) |
237
260
  | `bb-sync run --dry-run` | 预览下载和待办,不写文件 |
238
- | `bb-sync run --keep-open` | 跑完保留后台浏览器(手动过 MFA / 连着跑多条命令) |
239
- | `bb-sync due` | 扫描全部课程主页的 Due / To Do 与公告测验、考试,生成 `due.md` |
240
- | `bb-sync due --course CSC5010` | 只整理指定课程的待办 |
261
+ | `bb-sync run --root <目录>` | 本次同步到指定目录(临时覆盖配置里的 `root`) |
262
+ | `bb-sync run --keep-open` | 跑完保留浏览器(配合 `--headed` 才能看到窗口;连着跑多条命令) |
263
+ | `bb-sync due` | 扫描全部课程的 Due / To Do 与公告里的测验、考试和作业 deadline,生成 `due.md` |
264
+ | `bb-sync due --course CSC5010` | 只整理指定课程的待办(`due.md` 也只保留这些课程) |
265
+ | `bb-sync due --root <目录>` | 本次把 `due.md` 写到指定目录(临时覆盖配置里的 `root`) |
241
266
  | `bb-sync course list` | 列出账号下的课程 |
242
267
  | `bb-sync auth login` / `logout` / `status` | 录入、删除、查看已保存的凭据 |
243
268
  | `bb-sync config show` | 显示配置文件内容 |
244
269
  | `bb-sync config set <键> <值>` | 修改配置;另有 `get` / `unset` / `edit` / `path` / `init` |
245
270
  | `bb-sync browser status` | 查看后台浏览器是否在运行(`--keep-open` 留下的实例) |
246
271
  | `bb-sync browser stop` | 关闭后台浏览器(登录态保留) |
247
- | `bb-sync doctor` | 检查环境是否就绪 |
272
+ | `bb-sync doctor` | 检查环境是否就绪(`--skip-network` 跳过网络检查) |
248
273
  | `bb-sync --help` | 查看完整帮助 |
249
274
 
275
+ `--headed` / `--keep-open` 对 `bb-sync due` 同样适用。用 `--course` 时,`due.md` 会被整份重写为所选课程的待办,其他课程的条目不会保留。
276
+
250
277
  ## 遇到问题
251
278
 
252
279
  - **`bb-sync` 找不到**:重开终端,或执行 `uv tool update-shell`。
280
+ - **连不上 Blackboard**:校外也能直接访问,不需要学校 VPN;先运行 `bb-sync doctor` 看网络那一项,多数是本机代理无法转发 HTTPS 导致的,关掉代理再试一次。
253
281
  - **环境检查不通过**:按 `bb-sync doctor` 的提示安装或配置缺失项。
254
- - **想留住浏览器窗口**:默认跑完会自动关;加 `--keep-open` 才会保留,之后用 `bb-sync browser status` 看状态、`bb-sync browser stop` 关闭(不影响登录态)。
255
- - **登录失败或需要 MFA**:运行 `bb-sync auth status` 查看凭据,再用 `bb-sync run --headed` 重试。
282
+ - **想留住浏览器窗口**:默认跑完会自动关;用 `--headed --keep-open` 才会保留可见窗口,之后用 `bb-sync browser status` 看状态、`bb-sync browser stop` 关闭(不影响登录态)。
283
+ - **登录失败**:运行 `bb-sync auth status` 查看凭据,再用 `bb-sync run --headed` 重试。
256
284
  - **更换密码**:重新运行 `bb-sync auth login`。
285
+ - **换账号 / 彻底退出登录**:`bb-sync auth logout` 只删除钥匙串里的凭据,浏览器 profile 里的登录态仍然有效;先 `bb-sync browser stop`,再删除 `~/.bb-sync/.browser-profile/`。要换账号,重新运行 `bb-sync auth login` 录入新账号。
257
286
 
258
287
  更多问题欢迎[开 Issue](https://github.com/asdukw/cuhk-shenzhen-blackboard-sync/issues)。
259
288
 
260
289
  ## 文档
261
290
 
262
- - [docs/config.md](docs/config.md) —— 配置文件、目录映射与全部配置项
263
- - [docs/scripting.md](docs/scripting.md) —— `--json` 输出结构与退出码,方便接脚本
264
- - [CONTRIBUTING.md](CONTRIBUTING.md) —— 开发流程与质量门禁
265
- - [CHANGELOG.md](CHANGELOG.md) —— 版本变更记录
291
+ - [docs/config.md](docs/config.md):配置文件、目录映射与全部配置项
292
+ - [docs/scripting.md](docs/scripting.md):`--json` 输出结构与退出码,方便接脚本
293
+ - [CONTRIBUTING.md](CONTRIBUTING.md):开发流程与质量门禁
294
+ - [CHANGELOG.md](CHANGELOG.md):版本变更记录
266
295
 
267
296
  ## 免责声明
268
297
 
269
- 本工具只读取你自己账号里本来就能看到的内容,登录凭据保存在本机系统钥匙串中,不会上传到任何第三方。命令成功后会请求一次 GitHub Releases API 检查新版本,只发送 `bb-sync/<版本号>` 作为 User-Agent,不携带任何个人信息;设置环境变量 `BB_SYNC_NO_UPDATE_CHECK=1` 可关闭该检查。课程资料版权归香港中文大学(深圳)及各任课教师所有,**仅供个人学习使用,请勿二次分发**。使用本工具产生的一切后果由使用者自行承担。
298
+ 本工具只读取你自己账号里本来就能看到的内容,登录凭据保存在本机系统钥匙串中,不会上传到任何第三方。命令成功后会检查新版本,结果缓存 24 小时,每天最多请求一次 GitHub Releases API。请求只发送 `bb-sync/<版本号>` 作为 User-Agent,不携带任何个人信息。设置环境变量 `BB_SYNC_NO_UPDATE_CHECK=1` 可关闭该检查。
299
+
300
+ 课程资料版权归香港中文大学(深圳)及各任课教师所有,**仅供个人学习使用,请勿二次分发**。使用本工具产生的一切后果由使用者自行承担。
270
301
 
271
302
  ## License
272
303
 
@@ -0,0 +1,253 @@
1
+ # bb-sync
2
+
3
+ **港中深(香港中文大学·深圳 / CUHK-Shenzhen / CUHKSZ)Blackboard 课件下载与课程资源自动同步 CLI**
4
+
5
+ 登录 `bb.cuhk.edu.cn`,把课件、作业和指导 / 实验(tutorial / lab)增量下载到本地,把公告和全部课程的待办整理成 Markdown。重复运行时会跳过已经下载的文件。
6
+
7
+ *Blackboard course material sync CLI for CUHK-Shenzhen students.*
8
+
9
+ [![CI](https://github.com/asdukw/cuhk-shenzhen-blackboard-sync/actions/workflows/ci.yml/badge.svg)](https://github.com/asdukw/cuhk-shenzhen-blackboard-sync/actions/workflows/ci.yml)
10
+ [![Release](https://img.shields.io/github/v/release/asdukw/cuhk-shenzhen-blackboard-sync)](https://github.com/asdukw/cuhk-shenzhen-blackboard-sync/releases)
11
+ [![Python](https://img.shields.io/badge/python-3.11%2B-blue)](pyproject.toml)
12
+ [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
13
+ [![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS-lightgrey)](#安装)
14
+
15
+ > **适用边界**:只适配香港中文大学(深圳)的 `bb.cuhk.edu.cn` 和它的 ADFS SSO 登录流程。
16
+ > 其他学校、其他 Blackboard 站点请勿安装。支持 Windows 10/11(PowerShell)与 macOS(Intel / Apple Silicon,zsh / bash)。
17
+
18
+ ## 它解决什么问题
19
+
20
+ Blackboard 上的东西散在「课程内容」「作业」「公告」几个入口,一学期下来几十上百个文件,靠手动点、手动记截止日期很容易漏。bb-sync 把这些收进本地一个目录:
21
+
22
+ - 课件、作业、指导按课程归好类。重跑只下新增的,结束时逐条列出本轮真正新下载的文件。
23
+ - 有公告的课程会生成一份 `announcements.md`。没有公告的课程不生成,`bb-sync due` 也不写这个文件。
24
+ - 全部课程的待办汇总成一份 `due.md`,按「已逾期 → 今天 → 明天 → 未来 7 天 → 之后 → 日期未知 → 已过期事件」排好序。公告里带日期的课堂测验、考试和作业截止时间也一并计入。每条待办都是可勾选的任务列表(`- [ ]`),做完勾上 `- [x]`,下次同步保留完成状态。
25
+ - To Do 名称与公告写法对不上时(例如教务把 HW4 的作业容器命名成 `Assignment 5`),条目会渲染成 `Assignment 5(公告称 Homework assignment 4)`,两个来源的名字都保留,不静默二选一。
26
+
27
+ 它不回传作业、不代签到、不抓成绩,也绕不过任何权限。看到的就是你账号里本来能看到的。
28
+
29
+ ## 长什么样
30
+
31
+ `bb-sync run` 的真实输出分三段。先启动后台浏览器、登录、列出课程,再打印一份「同步计划」,写明每个课程代码会落到哪个本地目录:
32
+
33
+ ![bb-sync run 的同步计划:登录成功后列出 7 门课程到本地目录的映射](docs/images/run-plan.png)
34
+
35
+ 跑完是汇总,说明这轮新下载了什么、跳过了多少已存在的文件。最后是逐条待办明细,逾期的红色,测验和考试带类型标签:
36
+
37
+ ![bb-sync run 的汇总、新下载明细与待办明细](docs/images/run-summary.png)
38
+
39
+ 下面的文本示例可以直接复制。课程名和文件名是虚构的,链接缩写为 `…`,实际每条都指回对应的 Blackboard 课程页。
40
+
41
+ `due.md`:
42
+
43
+ ````markdown
44
+ # Blackboard 待办
45
+
46
+ > 更新时间:2026-10-14 21:03(本地时间)
47
+ > 已检查 5 门课程,发现 8 项待办;按优先级和截止日期排列。
48
+ > 其中公告里的测验 1 项、考试 1 项、作业 1 项已一并作为待办列出。
49
+ > 另有 1 项公告里的测验/考试日期已过,列在最后仅供回看。
50
+ > 完成一项就在前面打勾(`- [ ]` → `- [x]`),下次同步会保留完成状态。
51
+ > 括号里的「公告称 …」表示 To Do 名称与公告写法对不上,两个名字都来自 Blackboard。
52
+
53
+ ## 已逾期(1)
54
+
55
+ - [ ] **2026-10-12**(逾期 2 天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 作业 3 实验报告
56
+
57
+ ## 今天(1)
58
+
59
+ - [ ] **2026-10-14**(今天) — [MAT1001](https://bb.cuhk.edu.cn/…) — 习题 5
60
+
61
+ ## 明天(1)
62
+
63
+ - [ ] **2026-10-15**(明天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 【测验】Quiz 2
64
+
65
+ ## 未来 7 天(4)
66
+
67
+ - [x] **2026-10-17**(还有 3 天) — [ENG1001](https://bb.cuhk.edu.cn/…) — Essay 1 初稿
68
+ - [ ] **2026-10-18**(还有 4 天) — [DDA5002](https://bb.cuhk.edu.cn/…) — Assignment 5(公告称 Homework assignment 4)
69
+ - [ ] **2026-10-20**(还有 6 天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 【作业】HW4
70
+ - [ ] **2026-10-21**(还有 7 天) — [MAT1001](https://bb.cuhk.edu.cn/…) — 【考试】期中考试
71
+
72
+ ## 已过期事件(1)
73
+
74
+ - [ ] **2026-10-08**(已过 6 天) — [CSC5010](https://bb.cuhk.edu.cn/…) — 【测验】Quiz 1
75
+ ````
76
+
77
+ 下载目录:
78
+
79
+ ```text
80
+ ~/courses/
81
+ ├── CSC5010_人工智能/
82
+ │ ├── lectures/
83
+ │ │ ├── 01 绪论.pdf
84
+ │ │ └── 02 搜索算法.pdf
85
+ │ ├── assignments/
86
+ │ │ └── hw1/
87
+ │ │ ├── hw1.pdf
88
+ │ │ └── starter.zip
89
+ │ ├── tutorials/
90
+ │ │ └── tutorial01.ipynb
91
+ │ └── announcements.md
92
+ ├── MAT1001_微积分/
93
+ │ └── ...
94
+ └── due.md
95
+ ```
96
+
97
+ ## 安装
98
+
99
+ 需要 Git 和 Chrome 或 Edge。安装 bb-sync 有两个办法:uv 会自己准备兼容的 Python 3.11+ 并隔离安装,不需要预先装 Python;已经装了 Python 3.11+ 的话也可以直接用 pip。浏览器会探测常见安装位置,Windows 自带的 Edge 直接可用。
100
+
101
+ ### Windows
102
+
103
+ 在 PowerShell 中执行:
104
+
105
+ ```powershell
106
+ winget install --id Git.Git -e
107
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
108
+ ```
109
+
110
+ 也可以自己装 Google Chrome。
111
+
112
+ ### macOS
113
+
114
+ 推荐先安装 [Homebrew](https://brew.sh/),再执行:
115
+
116
+ ```bash
117
+ brew install git uv
118
+ brew install --cask google-chrome
119
+ ```
120
+
121
+ 如果已经安装 Chrome 或 Edge,可跳过最后一条。Edge 的 cask 名称为 `microsoft-edge`。
122
+
123
+ ### 安装 bb-sync(Windows / macOS 相同)
124
+
125
+ 用 uv 安装,重开终端后执行:
126
+
127
+ ```bash
128
+ uv tool install bb-sync
129
+ bb-sync doctor
130
+ ```
131
+
132
+ 也可以直接从 GitHub 安装(跟随 `main` 上的最新代码):
133
+
134
+ ```bash
135
+ uv tool install git+https://github.com/asdukw/cuhk-shenzhen-blackboard-sync
136
+ ```
137
+
138
+ 已经装了 Python 3.11 或更新版本时,改用 pip 也行,这条路不需要 uv:
139
+
140
+ ```bash
141
+ pip install --user bb-sync
142
+ ```
143
+
144
+ macOS 上一般用 `pip3 install --user bb-sync`。pip 把命令装进 Python 自己的脚本目录;提示找不到 `bb-sync` 就用 `python -m bb_sync`,例如 `python -m bb_sync doctor`,或者改用 `pipx install bb-sync`。
145
+
146
+ `bb-sync doctor` 检查环境。刚安装时凭据显示「未配置」、浏览器后端显示「未运行」,都正常。uv 装的如果提示找不到 `bb-sync`,执行 `uv tool update-shell`,再重开终端。
147
+
148
+ ## 首次使用
149
+
150
+ 保存学号和密码:
151
+
152
+ ```bash
153
+ bb-sync auth login
154
+ ```
155
+
156
+ 密码会保存在 Windows 凭据管理器或 macOS 钥匙串,不会写入配置文件。macOS 首次访问时可能弹出钥匙串授权提示,选择允许即可。
157
+
158
+ 第一次同步如果想看到登录过程(或手动完成验证码),可以用有头模式:
159
+
160
+ ```bash
161
+ bb-sync run --headed
162
+ ```
163
+
164
+ 这条命令会用你机器上的 Chrome(没有则用 Edge)打开一个窗口,登录一次即可。之后同步直接运行:
165
+
166
+ ```bash
167
+ bb-sync run
168
+ ```
169
+
170
+ 浏览器默认在后台运行,没有窗口,跑完自动关闭,不在你机器上留下进程。登录状态保存在 `~/.bb-sync/.browser-profile/` 下,跨次运行保留,所以不必每次登录。
171
+
172
+ 想让窗口在命令结束后留在屏幕上(例如连续跑几条命令、观察页面),用 `--headed --keep-open`,之后用 `bb-sync browser stop` 关闭。
173
+
174
+ ## 文件位置
175
+
176
+ 默认下载到用户主目录下的 `courses`:
177
+
178
+ - Windows:`C:\Users\<你>\courses`
179
+ - macOS:`/Users/<你>/courses`
180
+
181
+ 每门课一个文件夹:
182
+
183
+ - 课件 → `lectures/`
184
+ - 作业 → `assignments/`
185
+ - 指导 / 实验(tutorial / lab) → `tutorials/`
186
+ - 公告 → `announcements.md`(没有公告的课程不会生成)
187
+
188
+ 课程根目录还会生成 `due.md`:
189
+
190
+ - 按「已逾期 → 今天 → 明天 → 未来 7 天 → 之后 → 日期未知 → 已过期事件」排序。公告里带日期的课堂测验、考试和作业截止时间也计入。
191
+ - 每条待办带 `- [ ]` 复选框,勾选状态跨次同步保留。考完的测验和考试归入最后的「已过期事件」,保留 7 天。
192
+ - 「更新时间」只在待办内容变化时刷新。内容没变就不重写;没有待办时显示 Congratulations。
193
+
194
+ 要修改下载目录:
195
+
196
+ ```bash
197
+ bb-sync config set root "~/University/courses"
198
+ ```
199
+
200
+ Windows 也可以使用 `bb-sync config set root "D:/University/courses"`。更完整的配置说明见 [docs/config.md](docs/config.md)。
201
+
202
+ ## 常用命令
203
+
204
+ | 命令 | 作用 |
205
+ | --- | --- |
206
+ | `bb-sync run` | 增量同步全部课程并更新 `due.md` |
207
+ | `bb-sync run --headed` | 显示浏览器,适合首次登录或观察登录过程 |
208
+ | `bb-sync run --course CSC5010` | 只同步指定课程,可重复使用(`due.md` 也只保留这些课程) |
209
+ | `bb-sync run --dry-run` | 预览下载和待办,不写文件 |
210
+ | `bb-sync run --root <目录>` | 本次同步到指定目录(临时覆盖配置里的 `root`) |
211
+ | `bb-sync run --keep-open` | 跑完保留浏览器(配合 `--headed` 才能看到窗口;连着跑多条命令) |
212
+ | `bb-sync due` | 扫描全部课程的 Due / To Do 与公告里的测验、考试和作业 deadline,生成 `due.md` |
213
+ | `bb-sync due --course CSC5010` | 只整理指定课程的待办(`due.md` 也只保留这些课程) |
214
+ | `bb-sync due --root <目录>` | 本次把 `due.md` 写到指定目录(临时覆盖配置里的 `root`) |
215
+ | `bb-sync course list` | 列出账号下的课程 |
216
+ | `bb-sync auth login` / `logout` / `status` | 录入、删除、查看已保存的凭据 |
217
+ | `bb-sync config show` | 显示配置文件内容 |
218
+ | `bb-sync config set <键> <值>` | 修改配置;另有 `get` / `unset` / `edit` / `path` / `init` |
219
+ | `bb-sync browser status` | 查看后台浏览器是否在运行(`--keep-open` 留下的实例) |
220
+ | `bb-sync browser stop` | 关闭后台浏览器(登录态保留) |
221
+ | `bb-sync doctor` | 检查环境是否就绪(`--skip-network` 跳过网络检查) |
222
+ | `bb-sync --help` | 查看完整帮助 |
223
+
224
+ `--headed` / `--keep-open` 对 `bb-sync due` 同样适用。用 `--course` 时,`due.md` 会被整份重写为所选课程的待办,其他课程的条目不会保留。
225
+
226
+ ## 遇到问题
227
+
228
+ - **`bb-sync` 找不到**:重开终端,或执行 `uv tool update-shell`。
229
+ - **连不上 Blackboard**:校外也能直接访问,不需要学校 VPN;先运行 `bb-sync doctor` 看网络那一项,多数是本机代理无法转发 HTTPS 导致的,关掉代理再试一次。
230
+ - **环境检查不通过**:按 `bb-sync doctor` 的提示安装或配置缺失项。
231
+ - **想留住浏览器窗口**:默认跑完会自动关;用 `--headed --keep-open` 才会保留可见窗口,之后用 `bb-sync browser status` 看状态、`bb-sync browser stop` 关闭(不影响登录态)。
232
+ - **登录失败**:运行 `bb-sync auth status` 查看凭据,再用 `bb-sync run --headed` 重试。
233
+ - **更换密码**:重新运行 `bb-sync auth login`。
234
+ - **换账号 / 彻底退出登录**:`bb-sync auth logout` 只删除钥匙串里的凭据,浏览器 profile 里的登录态仍然有效;先 `bb-sync browser stop`,再删除 `~/.bb-sync/.browser-profile/`。要换账号,重新运行 `bb-sync auth login` 录入新账号。
235
+
236
+ 更多问题欢迎[开 Issue](https://github.com/asdukw/cuhk-shenzhen-blackboard-sync/issues)。
237
+
238
+ ## 文档
239
+
240
+ - [docs/config.md](docs/config.md):配置文件、目录映射与全部配置项
241
+ - [docs/scripting.md](docs/scripting.md):`--json` 输出结构与退出码,方便接脚本
242
+ - [CONTRIBUTING.md](CONTRIBUTING.md):开发流程与质量门禁
243
+ - [CHANGELOG.md](CHANGELOG.md):版本变更记录
244
+
245
+ ## 免责声明
246
+
247
+ 本工具只读取你自己账号里本来就能看到的内容,登录凭据保存在本机系统钥匙串中,不会上传到任何第三方。命令成功后会检查新版本,结果缓存 24 小时,每天最多请求一次 GitHub Releases API。请求只发送 `bb-sync/<版本号>` 作为 User-Agent,不携带任何个人信息。设置环境变量 `BB_SYNC_NO_UPDATE_CHECK=1` 可关闭该检查。
248
+
249
+ 课程资料版权归香港中文大学(深圳)及各任课教师所有,**仅供个人学习使用,请勿二次分发**。使用本工具产生的一切后果由使用者自行承担。
250
+
251
+ ## License
252
+
253
+ [MIT](LICENSE)