chuvsu-js 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.ts +5 -0
- package/dist/browser.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/tt/client.d.ts +11 -5
- package/dist/tt/client.js +38 -36
- package/dist/tt/parse.js +87 -2
- package/dist/tt/schedule.d.ts +13 -3
- package/dist/tt/schedule.js +95 -17
- package/dist/tt/types.d.ts +1 -0
- package/dist/tt/utils.d.ts +4 -0
- package/dist/tt/utils.js +19 -0
- package/package.json +5 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Schedule } from "./tt/schedule.js";
|
|
2
|
+
export { getCurrentPeriod, isSessionPeriod, getSemesterStart, getSemesterWeeks, getWeekNumber, getWeekdayName, } from "./tt/utils.js";
|
|
3
|
+
export { Period, EducationType } from "./common/types.js";
|
|
4
|
+
export type { Time, WeekRange, Teacher, } from "./common/types.js";
|
|
5
|
+
export type { Faculty, Group, ScheduleEntry, FullScheduleSlot, FullScheduleDay, LessonTimeSlot, Lesson, LessonTime, SemesterWeek, } from "./tt/types.js";
|
package/dist/browser.js
ADDED
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { LkClient } from "./lk/client.js";
|
|
|
2
2
|
export { TtClient } from "./tt/client.js";
|
|
3
3
|
export { Schedule } from "./tt/schedule.js";
|
|
4
4
|
export type { CacheEntry } from "./common/cache.js";
|
|
5
|
-
export { getSemesterStart, getSemesterWeeks, getWeekNumber, getWeekdayName, } from "./tt/utils.js";
|
|
5
|
+
export { getCurrentPeriod, isSessionPeriod, getSemesterStart, getSemesterWeeks, getWeekNumber, getWeekdayName, } from "./tt/utils.js";
|
|
6
6
|
export { Period, EducationType, AuthError, ParseError } from "./common/types.js";
|
|
7
7
|
export type { Time, WeekRange, Teacher, } from "./common/types.js";
|
|
8
8
|
export type { PersonalData, } from "./lk/types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { LkClient } from "./lk/client.js";
|
|
2
2
|
export { TtClient } from "./tt/client.js";
|
|
3
3
|
export { Schedule } from "./tt/schedule.js";
|
|
4
|
-
export { getSemesterStart, getSemesterWeeks, getWeekNumber, getWeekdayName, } from "./tt/utils.js";
|
|
4
|
+
export { getCurrentPeriod, isSessionPeriod, getSemesterStart, getSemesterWeeks, getWeekNumber, getWeekdayName, } from "./tt/utils.js";
|
|
5
5
|
export { AuthError, ParseError } from "./common/types.js";
|
package/dist/tt/client.d.ts
CHANGED
|
@@ -21,13 +21,19 @@ export declare class TtClient {
|
|
|
21
21
|
private relogin;
|
|
22
22
|
private authGet;
|
|
23
23
|
private authPost;
|
|
24
|
-
|
|
24
|
+
private fetchSchedule;
|
|
25
|
+
/**
|
|
26
|
+
* Get schedule for all periods. The returned Schedule automatically
|
|
27
|
+
* routes queries to the correct period based on the date.
|
|
28
|
+
*/
|
|
29
|
+
getSchedule(groupId: number): Promise<Schedule>;
|
|
30
|
+
/**
|
|
31
|
+
* Get schedule for a specific period only.
|
|
32
|
+
*/
|
|
33
|
+
getScheduleForPeriod(opts: {
|
|
25
34
|
groupId: number;
|
|
26
|
-
period
|
|
35
|
+
period: Period;
|
|
27
36
|
}): Promise<Schedule>;
|
|
28
|
-
getCurrentPeriod(opts?: {
|
|
29
|
-
date?: Date;
|
|
30
|
-
}): Period;
|
|
31
37
|
getFaculties(): Promise<Faculty[]>;
|
|
32
38
|
getGroupsForFaculty(opts: {
|
|
33
39
|
facultyId: number;
|
package/dist/tt/client.js
CHANGED
|
@@ -5,6 +5,12 @@ import { parseGroupButtons, parseFacultyButtons, parseTeacherButtons, parseFullS
|
|
|
5
5
|
import { Schedule } from "./schedule.js";
|
|
6
6
|
const BASE = "https://tt.chuvsu.ru";
|
|
7
7
|
const AUTH_URL = `${BASE}/auth`;
|
|
8
|
+
const ALL_PERIODS = [
|
|
9
|
+
1 /* Period.FallSemester */,
|
|
10
|
+
2 /* Period.WinterSession */,
|
|
11
|
+
3 /* Period.SpringSemester */,
|
|
12
|
+
4 /* Period.SummerSession */,
|
|
13
|
+
];
|
|
8
14
|
export class TtClient {
|
|
9
15
|
http = new HttpClient();
|
|
10
16
|
educationType;
|
|
@@ -91,44 +97,40 @@ export class TtClient {
|
|
|
91
97
|
return res;
|
|
92
98
|
}
|
|
93
99
|
// --- Schedule ---
|
|
94
|
-
async
|
|
95
|
-
const
|
|
96
|
-
const cacheKey = `${opts.groupId}:${period}`;
|
|
100
|
+
async fetchSchedule(groupId, period) {
|
|
101
|
+
const cacheKey = `${groupId}:${period}`;
|
|
97
102
|
const cached = this.cache?.get("schedule", cacheKey);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
103
|
+
if (cached)
|
|
104
|
+
return cached;
|
|
105
|
+
const url = `${BASE}/index/grouptt/gr/${groupId}`;
|
|
106
|
+
const { body } = await this.authPost(url, { htype: String(period) });
|
|
107
|
+
const days = parseFullSchedule(body);
|
|
108
|
+
this.cache?.set("schedule", cacheKey, days);
|
|
109
|
+
return days;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get schedule for all periods. The returned Schedule automatically
|
|
113
|
+
* routes queries to the correct period based on the date.
|
|
114
|
+
*/
|
|
115
|
+
async getSchedule(groupId) {
|
|
116
|
+
const schedules = new Map();
|
|
117
|
+
const results = await Promise.all(ALL_PERIODS.map(async (period) => {
|
|
118
|
+
const days = await this.fetchSchedule(groupId, period);
|
|
119
|
+
return { period, days };
|
|
120
|
+
}));
|
|
121
|
+
for (const { period, days } of results) {
|
|
122
|
+
schedules.set(period, days);
|
|
113
123
|
}
|
|
114
|
-
return new Schedule(
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// Feb–May → Spring semester (весенний семестр)
|
|
125
|
-
if (month >= 1 && month <= 4)
|
|
126
|
-
return 3 /* Period.SpringSemester */;
|
|
127
|
-
// Jun–Aug → Summer session (летняя сессия)
|
|
128
|
-
if (month >= 5 && month <= 7)
|
|
129
|
-
return 4 /* Period.SummerSession */;
|
|
130
|
-
// Sep – Dec 24 → Fall semester (осенний семестр)
|
|
131
|
-
return 1 /* Period.FallSemester */;
|
|
124
|
+
return new Schedule(groupId, schedules);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get schedule for a specific period only.
|
|
128
|
+
*/
|
|
129
|
+
async getScheduleForPeriod(opts) {
|
|
130
|
+
const days = await this.fetchSchedule(opts.groupId, opts.period);
|
|
131
|
+
const schedules = new Map();
|
|
132
|
+
schedules.set(opts.period, days);
|
|
133
|
+
return new Schedule(opts.groupId, schedules, opts.period);
|
|
132
134
|
}
|
|
133
135
|
// --- Search / Discovery ---
|
|
134
136
|
async getFaculties() {
|
package/dist/tt/parse.js
CHANGED
|
@@ -56,6 +56,14 @@ export function parseTeacherButtons(html) {
|
|
|
56
56
|
}
|
|
57
57
|
export function parseFullSchedule(html) {
|
|
58
58
|
const doc = parseHtml(html);
|
|
59
|
+
// Session layout has date-based cells with ids like "trd20251224"
|
|
60
|
+
if (doc.querySelector('td[id^="trd2"]')) {
|
|
61
|
+
return parseSessionSchedule(doc);
|
|
62
|
+
}
|
|
63
|
+
return parseSemesterSchedule(doc);
|
|
64
|
+
}
|
|
65
|
+
// --- Semester schedule parsing (weekday-based, repeating weekly) ---
|
|
66
|
+
function parseSemesterSchedule(doc) {
|
|
59
67
|
const days = [];
|
|
60
68
|
const rows = doc.querySelectorAll("tr");
|
|
61
69
|
let currentDay = null;
|
|
@@ -86,7 +94,7 @@ export function parseFullSchedule(html) {
|
|
|
86
94
|
continue;
|
|
87
95
|
const entries = [];
|
|
88
96
|
for (const entryRow of dataCell.querySelectorAll("table tr")) {
|
|
89
|
-
const entry =
|
|
97
|
+
const entry = parseSemesterEntry(entryRow);
|
|
90
98
|
if (entry)
|
|
91
99
|
entries.push(entry);
|
|
92
100
|
}
|
|
@@ -99,7 +107,7 @@ export function parseFullSchedule(html) {
|
|
|
99
107
|
}
|
|
100
108
|
return days;
|
|
101
109
|
}
|
|
102
|
-
function
|
|
110
|
+
function parseSemesterEntry(el) {
|
|
103
111
|
const td = el.querySelector("td") ?? el;
|
|
104
112
|
const fullHtml = td.innerHTML ?? "";
|
|
105
113
|
const plainText = text(td);
|
|
@@ -125,3 +133,80 @@ function parseScheduleEntry(el) {
|
|
|
125
133
|
weekParity,
|
|
126
134
|
};
|
|
127
135
|
}
|
|
136
|
+
// --- Session schedule parsing (date-based, specific dates) ---
|
|
137
|
+
function parseSessionSchedule(doc) {
|
|
138
|
+
const days = [];
|
|
139
|
+
for (const dateCell of doc.querySelectorAll('td[id^="trd2"]')) {
|
|
140
|
+
// Parse date from cell id: trd20251224 -> 2025-12-24
|
|
141
|
+
const id = dateCell.getAttribute("id") ?? "";
|
|
142
|
+
const dateMatch = id.match(/trd(\d{4})(\d{2})(\d{2})/);
|
|
143
|
+
if (!dateMatch)
|
|
144
|
+
continue;
|
|
145
|
+
const year = parseInt(dateMatch[1]);
|
|
146
|
+
const month = parseInt(dateMatch[2]) - 1;
|
|
147
|
+
const dayNum = parseInt(dateMatch[3]);
|
|
148
|
+
const date = new Date(year, month, dayNum);
|
|
149
|
+
// Extract weekday from after <br>
|
|
150
|
+
const cellHtml = dateCell.innerHTML ?? "";
|
|
151
|
+
const brMatch = cellHtml.match(/<br\s*\/?>\s*(.+)/i);
|
|
152
|
+
const weekday = brMatch ? brMatch[1].trim() : "";
|
|
153
|
+
// Data cell is the next td.trdata sibling in the same row
|
|
154
|
+
const row = dateCell.parentElement;
|
|
155
|
+
if (!row)
|
|
156
|
+
continue;
|
|
157
|
+
const dataCell = row.querySelector("td.trdata:not(.trfd)");
|
|
158
|
+
if (!dataCell)
|
|
159
|
+
continue;
|
|
160
|
+
// Parse entries
|
|
161
|
+
const slots = [];
|
|
162
|
+
let slotNumber = 1;
|
|
163
|
+
for (const entryRow of dataCell.querySelectorAll("table tr")) {
|
|
164
|
+
const td = entryRow.querySelector("td") ?? entryRow;
|
|
165
|
+
const entry = parseSessionEntry(td);
|
|
166
|
+
if (!entry)
|
|
167
|
+
continue;
|
|
168
|
+
slots.push({
|
|
169
|
+
number: slotNumber++,
|
|
170
|
+
timeStart: entry.timeStart,
|
|
171
|
+
timeEnd: entry.timeEnd,
|
|
172
|
+
entries: [entry.entry],
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
if (slots.length > 0) {
|
|
176
|
+
days.push({ weekday, date, slots });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return days;
|
|
180
|
+
}
|
|
181
|
+
function parseSessionEntry(td) {
|
|
182
|
+
const fullHtml = td.innerHTML ?? "";
|
|
183
|
+
const plainText = text(td);
|
|
184
|
+
if (!plainText)
|
|
185
|
+
return null;
|
|
186
|
+
// Subject from blue span
|
|
187
|
+
const subjectEl = td.querySelector('span[style*="color: blue"]');
|
|
188
|
+
const subject = subjectEl ? text(subjectEl) : "";
|
|
189
|
+
if (!subject)
|
|
190
|
+
return null;
|
|
191
|
+
// Room: text before the first <span
|
|
192
|
+
const roomMatch = fullHtml.match(/^([^<]*?)\s*<span/);
|
|
193
|
+
const room = roomMatch ? roomMatch[1].trim() : "";
|
|
194
|
+
// Type: parenthesized text after </span>, case-insensitive
|
|
195
|
+
const typeMatch = plainText.match(/\((лк|пр|лб|зач|экз|зчО|кр|конс\.?|Экз)\)/i);
|
|
196
|
+
const type = typeMatch ? typeMatch[1].replace(/\.$/, "").toLowerCase() : "";
|
|
197
|
+
// Time: after <br>, format HH:MM - HH:MM
|
|
198
|
+
const timeMatch = fullHtml.match(/<br\s*\/?>\s*(\d{2}:\d{2})\s*-\s*(\d{2}:\d{2})/);
|
|
199
|
+
if (!timeMatch)
|
|
200
|
+
return null;
|
|
201
|
+
return {
|
|
202
|
+
entry: {
|
|
203
|
+
room,
|
|
204
|
+
subject,
|
|
205
|
+
type,
|
|
206
|
+
weeks: { from: 0, to: 0 },
|
|
207
|
+
teacher: { name: "" },
|
|
208
|
+
},
|
|
209
|
+
timeStart: parseTime(timeMatch[1]),
|
|
210
|
+
timeEnd: parseTime(timeMatch[2]),
|
|
211
|
+
};
|
|
212
|
+
}
|
package/dist/tt/schedule.d.ts
CHANGED
|
@@ -2,11 +2,21 @@ import type { FullScheduleDay, SemesterWeek, Lesson } from "./types.js";
|
|
|
2
2
|
import { Period } from "../common/types.js";
|
|
3
3
|
export declare class Schedule {
|
|
4
4
|
readonly groupId: number;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
constructor(groupId: number,
|
|
5
|
+
private scheduleMap;
|
|
6
|
+
private _period?;
|
|
7
|
+
constructor(groupId: number, schedules: Map<number, FullScheduleDay[]>, period?: Period);
|
|
8
|
+
/** Current (or fixed) period for this schedule. */
|
|
9
|
+
get period(): Period;
|
|
10
|
+
/** Days for the current period. */
|
|
11
|
+
get days(): FullScheduleDay[];
|
|
12
|
+
/** All periods that have data in this schedule. */
|
|
13
|
+
get periods(): Period[];
|
|
14
|
+
/** Get days for a specific period. */
|
|
15
|
+
getDays(period: Period): FullScheduleDay[];
|
|
8
16
|
private getSlotsForWeekday;
|
|
9
17
|
private getDateForWeekday;
|
|
18
|
+
private static isSameDay;
|
|
19
|
+
private getSessionLessonsForDate;
|
|
10
20
|
forDay(weekday: number, opts?: {
|
|
11
21
|
subgroup?: number;
|
|
12
22
|
week?: number;
|
package/dist/tt/schedule.js
CHANGED
|
@@ -1,23 +1,40 @@
|
|
|
1
|
-
import { getWeekdayName, getMonday, getSemesterStart, getSemesterWeeks, getWeekNumber, filterSlots, slotsToLessons, } from "./utils.js";
|
|
1
|
+
import { getCurrentPeriod, isSessionPeriod, getWeekdayName, getMonday, getSemesterStart, getSemesterWeeks, getWeekNumber, filterSlots, slotsToLessons, } from "./utils.js";
|
|
2
2
|
export class Schedule {
|
|
3
3
|
groupId;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
constructor(groupId,
|
|
4
|
+
scheduleMap;
|
|
5
|
+
_period;
|
|
6
|
+
constructor(groupId, schedules, period) {
|
|
7
7
|
this.groupId = groupId;
|
|
8
|
-
this.
|
|
9
|
-
this.
|
|
8
|
+
this.scheduleMap = schedules;
|
|
9
|
+
this._period = period;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
/** Current (or fixed) period for this schedule. */
|
|
12
|
+
get period() {
|
|
13
|
+
return this._period ?? getCurrentPeriod();
|
|
14
|
+
}
|
|
15
|
+
/** Days for the current period. */
|
|
16
|
+
get days() {
|
|
17
|
+
return this.scheduleMap.get(this.period) ?? [];
|
|
18
|
+
}
|
|
19
|
+
/** All periods that have data in this schedule. */
|
|
20
|
+
get periods() {
|
|
21
|
+
return [...this.scheduleMap.keys()];
|
|
22
|
+
}
|
|
23
|
+
/** Get days for a specific period. */
|
|
24
|
+
getDays(period) {
|
|
25
|
+
return this.scheduleMap.get(period) ?? [];
|
|
26
|
+
}
|
|
27
|
+
// --- Semester helpers (weekday-based) ---
|
|
28
|
+
getSlotsForWeekday(weekday, days, opts) {
|
|
12
29
|
const dayName = getWeekdayName(weekday);
|
|
13
|
-
const day =
|
|
30
|
+
const day = days.find((d) => d.weekday.toLowerCase() === dayName.toLowerCase());
|
|
14
31
|
if (!day)
|
|
15
32
|
return [];
|
|
16
33
|
return filterSlots(day.slots, opts);
|
|
17
34
|
}
|
|
18
|
-
getDateForWeekday(weekday, week) {
|
|
35
|
+
getDateForWeekday(weekday, period, week) {
|
|
19
36
|
if (week != null) {
|
|
20
|
-
const startMonday = getMonday(getSemesterStart({ period
|
|
37
|
+
const startMonday = getMonday(getSemesterStart({ period }));
|
|
21
38
|
const date = new Date(startMonday);
|
|
22
39
|
date.setDate(startMonday.getDate() +
|
|
23
40
|
(week - 1) * 7 +
|
|
@@ -32,24 +49,85 @@ export class Schedule {
|
|
|
32
49
|
date.setHours(0, 0, 0, 0);
|
|
33
50
|
return date;
|
|
34
51
|
}
|
|
52
|
+
// --- Session helpers (date-based) ---
|
|
53
|
+
static isSameDay(a, b) {
|
|
54
|
+
return (a.getFullYear() === b.getFullYear() &&
|
|
55
|
+
a.getMonth() === b.getMonth() &&
|
|
56
|
+
a.getDate() === b.getDate());
|
|
57
|
+
}
|
|
58
|
+
getSessionLessonsForDate(days, date) {
|
|
59
|
+
const day = days.find((d) => d.date && Schedule.isSameDay(d.date, date));
|
|
60
|
+
if (!day)
|
|
61
|
+
return [];
|
|
62
|
+
return slotsToLessons(day.slots, date);
|
|
63
|
+
}
|
|
64
|
+
// --- Public query methods ---
|
|
35
65
|
forDay(weekday, opts) {
|
|
36
|
-
const
|
|
37
|
-
const
|
|
66
|
+
const period = this.period;
|
|
67
|
+
const days = this.getDays(period);
|
|
68
|
+
if (isSessionPeriod(period)) {
|
|
69
|
+
// For sessions, return all entries on days matching this weekday
|
|
70
|
+
const lessons = [];
|
|
71
|
+
const dayName = getWeekdayName(weekday);
|
|
72
|
+
for (const d of days) {
|
|
73
|
+
if (d.weekday.toLowerCase() === dayName.toLowerCase() && d.date) {
|
|
74
|
+
lessons.push(...slotsToLessons(d.slots, d.date));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return lessons;
|
|
78
|
+
}
|
|
79
|
+
const slots = this.getSlotsForWeekday(weekday, days, opts);
|
|
80
|
+
const date = this.getDateForWeekday(weekday, period, opts?.week);
|
|
38
81
|
return slotsToLessons(slots, date);
|
|
39
82
|
}
|
|
40
83
|
forDate(date, opts) {
|
|
84
|
+
const period = getCurrentPeriod({ date });
|
|
85
|
+
const days = this.getDays(period);
|
|
86
|
+
if (isSessionPeriod(period)) {
|
|
87
|
+
const lessons = this.getSessionLessonsForDate(days, date);
|
|
88
|
+
if (lessons.length > 0)
|
|
89
|
+
return lessons;
|
|
90
|
+
}
|
|
91
|
+
// Try session periods for exact date match (sessions can have entries
|
|
92
|
+
// on dates that fall outside their "official" period boundaries)
|
|
93
|
+
for (const [p, d] of this.scheduleMap) {
|
|
94
|
+
if (p === period)
|
|
95
|
+
continue;
|
|
96
|
+
const match = d.find((day) => day.date && Schedule.isSameDay(day.date, date));
|
|
97
|
+
if (match)
|
|
98
|
+
return slotsToLessons(match.slots, date);
|
|
99
|
+
}
|
|
100
|
+
if (isSessionPeriod(period))
|
|
101
|
+
return [];
|
|
41
102
|
const weekday = date.getDay();
|
|
42
|
-
const week = getWeekNumber({ period
|
|
43
|
-
const slots = this.getSlotsForWeekday(weekday, {
|
|
103
|
+
const week = getWeekNumber({ period, date });
|
|
104
|
+
const slots = this.getSlotsForWeekday(weekday, days, {
|
|
44
105
|
subgroup: opts?.subgroup,
|
|
45
106
|
week,
|
|
46
107
|
});
|
|
47
108
|
return slotsToLessons(slots, date);
|
|
48
109
|
}
|
|
49
110
|
forWeek(week, opts) {
|
|
50
|
-
const
|
|
111
|
+
const period = this.period;
|
|
112
|
+
const days = this.getDays(period);
|
|
113
|
+
if (isSessionPeriod(period)) {
|
|
114
|
+
// For sessions, return all entries within this calendar week
|
|
115
|
+
const now = new Date();
|
|
116
|
+
const monday = getMonday(now);
|
|
117
|
+
const sunday = new Date(monday);
|
|
118
|
+
sunday.setDate(monday.getDate() + 6);
|
|
119
|
+
sunday.setHours(23, 59, 59, 999);
|
|
120
|
+
const lessons = [];
|
|
121
|
+
for (const d of days) {
|
|
122
|
+
if (d.date && d.date >= monday && d.date <= sunday) {
|
|
123
|
+
lessons.push(...slotsToLessons(d.slots, d.date));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return lessons;
|
|
127
|
+
}
|
|
128
|
+
const effectiveWeek = week ?? getWeekNumber({ period });
|
|
51
129
|
const semesterWeeks = getSemesterWeeks({
|
|
52
|
-
period
|
|
130
|
+
period,
|
|
53
131
|
weekCount: effectiveWeek,
|
|
54
132
|
});
|
|
55
133
|
const weekData = semesterWeeks.find((w) => w.week === effectiveWeek);
|
|
@@ -60,7 +138,7 @@ export class Schedule {
|
|
|
60
138
|
date.setDate(mondayDate.getDate() + i);
|
|
61
139
|
date.setHours(0, 0, 0, 0);
|
|
62
140
|
const weekday = i === 6 ? 0 : i + 1;
|
|
63
|
-
const slots = this.getSlotsForWeekday(weekday, {
|
|
141
|
+
const slots = this.getSlotsForWeekday(weekday, days, {
|
|
64
142
|
subgroup: opts?.subgroup,
|
|
65
143
|
week: effectiveWeek,
|
|
66
144
|
});
|
package/dist/tt/types.d.ts
CHANGED
package/dist/tt/utils.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { FullScheduleSlot, SemesterWeek, Lesson } from "./types.js";
|
|
2
2
|
import { Period } from "../common/types.js";
|
|
3
|
+
export declare function getCurrentPeriod(opts?: {
|
|
4
|
+
date?: Date;
|
|
5
|
+
}): Period;
|
|
6
|
+
export declare function isSessionPeriod(period: Period): boolean;
|
|
3
7
|
export declare function getWeekdayName(weekday: number): string;
|
|
4
8
|
export declare function getMonday(date: Date): Date;
|
|
5
9
|
/**
|
package/dist/tt/utils.js
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
export function getCurrentPeriod(opts) {
|
|
2
|
+
const date = opts?.date ?? new Date();
|
|
3
|
+
const month = date.getMonth();
|
|
4
|
+
const day = date.getDate();
|
|
5
|
+
// Dec 25+ and Jan → Winter session (зимняя сессия)
|
|
6
|
+
if (month === 0 || (month === 11 && day >= 25))
|
|
7
|
+
return 2 /* Period.WinterSession */;
|
|
8
|
+
// Feb–May → Spring semester (весенний семестр)
|
|
9
|
+
if (month >= 1 && month <= 4)
|
|
10
|
+
return 3 /* Period.SpringSemester */;
|
|
11
|
+
// Jun–Aug → Summer session (летняя сессия)
|
|
12
|
+
if (month >= 5 && month <= 7)
|
|
13
|
+
return 4 /* Period.SummerSession */;
|
|
14
|
+
// Sep – Dec 24 → Fall semester (осенний семестр)
|
|
15
|
+
return 1 /* Period.FallSemester */;
|
|
16
|
+
}
|
|
17
|
+
export function isSessionPeriod(period) {
|
|
18
|
+
return period === 2 /* Period.WinterSession */ || period === 4 /* Period.SummerSession */;
|
|
19
|
+
}
|
|
1
20
|
const WEEKDAY_NAMES = [
|
|
2
21
|
"Воскресенье",
|
|
3
22
|
"Понедельник",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chuvsu-js",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Node.js library for ChuvSU student portal (lk.chuvsu.ru) and schedule (tt.chuvsu.ru)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
".": {
|
|
10
10
|
"import": "./dist/index.js",
|
|
11
11
|
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./browser": {
|
|
14
|
+
"import": "./dist/browser.js",
|
|
15
|
+
"types": "./dist/browser.d.ts"
|
|
12
16
|
}
|
|
13
17
|
},
|
|
14
18
|
"files": [
|