Aspirin0000

SJTU Canvas Assistant

Community Aspirin0000
Updated

Local Python CLI and MCP server for SJTU Canvas course files, submissions, videos, subtitles, and PPT assets

SJTU Canvas Assistant

一个从零搭建的本地 Python CLI 框架,用 Canvas Access Token 读取上海交通大学 Canvas 数据,下载课程文件,并生成可供后续 Codex/MCP 使用的本地索引。

默认 Canvas 主站:

https://oc.sjtu.edu.cn

第一版不模拟 jAccount 登录,不保存密码,不自动提交作业。课程、文件、作业等基础数据走 Canvas API;视频模块通过 Canvas Access Token 发起 sessionless LTI,再只读调用 SJTU 视频 API。

参考、致谢与许可证

本项目阅读并借鉴了学长项目 SJTU Canvas Helper 的接口方向。该参考项目使用 MIT License,版权声明为 Copyright (c) 2025 Zihong Lin。本项目同样以 MIT License 开源,并保留对参考项目的明确链接和致谢。

  • Canvas 基础数据走 /api/v1/... 和 Bearer token。
  • 课程列表包含 teachersterm
  • 文件、文件夹、模块、作业分别通过 Canvas API 拉取,并处理分页。
  • SJTU 视频/字幕/PPT 回放通过 Canvas 外部工具 8329 接入。当前实现优先使用 Canvas sessionless_launch API 发起 LTI,不需要模拟 jAccount 表单登录。
  • MCP Server 直接复用本项目的 CanvasClientCourseSyncerSJTUVideoClient 和索引模型,而不是重新写一套访问逻辑。

本项目不会照搬 Tauri 桌面 App,只提供可扩展的本地 CLI、Python 模块和 MCP stdio server。如果未来直接复制或改写参考项目中的实质代码,应继续保留其原 MIT 许可证声明。

安装

建议使用虚拟环境:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
python -m pip install -e ".[dev]"

安装后会得到两个等价命令:

sjtu-canvas --help
sjtu-canvas-assistant --help

也可以不安装脚本,直接运行:

python -m sjtu_canvas_assistant.cli --help

创建 Canvas Access Token

在 SJTU Canvas 页面中创建个人访问令牌:

  1. 打开 https://oc.sjtu.edu.cn
  2. 登录后进入左侧 Account / 账户
  3. 打开 Settings / 设置
  4. 找到 Approved Integrations / 已批准的集成
  5. 点击 New Access Token / 新建访问令牌
  6. 填写用途,例如 sjtu-canvas-assistant-local,按需设置过期时间。
  7. 复制生成的 token。Canvas 通常只显示一次,请妥善保存。

不要把 token 写进代码或提交到 git。

配置

复制示例配置:

cp .env.example .env

编辑 .env

CANVAS_TOKEN=你的 Canvas Access Token
CANVAS_BASE_URL=https://oc.sjtu.edu.cn
CANVAS_DATA_DIR=data

# 可选调试项;通常留空,由 video 命令自动通过 Canvas LTI 换取。
SJTU_VIDEO_TOKEN=
SJTU_VIDEO_COURSE_ID=

.env 已被 .gitignore 忽略。

也可以临时用环境变量:

export CANVAS_TOKEN="你的 Canvas Access Token"

常用命令

验证 token 并显示当前用户:

sjtu-canvas whoami

列出当前账号可访问课程:

sjtu-canvas courses
sjtu-canvas courses --active-only

输出 JSON:

sjtu-canvas courses --json

列出某门课的全部核心信息:

sjtu-canvas course 12345

分别列出文件、文件夹、模块、作业:

sjtu-canvas files 12345
sjtu-canvas folders 12345
sjtu-canvas modules 12345
sjtu-canvas assignments 12345

列出和查看自己已经提交过的作业:

sjtu-canvas submissions 12345
sjtu-canvas submissions 12345 --all
sjtu-canvas submission 12345 ASSIGNMENT_ID

下载自己提交过的作业附件:

sjtu-canvas download-submissions 12345
sjtu-canvas download-submissions 12345 --assignment-id ASSIGNMENT_ID
sjtu-canvas download-submissions 12345 --latest-only

