44
55部署在 GitHub Actions 上,每天定时运行,** 零成本、免服务器、全自动** 。
66
7+ > 本项目仅供学习交流与个人复习使用,不可用于侵犯知识产权等非法目的,否则后果自负。
8+
79## 它能做什么?
810
9- 假设你选了「数据结构 」和「操作系统 」两门课。每天晚上 22:00,iCourse Subscriber 会自动:
11+ 假设你选了「摸鱼学导论 」和「躺平学原理 」两门课。每天晚上 22:00,iCourse Subscriber 会自动:
1012
11131 . 登录你的复旦 iCourse 账号(通过 WebVPN)
12142 . 检查这两门课是否有新的录播视频
13153 . 如果有:下载视频 → 语音识别 → AI 生成课程笔记
14164 . 将所有新课次的笔记汇总成** 一封邮件** 发送给你
1517
16- 邮件包含专业排版的 Markdown 渲染内容,覆盖课程重点、公式推导、代码示例等 。如果老师提到了作业、考试、签到等事项 ,会在笔记开头醒目标注。
18+ 邮件包含专业排版的 Markdown 渲染内容,覆盖课程重点、讲解内容、例子讲解等 。如果老师提到了作业、考试、签到、组队等重要课程事项 ,会在笔记开头醒目标注。
1719
1820## 快速部署(5 分钟)
1921
3032| ` STUID ` | 复旦学号 | ` 22307110000 ` |
3133| ` UISPSW ` | UIS 统一身份认证密码 | ` your_password ` |
3234| ` COURSE_IDS ` | 要监控的课程 ID,多个用英文逗号分隔 | ` 35472,30251 ` |
33- | ` DASHSCOPE_API_KEY ` | ModelScope 平台 API Key | ` sk -xxxxxxxx` |
35+ | ` DASHSCOPE_API_KEY ` | ModelScope 平台 API Key | ` ms -xxxxxxxx` |
3436| ` SMTP_EMAIL ` | 用于发送邮件的 QQ 邮箱 | ` 123456@qq.com ` |
3537| ` SMTP_PASSWORD ` | QQ 邮箱 SMTP ** 授权码** (不是登录密码) | ` abcdefghijklmnop ` |
36- | ` RECEIVER_EMAIL ` | 接收摘要邮件的邮箱(可以和发件邮箱相同) | ` you@example.com ` |
38+ | ` RECEIVER_EMAIL ` | 接收摘要邮件的邮箱(可以和发件邮箱相同) | ` you@m.fudan.edu.com ` |
39+
40+ 不知道这些secrets是什么意思?见如下讲解:
3741
3842### 第 3 步:获取课程 ID
3943
4044登录 [ iCourse 网页版] ( https://icourse.fudan.edu.cn ) ,进入你要监控的课程页面,URL 中的数字就是课程 ID:
4145
42- ![ 课程id如图所示] ( docs\ courseid.png )
46+ ![ 课程id如图所示] ( docs/ courseid.png )
4347
4448多门课用英文逗号隔开:` 35472,30251,40123 `
4549
49532 . 进入 [ API 密钥管理] ( https://modelscope.cn/my/myaccesstoken ) 页面
50543 . 创建一个 API Key,复制到 ` DASHSCOPE_API_KEY `
5155
56+ > 魔搭社区提供每天两千次的免费API调用额度,无需付费即可调用大模型api生成课程笔记。
57+
5258### 第 5 步:获取 QQ 邮箱 SMTP 授权码
5359
54- 1 . 登录 [ QQ 邮箱] ( https://mail.qq.com ) → 设置 → 账户
60+ 1 . 登录 [ QQ 邮箱] ( https://mail.qq.com ) → 设置 → 账户与安全 → 安全设置
55612 . 找到「POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV 服务」
56623 . 开启 SMTP 服务,按提示获取** 授权码** (16 位字母)
57634 . 将授权码填入 ` SMTP_PASSWORD `
5864
65+ > SMTP授权码的作用是以你邮箱的名义给你自己发送邮件通知。
66+
5967### 第 6 步:运行
6068
6169- ** 自动运行** :每天北京时间 22:00 自动执行(可在 ` check.yml ` 中修改 cron)
6270- ** 手动触发** :进入仓库 → Actions → iCourse Check → Run workflow
6371
6472首次运行会处理所有已有录播,后续只处理新增课次。
6573
66- ## 本地运行
74+ ## 本地运行(Linux环境)
6775
6876``` bash
6977# 克隆仓库
@@ -90,7 +98,7 @@ export $(cat .env | xargs)
9098python main.py
9199```
92100
93- ## 数据安全
101+ ## 数据安全与知识产权
94102
95103- ** 不保留视频** :视频下载后立即通过 ffmpeg 管道转录,转录完成立即删除
96104- ** 数据库加密存储** :SQLite 数据库在提交到仓库前使用 AES-256-CBC 加密,密钥由你的多个 Secret 拼接派生,即使仓库公开,他人也无法解密
@@ -123,51 +131,59 @@ python main.py
123131
124132### 整体流程
125133
126- ```
127- ┌─────────────────────────────────────────────────────────┐
128- │ GitHub Actions Cron │
129- │ (每天 22:00 UTC+8) │
130- ├─────────────────────────────────────────────────────────┤
131- │ 1. 解密 data/icourse.db.enc → data/icourse.db │
132- │ 2. python main.py │
133- │ 3. 加密 data/icourse.db → git commit + push │
134- └──────────────────────────┬──────────────────────────────┘
135- │
136- ┌────────────────▼────────────────┐
137- │ main.py: run() │
138- ├─────────────────────────────────┤
139- │ WebVPN 登录 + iCourse CAS 认证 │
140- │ (5 次重试) │
141- └────────────────┬────────────────┘
142- │
143- ┌─────────────────▼──────────────────┐
144- │ for each course_id in COURSE_IDS │
145- │ ┌──────────────────────────────┐ │
146- │ │ 检查 session → 获取课程详情 │ │
147- │ │ 对比 DB → 筛选未处理的课次 │ │
148- │ │ (playback_status=1 且未处理) │ │
149- │ └──────────────┬───────────────┘ │
150- │ for each new lecture │
151- │ ┌──────────────▼───────────────┐ │
152- │ │ 检查 session (防过期) │ │
153- │ │ get_video_url → 签名 CDN URL │ │
154- │ │ download_video (流式下载) │ │
155- │ │ transcribe_video (管道转录) │ │
156- │ │ 删除视频文件 │ │
157- │ │ summarize (LLM 摘要) │ │
158- │ │ 存入 DB, 标记 processed │ │
159- │ │ 收集到 email_items │ │
160- │ └──────────────────────────────┘ │
161- └─────────────────┬──────────────────┘
162- │
163- ┌────────────────▼────────────────┐
164- │ 批量发送邮件 (1 封包含所有摘要) │
165- │ 标记 emailed │
166- └─────────────────────────────────┘
134+ ``` mermaid
135+ flowchart TD
136+ %% GitHub Actions 层级
137+ subgraph Cron ["GitHub Actions Cron (每天 22:00 UTC+8)"]
138+ A1["1. 解密 data/icourse.db.enc → data/icourse.db"]
139+ A2["2. python main.py"]
140+ A3["3. 加密 data/icourse.db → git commit + push"]
141+ end
142+
143+ %% Python 脚本层级
144+ subgraph Main ["main.py: run()"]
145+ B1["WebVPN 登录 + iCourse CAS 认证<br/>(5 次重试)"]
146+
147+ %% 课程循环
148+ subgraph CourseLoop ["for each course_id in COURSE_IDS"]
149+ C1["检查 session → 获取课程详情<br/>对比 DB → 筛选未处理的课次<br/>(playback_status=1 且未处理)"]
150+
151+ %% 课次循环
152+ subgraph LectureLoop ["for each new lecture"]
153+ D1["检查 session (防过期)"]
154+ D2["get_video_url → 签名 CDN URL"]
155+ D3["download_video (流式下载)"]
156+ D4["transcribe_video (管道转录)"]
157+ D5["删除视频文件"]
158+ D6["summarize (LLM 摘要)"]
159+ D7["存入 DB, 标记 processed<br/>收集到 email_items"]
160+
161+ D1 --> D2 --> D3 --> D4 --> D5 --> D6 --> D7
162+ end
163+
164+ C1 --> D1
165+ end
166+
167+ E1["批量发送邮件 (1 封包含所有摘要)<br/>标记 emailed"]
168+
169+ B1 --> C1
170+ D7 --> E1
171+ end
172+
173+ %% 定义跨模块的执行流转连线
174+ A1 --> A2
175+ A2 -->|触发脚本执行| B1
176+ E1 -->|执行完毕返回| A3
177+
178+ %% 可选:给循环框加一点虚线样式以区分普通模块
179+ classDef loopBlock fill:#f0f8ff,stroke:#00509E,stroke-width:1.5px,stroke-dasharray: 5 5;
180+ class CourseLoop,LectureLoop loopBlock;
167181```
168182
169183### WebVPN 认证(` src/webvpn.py ` )
170184
185+ 我们逆向了复旦的WebVPN和UIS登录的完整流程,以便在线定时登录。以下是流程说明:
186+
171187复旦 WebVPN 使用 ** AES-128-CFB** 对目标 URL 的主机名进行加密,IV 固定为 ` wrdvpnisthebest! ` 。例如:
172188
173189```
0 commit comments