| name | canvas-sjtu |
| description | Login, session management, file operations, and unified browsing for Canvas@SJTU (oc.sjtu.edu.cn) via jAccount SSO. Use when the user needs to access Canvas@SJTU, login to oc.sjtu.edu.cn, browse courses/assignments/files/announcements/modules, download files, submit assignments, or navigate Canvas via structured paths. Features: navigate() unified browsing primitive (one function for all page-level operations), jAccount captcha login, Playwright session persistence, dual-mode API (Bearer token or Playwright cookies), Canvas REST API, and S3 file uploads. Provides a unified CLI (canvas.py) for all operations. |
Canvas@SJTU Session Manager
Setup (First Time)
pip install playwright
playwright install chromium
mkdir -p local
python scripts/login.py
All runtime data stored in ./local/ (gitignored):
local/oc_session.json — Playwright session state
local/oc_courses.json — Course index cache
local/downloads/ — Downloaded files
local/oc_login.log — Login activity log
Quick Start
python scripts/canvas.py <command>
| Command | Function | Safety |
|---|
navigate [<path>] | Unified browsing primitive — browse Canvas by path; returns structured JSON for agent consumption | Read-only |
dashboard | Home overview (active courses + upcoming deadlines) | Read-only |
courses | List all active courses (force-refresh from API) | Read-only |
files <course> | List all files in a course | Read-only |
download <course> <kw> | Download files matching keyword | Read-only |
assignments <course> | List assignments (due dates, scores, submission status) | Read-only |
submit <course> <asgn> <file> | Submit file to assignment via S3 upload | Requires explicit confirmation |
open | Open Canvas in visible browser | Read-only |
login | Manual re-login (opens browser) | Write (session) |
<course> accepts: numeric ID (e.g., 87954) or keyword (e.g., 光纤, 电子线路).
Navigate — Unified Browsing Primitive
A single function that replaces all page-level commands. Designed for AI agents to browse Canvas like a human.
python canvas.py navigate [<path>]
Path hierarchy:
| Path | Returns |
|---|
/ | Dashboard: active courses + todos |
/courses/:id | Course home: modules/files/assignments/pages/announcements counts + previews |
/courses/:id/modules | Module list (with completion state) |
/courses/:id/modules/:mid | Module items (PPT/视频/实验/etc.) |
/courses/:id/files | File list (with sizes) |
/courses/:id/assignments | Assignment list (with scores, submission status) |
/courses/:id/announcements | Announcement list (with author/dates) |
/courses/:id/pages | Wiki page list |
Design: New API endpoints only need one if sub == "xxx" block in navigate(). No new CLI command required.
Login Flow
- Canvas login page:
https://oc.sjtu.edu.cn/login/canvas
- jAccount SSO link:
/login/openid_connect → redirects to jaccount.sjtu.edu.cn/jaccount/jalogin
- jAccount form fields:
#input-login-user, #input-login-pass, #input-login-captcha
- Captcha URL:
captcha?uuid=UUID&t=TIMESTAMP (110x40px, 4-5 lowercase letters)
- After SSO, redirect back to Canvas dashboard
Submission API (Write — with confirmation)
The submit command implements the 3-step Canvas file upload pipeline:
-
Upload preflight: POST /api/v1/courses/:cid/assignments/:aid/submissions/self/files
- Body:
name=X&size=N&content_type=Y
- Returns:
{upload_url, upload_params} (AWS S3 presigned URL)
-
S3 upload: POST {upload_url} with multipart form data
- Includes all
upload_params + file binary
- Uses Playwright API request context (bypasses CORS, shares session cookies)
-
Confirm submission: POST /api/v1/courses/:cid/assignments/:aid/submissions
- Body:
submission[submission_type]=online_upload&submission[file_ids][]=:id
- Requires
X-CSRF-Token header (extracted from session cookies, URL-decoded)
Safety: User must type SUBMIT explicitly to confirm. Preview shows course, assignment, file path, size, and MIME type before confirmation.
Architecture
- API-first: Uses Canvas REST API (
/api/v1) instead of HTML scraping
- Dual-mode: Bearer token (lightweight, ~50ms) preferred; Playwright session (~1.5s) fallback
- Browsing primitive:
navigate() — one function for all page-level operations
- Playwright request context:
p.request.new_context(storage_state=...) to share session cookies for file downloads and uploads (avoids CORS issues with page-level fetch())
- CourseIndex: 1-hour file cache (
oc_courses.json) with keyword + numeric ID resolution
- Session: Playwright
storage_state() JSON → cookies + localStorage → restored via new_context(storage_state=...)
Scripts
| Script | Purpose |
|---|
scripts/canvas.py | Unified CLI (all operations — navigate, dashboard, files, download, assignments, submit, open, login, token) |
scripts/login.py | Manual login with browser window, saves session |
scripts/access.py | Legacy: open Canvas with saved session |
Platform Notes
- Windows: Use
Start-Process (not -NoNewWindow) for background browser scripts
- enhanced_terminal: Avoid for Python on Windows (DLL init error -1073741502)
- Chrome profile:
C:\Users\81004\AppData\Local\Google\Chrome\User Data\Default