默认会保留 Canvas submission history 中各次提交的附件,路径形如:

data/课程名 [课程ID]/submissions/作业名 [作业ID]/attempt-1/文件名

这几个命令只读取和下载你自己的提交记录,不会提交、修改或评论作业。JSON/MCP 输出会隐藏附件下载 URL。

下载前预检文件数量、总大小和本地路径:

sjtu-canvas plan 12345
sjtu-canvas plan 12345 --output data --json

按课程下载文件并生成索引:

sjtu-canvas download 12345

指定输出目录:

sjtu-canvas download 12345 --output data

只生成索引,不下载缺失文件:

sjtu-canvas index 12345

查看视频/字幕模块状态:

sjtu-canvas video-status 12345
sjtu-canvas video status

列出某门课的视频:

sjtu-canvas video list 12345
sjtu-canvas video list 12345 --json

读取某个视频的播放元数据:

sjtu-canvas video info 12345 VIDEO_ID

导出字幕为 SRT:

sjtu-canvas video subtitle 12345 VIDEO_ID
sjtu-canvas video subtitle 12345 VIDEO_ID --output data/subtitles/example.srt

读取 PPT 回放切片元数据:

sjtu-canvas video ppt 12345 VIDEO_ID

下载 PPT 回放图片并合成 PDF:

sjtu-canvas video ppt-export 12345 VIDEO_ID
sjtu-canvas video ppt-export 12345 VIDEO_ID --output data/ppt/example
sjtu-canvas video ppt-export 12345 VIDEO_ID --no-pdf

下载与索引行为

下载时会尽量保持 Canvas 文件夹结构。例如 Canvas 中的:

course files/课件/Week 1/intro.pdf

会保存为:

data/课程名 [课程ID]/课件/Week 1/intro.pdf

路径和文件名会做安全清洗,避免 / \ : * ? " < > | 等跨平台非法字符。

如果本地已存在同大小文件,默认跳过,不重复下载。若本地同名文件大小不同,会保留原文件并为新下载文件追加 __canvas_文件ID 后缀以避免覆盖。

每次 downloadindex 会生成:

data/课程名 [课程ID]/course_index.json
data/课程名 [课程ID]/course_index.md

索引包含:

  • 课程基本信息
  • 文件、文件夹、模块、作业
  • 本地下载路径和状态
  • 文件更新时间
  • 视频/字幕/PPT 回放的只读接入状态
  • MCP Server 工具接口状态

错误处理

已覆盖的常见错误:

  • token 缺失:提示设置 CANVAS_TOKEN
  • 401:token 无效或过期
  • 403:无权限访问课程或资源
  • 404:课程、文件夹或资源不存在
  • 网络超时/连接失败
  • 文件名非法字符清洗
  • 下载文件大小不匹配
  • 本地文件名冲突

错误信息不会打印 token。

视频、字幕、PPT 回放

当前已经接入视频读取和本地导出能力。认证流程是:

  1. 使用 Canvas Access Token 调用 /api/v1/courses/{course_id}/external_tools/sessionless_launch?id=8329&launch_type=course_navigation
  2. 打开 Canvas 返回的一次性 LTI launch URL。
  3. 解析 LTI/OIDC 表单并提交到 v.sjtu.edu.cn
  4. 从跳转 URL 中取得 tokenId
  5. 调用 getAccessTokenByTokenId 换取 SJTU 视频 API token 和视频系统 courId
  6. 后续视频 API 请求使用临时视频 token。

支持的只读功能:

  • video list: 调用 findVodVideoList 列出课程视频。
  • video info: 调用 getVodVideoInfos 获取播放元数据。默认表格不会打印播放 URL;JSON/MCP 输出会递归脱敏 token/cookie/session 字段,并默认隐藏播放/下载 URL。
  • video subtitle: 调用 transfer/translate/detail 获取字幕并生成 SRT。
  • video ppt: 调用 vod-analysis/query-ppt-slice-es 获取 PPT 切片元数据。

支持的本地导出功能:

  • video ppt-export: 下载 PPT 回放切片图片,默认合成为 ppt.pdf
  • 已存在的图片会默认跳过;加 --force 会重新下载并重新生成 PDF。
  • --no-pdf 可以只下载图片,不合成 PDF。

