A JavaScript library to provide a program-friendly interface to Web Learning of Tsinghua University
This is a JavaScript library aimed to provide a program-friendly interface of web Learning of Tsinghua University.
This project is licensed under MIT License.
The library uses node-fetch-cookie-native
, which is a simple wrapper for node-fetch-native and fetch-cookie, providing cookie and redirection support in both browsers and Node.
In case of any syntax problems, just upgrade your browser / Node, or use any corresponding polyfills.
yarn add thu-learn-lib
<script src="https://cdn.jsdelivr.net/npm/thu-learn-lib@3"></script>
<!-- or -->
<script src="https://unpkg.com/thu-learn-lib@3"></script>
The library is exposed under window.LearnLib
.
<script type="module">
import { Learn2018Helper } from 'https://esm.sh/thu-learn-lib@3';
</script>
yarn run build
You can find the bundled library in lib/
.
index.js
: ES module entryindex.d.ts
: definition file for TypeScriptindex.global.js{,.map}
: IIFE for use in browser (with source map for debugging)yarn run dev
This will open a dev browser with a testing extension. Click the t
icon in extension bar, then execute anything you want in the Console of Chrome Developer Tool.
The library is exposed under window.LearnLib
.
Use yarn run dev:build
to build the extension that can be installed to your chrome browser manually.
import { Learn2018Helper } from 'thu-learn-lib';
// There are three ways of logging in:
// 1. provide a cookie jar with existing cookies (see `tough-cookie`)
const helper = new Learn2018Helper({ cookieJar });
// 2. provide nothing, but invoking login with username and password
const helper = new Learn2018Helper();
// 3. provide a CredentialProvider function, which can be async
const helper = new Learn2018Helper({
provider: () => ({ username, password }),
});
// Note that by using the following two methods you may encounter problems like login time out.
// But if you provide a credential provider, the library will retry logging in when failing, automatically resolving the cookie expiry problem.
// So we strongly recommend using this method.
// If you do not provide a cookie jar or CredentialProvider, you must log in manually. Otherwise you do not need to call login explicitly.
try {
await helper.login(username, password);
} catch (e) {
// e is a FailReason
}
// You can also take out cookies (e.g. for file download), which will not work in browsers.
console.log(helper.cookieJar);
// Logout if you want, but the cookie jar will not be cleared.
await helper.logout();
We currently support both student and teacher (or TA) version of web learning. To keep backwards compatibility, the default behavior of all APIs is to use the student version. The following APIs needs CourseType.TEACHER
as the last (optional) parameter to access the teacher version. You should use them when you are the teacher / TA of one course, for you will get nothing from the student version in that case.
We do not maintain a global type in Learn2018Helper
class, for there can be the situation that one can be a student and teacher of the same course simultaneously, on which by using different CourseType
you can get different results.
getCourseList
getNotificationList/getFileList/getHomeworkList/getDiscussionList/getAnsweredQuestionList
getAllContents
Note that currently fetching homework information from teacher version is partially implemented.
import { ContentType, ApiError } from 'thu-learn-lib';
// get ids of all semesters that current account has access to
const semesters = await helper.getSemesterIdList();
// get get semester info
const semester = await helper.getCurrentSemester();
// get courses of this semester
const courses = await helper.getCourseList(semester.id);
const course = courses[0];
// get detail information about the course
const discussions = await helper.getDiscussionList(course.id);
const notifications = await helper.getNotificationList(course.id);
const files = await helper.getFileList(course.id);
const homework = await helper.getHomeworkList(course.id);
const questions = await helper.getAnsweredQuestionList(course.id);
// get content from bunches of courses
// the return type will be { [id: string]: Content }
// where Content = Notification | File | Homework | Discussion | Question
const homeworks = await helper.getAllContents([1, 2, 3], ContentType.HOMEWORK);
// get course calendar in a period
try {
const calendar = await helper.getCalendar('20191001', '20191201');
} catch (e) {
const error = e as ApiError;
// check e.reason and e.extra for information
// you might want to check your date format or shrink the range (currently we observe a limit of 29 days)
}
According to security strategies (CORS, CORB) of browsers, you might need to run the code in the page context of https://learn.tsinghua.edu.cn
and https://id.tsinghua.edu.cn
. The simplest way is to run the code in Node.js or in browser extension.
See src/types.ts
for type definitions. Note that ApiError
represents the type that will be used in rejected Promises.
Run yarn test
for testing. It requires your personal credential since we don't have mocks for these APIs. To do this, you must touch a .env
similar to template.env
under /test folder.
It's ok if you meet Timeout * Async callback was not invoked within the 5000ms timeout...
error when running tests, rerun tests may resolve this problem. If you hate this, just add the third argument timeout
to every testcase it("should...", async () => void, timeout)
and make sure it's greater than 5000.
Homework.gradeLevel
changed to HomeworkGradeLevel
(a string enum) for better i18nfetch-cookie
dependency in browser build, reducing bundle sizegetUserInfo
interface (#48, thanks to @robertying)webpack
-> tsup
webpack
-> vite
jest
-> vitest
cross-fetch
-> node-fetch-native
(Node.js now has native fetch
)real-isomorphic-fetch
-> fetch-cookie
(fetch-cookie
now can handle redirects)tough-cookie-no-native
-> tough-cookie
(tough-cookie
is now native)/lib
or /lib/types
anymorefake-parse5
to a seperate library
generatePreviewUrlForFirstPage
to switch preview URL type (default to true
)RemoteFile
to represent a file on Web LearningallowFailure
in getAllContents
for conveniencegetCSRFToken
methodaddCSRFTokenToUrl
function as API for convenienceimport
in Node.jsparse5
with htmlparser2
in Cheerio and remove it from bundled file (replaced with src/fake-parse5
)v2.3.1
(not published) and v2.3.0
that build output fails to be uploaded to npmApiError
in usage of Promise.reject
(might be a breaking change)previewUrl
Learn2018Helper
class to protect credentialspreviewUrl
to File
eval
in getCalendar
FailReason
to represent all strings that will be used as the reason of rejected Promiseslogin
and logout
no longer return PromisesCredentialProvider
is provided (thanks to mayeths)jest
(thanks to mayeths)null
values in getSemesterIdList
APIhttps://learn.tsinghua.edu.cn/
from learn2018
permanentlygetTACourseList
to get TA's course list (temporarily can not be used by other functions)js-base64
backBase64.js
instead of js-base64
, which uses evil eval
yarn
attachmentUrl
filed of Notificationurl
for Courseurl
for Question (to display correct section name)url
error in Questiondescription
field of homeworkentities
to decode HTML entities