summaryrefslogtreecommitdiff
path: root/SplusParser.ts
diff options
context:
space:
mode:
authorThunderbolt <git@tforge.de>2018-04-26 10:09:34 +0200
committerThunderbolt <git@tforge.de>2018-04-26 10:09:34 +0200
commita439d29d8ff0bbee2d7c92c7594729c13c87baf8 (patch)
tree10f5bbdc749bbaefffb0c3fb5fb0a5354cc40bcd /SplusParser.ts
downloadsplus-a439d29d8ff0bbee2d7c92c7594729c13c87baf8.tar.gz
splus-a439d29d8ff0bbee2d7c92c7594729c13c87baf8.zip
Initial commit
Diffstat (limited to 'SplusParser.ts')
-rw-r--r--SplusParser.ts160
1 files changed, 160 insertions, 0 deletions
diff --git a/SplusParser.ts b/SplusParser.ts
new file mode 100644
index 0000000..be693fd
--- /dev/null
+++ b/SplusParser.ts
@@ -0,0 +1,160 @@
+import {load} from 'cheerio';
+
+interface IBlock {
+ title: string;
+ durationHours: number;
+ durationSlots: number;
+ info: string;
+ room: string;
+ lecturer: string
+}
+
+export interface ILecture {
+ title: string;
+ day: number;
+ begin: number;
+ end: number;
+ info: string;
+ room: string,
+ lecturer: string;
+}
+
+export class SplusParser {
+ private readonly startHour = 7;
+
+ private readonly $: CheerioStatic;
+ private readonly $table: Cheerio;
+ private readonly $rows: Cheerio;
+
+ private colWidths: number[] = [];
+ private colBlocked: number[] = [];
+
+ private blocks: IBlock[][][] = [];
+
+ constructor(data: string) {
+ this.$ = load(data);
+
+ this.$table = this.$(this.$('table.grid-border-args')[0]);
+ this.$rows = this.$table.find('> tbody > tr');
+
+ this.parseColWidths();
+ this.parseTable();
+ }
+
+ getLectures(filter?: (lecture: ILecture) => boolean): ILecture[] {
+ let lectures: ILecture[] = [];
+
+ for (let i = 0; i < this.blocks.length; i++) {
+ const begin = this.startHour + i * 0.25;
+
+ const slot = this.blocks[i];
+ for (let j = 0; j < slot.length; j++) {
+ const day = slot[j];
+ for (let k = 0; k < day.length; k++) {
+ const block = day[k];
+
+ const lecture = {
+ title: block.title,
+ day: j,
+ begin: begin,
+ end: begin + block.durationHours,
+ info: block.info,
+ room: block.room,
+ lecturer: block.lecturer
+ };
+
+ if(!filter || filter(lecture)) {
+ lectures.push(lecture);
+ }
+ }
+ }
+ }
+
+ return lectures;
+ }
+
+ private getDay(col: number) {
+ return this.colWidths.findIndex(width => (col -= width) < 0);
+ }
+
+ private parseColWidths() {
+ const $cols = this.$(this.$rows[0]).find('td:not(:first-child)');
+
+ for (let i = 0; i < $cols.length; i++) {
+ const $col = this.$($cols[i]);
+ this.colWidths[i] = parseInt($col.attr('colspan'));
+ }
+
+ let index = 0;
+ for (let i = 0; i < this.colWidths.length; i++) {
+ for (let j = 0; j < this.colWidths[i]; i++) {
+ this.colBlocked[index++] = 0;
+ }
+ }
+ }
+
+ private parseTable() {
+ for (let i = 0; i < this.$rows.length - 1; i++) {
+ // i + 1 to skip the columns row
+ const $row = this.$(this.$rows[i + 1]);
+
+ this.colBlocked = this.colBlocked.map(v => v > 0 ? v - 1 : 0);
+
+ this.blocks.push(this.parseRow($row));
+ }
+ }
+
+ private parseRow($row: Cheerio) {
+ const $cols = $row.find('> td:not(:first-child)');
+ const blocks: IBlock[][] = [];
+
+ let offset = 0;
+ for (let i = 0; i < $cols.length; i++) {
+ while (this.colBlocked[i + offset] > 0) {
+ const day = this.getDay(i + offset);
+ if (blocks[day] === undefined) {
+ blocks[day] = [];
+ }
+
+ offset++;
+ }
+
+ const day = this.getDay(i + offset);
+ if (blocks[day] === undefined) {
+ blocks[day] = [];
+ }
+
+ const $c = this.$($cols[i]);
+ if ($c.hasClass('object-cell-border')) {
+ const block = this.parseBlock($c);
+ blocks[day].push(block);
+
+ this.colBlocked[i + offset] = block.durationSlots;
+ }
+ }
+
+ return blocks;
+ }
+
+ private parseBlock($block: Cheerio): IBlock {
+ const $tblTitle = $block.find('table:nth-child(1)');
+ const $tblInfo = $block.find('table:nth-child(2)');
+ const $tblLocation = $block.find('table:nth-child(3)');
+
+ const $tdRoom = $tblLocation.find('td:nth-child(1)');
+ const $tdLecturer = $tblLocation.find('td:nth-child(2)');
+
+ // Remove the Modulhandbuch "mhb" link
+ $tblTitle.find('br + strong').remove();
+
+ const slots = parseInt($block.attr('rowspan'));
+ return {
+ title: $tblTitle.text().trim(),
+ durationHours: slots / 4,
+ durationSlots: slots,
+ info: $tblInfo.text().trim(),
+ room: $tdRoom.text().trim(),
+ lecturer: $tdLecturer.text().trim()
+ };
+ }
+}