字幕来源是 SJTU 视频系统返回的数据。本工具不做本地语音识别,也不调用大模型生成字幕,只把接口返回的字幕行转换成 .srt。当前接口没有暴露字幕作者或生成器字段,因此不能可靠区分是平台自动转写、教师上传,还是后续修订版本。

暂不实现:

  • 视频二进制下载。
  • 任何作业提交或自动交互。

根据参考项目实现,底层端点是:

  1. Canvas sessionless launch:/api/v1/courses/{course_id}/external_tools/sessionless_launch
  2. LTI 初始化:https://v.sjtu.edu.cn/jy-application-canvas-sjtu/oidc/login_initiations
  3. token 交换:https://v.sjtu.edu.cn/jy-application-canvas-sjtu/lti3/getAccessTokenByTokenId
  4. 调用 findVodVideoList 列出视频。
  5. 调用 getVodVideoInfos 获取播放地址。
  6. 调用 transfer/translate/detail 获取字幕。
  7. 调用 vod-analysis/query-ppt-slice-es 获取 PPT 切片元数据。

这条链路不读取 jAccount 密码。命令执行期间会使用 Canvas 返回的一次性 launch URL 和临时视频 token,错误信息会去掉 query/token,避免泄露凭据。

MCP 接入

项目已经把能力拆成可复用模块:

  • CanvasClient: Canvas API、分页、错误处理、下载流
  • CourseSyncer: 课程元数据拉取、下载规划、本地同步
  • SJTUVideoClient: 视频 LTI 认证、视频列表、详情、字幕、PPT 切片元数据
  • PPTAssetExporter: PPT 回放图片下载和 PDF 合成
  • indexer: JSON/Markdown 索引
  • models: 稳定数据模型

本地 MCP stdio server 已提供,启动命令:

sjtu-canvas-mcp

也可以通过主 CLI 启动:

sjtu-canvas mcp

在支持 MCP 的客户端中可配置为:

{
  "mcpServers": {
    "sjtu-canvas": {
      "command": "/Users/hebing/Documents/Canvas/.venv/bin/sjtu-canvas-mcp",
      "cwd": "/Users/hebing/Documents/Canvas"
    }
  }
}

cwd 建议指向项目根目录,这样 server 能读取本地 .env。不要把 .env 提交到 git。

当前暴露的工具:

  • get_current_user
  • list_courses
  • get_course
  • list_course_files
  • list_course_folders
  • list_course_modules
  • list_course_assignments
  • list_my_submissions
  • get_my_submission
  • get_course_bundle
  • plan_course_download
  • generate_course_index
  • download_course_files
  • download_my_submission_files
  • video_status
  • resolve_video_auth
  • list_course_videos
  • get_video_info
  • get_video_subtitle
  • get_video_ppt_slices
  • download_video_ppt

作业相关能力只读;提交记录工具只下载你自己已提交的附件,不开放提交、评论或改分。视频导出工具只写本地文件,不自动发布或上传。

开发验证

python -m pytest
sjtu-canvas --help
sjtu-canvas video-status
sjtu-canvas video --help
printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"manual","version":"0"}}}\n{"jsonrpc":"2.0","id":2,"method":"tools/list"}\n' | sjtu-canvas-mcp

如果没有真实 token,也可以运行上述 mock 测试和 help 命令验证框架。

MCP Server · Populars

MCP Server · New

    longsizhuo

    openInvest

    基于multiple LLM的风险投资助手

    Community longsizhuo
    CCCpan

    Gebaini

    中国数据核验 MCP Server | 身份核验/企业查询/车辆信息/OCR识别/风险评估 | 10个Tool覆盖5大类 | 微信: chenganp | 邮箱: [email protected]

    Community CCCpan
    ucsandman

    DashClaw

    🛡️The governance runtime for AI agents. Intercept actions, enforce guard policies, require approvals, and produce audit-ready decision trails.

    Community ucsandman
    ClementRingot

    SAP Released Objects Server

    Server for SAP Cloudification Repository - Clean Core Level A/B/C/D filtering

    Community ClementRingot
    raintree-technology

    docpull

    Convert the public web into AI-ready Markdown with a local Python CLI/SDK/MCP crawler.