Skip to content

Classroom Video

ChangYo edited this page Oct 25, 2026 · 2 revisions

课堂视频

项 值
平台 v.sjtu.edu.cn
认证 校园 Web 会话(jAccount SSO Cookie)
数据方向 只读
难度 中
最后验证 2026-10-06
证据等级 A(实测)

课堂视频(交大视频)是 Canvas「课堂视频新版」指向的平台,真实服务由教育技术中心提供。它提供本人教学班的录像、双路 MP4、逐句转写、AI 知识点和分段总结、PPT 逐页图片与 OCR。

要点

  • 可获取:课程、录像场次、双路 MP4、转写、AI 总结、PPT 图片与 OCR、播放数、最近观看。
  • 前置:v.sjtu.edu.cn 的校园会话 Cookie。不需要 JWT、LTI 或 Canvas Token。
  • 注意:未登录时接口返回空列表或空响应,不返回 401;转写和 PPT 异步生成;MP4 直链是签名 URL,不应缓存。

数据清单

对象 内容 备注
课程/教学班 teclId、subjCode、subjName、学期 acteId、院系 课程代码可与 Canvas course_code 映射
录像场次 courseId、起止时间、教室 clroName、节次 letiNumber、教师、缩略图 含未来排课,需区分已录/未上
播放流 双路 MP4(viewNum 1/5)、vodTime 秒 签名 URL,每次现取
逐句转写 bg/ed(毫秒)、res 文本 异步,完成度滞后
AI 总结 mindmap 知识点树 + timeRanges;documentSkims 分段总结 异步
PPT 逐页 imageUrl、ocrText、imageSeekTime、textKeywordList 图片免 Cookie;OCR 有噪声
观看数据 playCount、lastPlayInfoByTeclId 只读;不要上报/伪造

1. 平台架构

子系统 Base URL 鉴权 用途
课堂录像数据 API https://v.sjtu.edu.cn/jy-application-resourcemanage/v1 仅 sjtu.edu.cn Cookie 本文主体
统一身份 https://v.sjtu.edu.cn/cloud-rbac Cookie 登录判定、用户信息
视频门户(旁听/收藏/排行) https://v.sjtu.edu.cn/jy-application-resmgr Cookie + jwt-token 头(localStorage) 首版不需要
Canvas LTI 侧 https://v.sjtu.edu.cn/jy-application-canvas-sjtu LTI token 不需要;直接调 v.sjtu 更简单
媒体域 https://live.sjtu.edu.cn:443 URL 签名 key MP4、PPT 图片、缩略图

前端页面 #/play-center?<加密串> 中的参数由 SPA 解析为 teclId(教学班 ID)。不需要解密该参数,从课程列表接口即可正向发现。[实测]

关键标识

标识 含义 示例
teclId 教学班 9000 = 计算理论 2026 秋
courseId / id 一场录像(一次课的一节) 153907
acteId 学期 11 = 2026-2027-1
letiNumber 节次 8
vodTime 时长(秒) 3580
subjCode 课程代码 CS3313;与 Canvas course_code 中的课程号一致

2. 认证

只需要 Cookie

  1. 用户在受控窗口打开 https://v.sjtu.edu.cn/,完成 jAccount SSO。
  2. 站点在 sjtu.edu.cn 域种 Cookie。
  3. 后续 /jy-application-resourcemanage/v1/* 全部接口带 Cookie 即可,不需要 jwt-token 头。[实测 2026-10-06]

探活

GET https://v.sjtu.edu.cn/cloud-rbac/authority/me

成功条件:code === '0' 且 result.user 存在。返回里含学号、姓名、院系、角色(如「CANVAS学生」「CANVAS校内」)和权限 sign 列表。[实测]

不要用 JWT / LTI / Canvas Token

  • jwt-token 是 resmgr 门户(旁听等)的凭据,存在 localStorage;课堂录像侧不需要。
  • Canvas LTI 启动页需要 Canvas 网页会话,直接调 v.sjtu 更简单。
  • Canvas Personal Token 对课堂视频链路没有帮助。

未登录的表现

接口返回空响应或空列表,不返回 401;SPA 会一直显示「加载中」。集成时必须主动调用 authority/me 探活,不要把空数据当成「无录课」。[实测]


3. 端点表

Base:https://v.sjtu.edu.cn/jy-application-resourcemanage/v1

会话与课程

接口 关键参数 返回
GET https://v.sjtu.edu.cn/cloud-rbac/authority/me - 登录态、学号姓名院系、角色、权限
GET /v1/app/info - 应用注册信息、oauth 入口
GET /v1/list/termYear - 学期列表;Dela 取 currentTerm。参数/返回结构待复核(见待验证清单)
GET /v1/myself/curriculum acteId、courBeginTime、courEndTime、page.* 我的课程场次:teclId、subjCode/subjName、courBeginTime;含未来排课
GET /v1/teachingClass/{teclId}/t-1 teclId 路径 教学班详情:学年学期、院系、录课配置、学生名单
GET /v1/group_subject_vod_list/t-1 page.orders[0].field=courBeginTime、asc=false 备用点播课程列表;Dela 在 curriculum 为空时补查,并按 acteId 过滤

视频与播放

接口 关键参数 返回
GET /v1/subject_vod_list_new teclIds、page.* 场次列表:id、起止时间、教室 clroName、letiNumber、教师、缩略图 shotImgUrl、courTransferFlag、coursePptSliceStatus
GET /v1/course_vod_videoinfos courseId 单场元数据 + 直播状态;不含直链
GET /v1/course_vod_urls_new courseId courseVodViewList:双路 MP4(url、viewNum 1/5、vodTime 秒)
GET /v1/mss_sdk_play_mode courseId 通道配置:{"name":["链路1","链路2","校内"],"show":[1,1,0]}
GET /v1/vod/playCount id 播放次数
GET /v1/source/vod/lastPlayInfoByTeclId teclId 最近观看场次
GET /v1/vod/download/{courseId} fileName 官方 zip 下载

转写、AI、PPT

接口 关键参数 返回
GET /v1/course_vod_subtitle_with_keyword courseId courseTransferEsDtoList[]:bg/ed(毫秒)、res(句文本)
GET /v1/course/ai/textSummary/{courseId} 路径 mindmap:知识点树,节点带 label、timeRanges[](秒);summary:JSON 字符串
GET /v1/course/ai/summary/search/{courseId} 路径 documentSkims[]:time(如 "7-689")、overview、content
GET /v1/course/ai/ppt courseId docList[]:imageUrl、ocrText、imageSeekTime(秒)、textKeywordList
POST /v1/aftertime/captions/{courseId} 空 JSON captionsReleaseStatus 字幕发布状态

4. 响应结构与分页

通用响应:

{
  "code": null,
  "data": { "...": "..." },
  "message": "...",
  "ok": true,
  "status": 200
}
  • 成功:ok: true,code: null;authority/me 用 code: '0'。
  • 失败:ok: false、dataOk: false、status 非 200,或 code: '-1'。unwrap 时都要判。
  • 列表数据在 data.records;分页字段 pageCount。

分页参数:

page.pageIndex=1
page.pageSize=1000
page.orders[0].field=courBeginTime
page.orders[0].asc=false

关键事实:

  • pageIndex 从 1 开始。
  • 官方空分页可能返回 records: null;只有在第一页、ok:true、dataOk:true、rowCount:0、pageCount:0 时才当空数组。[实测]
  • 后续页不能用「零总数」清空已取结果;否则网络抖动会把列表清空。
  • 没有 pageCount 时,用 records.length < pageSize 判断结束。

5. 数据质量

  • 转写:中文课堂 ASR,同音字噪声明显。它适合检索,也可以作为 Agent 的参考文本,但不作为权威讲稿;展示时应标注「机器转写」。
  • OCR:PPT 页文本可用,但混入播放器 UI 噪声(如「保存」「切换」「更多」)。同样标来源。
  • 三套时间戳:知识点 timeRanges(秒)、转写 bg/ed(毫秒)、PPT imageSeekTime(秒)。做「点击知识点跳转」时秒级精度足够。
  • 元数据:课名/教师/教室/时间/节次来自排课系统,准确度较高。
  • 覆盖:2026-10-06 实测 Canvas 在读 9 门课,其中 8 门有录课,计算机伦理学没有。录课取决于教室设备和课程配置,并非全覆盖。[实测]

6. 常见问题

  1. 未登录返回空列表或空响应,不返回 401:先调用 authority/me;空列表不等于无录课。
  2. 未来排课也在列表里:curriculum 含未上的场次;用时间/lvcrVodStatus 区分已录/未上。
  3. 转写和 PPT 是异步的:录制当天可能还没好;存状态位,下次重拉,不要假设恒可用。
  4. 部分课程没有录课:UI 必须支持「该课无录课」状态。
  5. MP4 是签名 URL:?key=<timestamp>-0-0-<hex>,免 Cookie、支持 Range;单次观察 ≥8h 仍有效,确切 TTL 未测出。每次播放现取,不要缓存 URL。
  6. 不要缓存签名 URL:只缓存场次元数据;播放/下载前重新调 course_vod_urls_new。
  7. 不要把播放上报当功能:addVodWatchRecord、recordPlayInfo、keepAlive 等写接口一律不调;部分课程以观看记录考核,第三方播放不应伪装成官方观看。
  8. JWT 只给门户:resmgr 的 jwt-token 不要拿来调课堂录像 API。
  9. LTI 只给 Canvas 内嵌:直接调 v.sjtu 更简单,不要为了拿 LTI token 去模拟 Canvas 网页会话。
  10. list/termYear 的返回/参数可能变化:Dela 当前取 currentTerm;学期切换时要复核,必要时回退到 teachingClass 的 acteId。
  11. 限流未观察:单日数十次调用无异常,但不要压测;按需重试即可。
  12. 直播未验证:首版不涉及。

7. 最小示例

// session 是已登录 v.sjtu 的持久会话
const BASE = 'https://v.sjtu.edu.cn/jy-application-resourcemanage/v1';

async function probe(session: CampusSession) {
  const response = await session.fetch('https://v.sjtu.edu.cn/cloud-rbac/authority/me', {
    headers: { Accept: 'application/json' },
  });
  const payload = await response.json();
  if (String(payload.code) !== '0' || !payload.result?.user) {
    throw new Error('校园会话已失效,请登录交大视频');
  }
  return payload.result.user;
}

function recordsOf<T>(payload: any): T[] {
  const data = payload?.data;
  if (data?.records === null) {
    if (
      payload.ok === true &&
      payload.dataOk === true &&
      data.rowCount === 0 &&
      data.pageCount === 0
    ) {
      return [];
    }
    throw new Error('视频列表返回了空记录');
  }
  if (!Array.isArray(data?.records)) throw new Error('视频列表结构已变化');
  return data.records as T[];
}

async function listVideos(session: CampusSession, teclId: number) {
  const query = new URLSearchParams({
    teclIds: String(teclId),
    'page.pageIndex': '1',
    'page.pageSize': '1000',
    'page.orders[0].field': 'courBeginTime',
    'page.orders[0].asc': 'false',
  });
  const response = await session.fetch(`${BASE}/subject_vod_list_new?${query}`, {
    headers: { Accept: 'application/json', Referer: 'https://v.sjtu.edu.cn/jy-application-resourcemanage-ui/' },
  });
  const payload = await response.json();
  if (payload.ok === false || payload.dataOk === false) throw new Error('视频列表请求失败');
  return recordsOf<{ id: number; courBeginTime: string; clroName?: string }>(payload);
}

async function getStreams(session: CampusSession, courseId: number) {
  const response = await session.fetch(`${BASE}/course_vod_urls_new?courseId=${courseId}`, {
    headers: { Accept: 'application/json', Referer: 'https://v.sjtu.edu.cn/jy-application-resourcemanage-ui/' },
  });
  const payload = await response.json();
  const streams = payload.data?.courseVodViewList ?? [];
  return streams.map((stream: { url: string; viewNum: number; vodTime?: number }) => ({
    url: stream.url,
    view: stream.viewNum,
    duration: stream.vodTime ?? 0,
  }));
}

本地个人播放器可以把 MP4 URL 直接交给 <video>;如果要下载,用 Range 请求并校验 206/文件大小。签名 URL 每次播放前重新取。

桌面应用建议把播放放主进程代理:签名 URL 不进 renderer,Range/Referer 由主进程转发,避免远程内容按可猜测的 videoId 盗播。Dela 的 src/main/vsjtu/playback.ts 就是这么做的(每次运行随机 HMAC token)。[实测 2026-10]


8. 不要做

  • 不要上报观看记录、伪造播放进度、把第三方播放说成官方观看。
  • 不要批量下载或重新分发课堂录像;课程内容不属于公开资源。
  • 不要绕过登录、破解签名、抓取他人课程。
  • 不要直播/旁听门户未验证的接口。

9. 证据与来源

  • 四个子系统、teclId/acteId/courseId、认证只需 Cookie、authority/me 探活、空列表行为、双路 MP4、签名 TTL、转写/总结/PPT 字段、覆盖率、异步流水线:[实测 2026-10-06,内部实测记录未入库;实现见 Dela src/main/vsjtu/*]
  • Dela 代码中的 list/termYear、records:null 处理、group_subject_vod_list/t-1 备用列表、播放代理:[实测 2026-09/10,Dela src/main/vsjtu/*]
  • 交大视频:[官方] https://v.sjtu.edu.cn/

变更记录

  • 2026-10-25:首版。基于内部实测记录与 Dela 代码重写,补充转写、AI、PPT 端点、数据质量和常见问题。

Clone this wiki locally