From 3f90f2f626b6fec3c5564c7b0c7aa8914b8ef9a2 Mon Sep 17 00:00:00 2001 From: schneefux Date: Sun, 16 Sep 2018 15:04:33 +0200 Subject: Hardwire ICS and fix disappearing lectures --- src/index.ts | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) (limited to 'src/index.ts') diff --git a/src/index.ts b/src/index.ts index 3d7e588..bb3b6c7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,57 +1,63 @@ import * as moment from 'moment'; import * as BPromise from 'bluebird'; import * as fs from 'fs'; +import * as ical from 'ical-generator'; + +import {createHash} from 'crypto'; import {SplusApi} from './core/SplusApi'; -import {IEvent} from './core/IEvent'; import {ILecture} from './core/ILecture'; -import {IcalSink} from './sinks/IcalSink'; -import {GoogleCalendarSink} from './sinks/GoogleCalendarSink'; +const sha256 = (x) => createHash('sha256').update(x, 'utf8').digest('hex'); +const flatten = (arr) => [].concat(...arr); const range = (upper: number): number[] => Array.from(Array(upper), (x, i) => i); -const xprod = (arr1, arr2) => [].concat(...arr1.map((e1) => arr2.map((e2) => [e1, e2]))); +const xprod = (arr1, arr2) => flatten(arr1.map((e1) => arr2.map((e2) => [e1, e2]))); const isIncluded = (s1) => (s2) => s1.includes(s2); const anyTrue = (arr, cond) => arr.filter(cond).length > 0; +const allFalse = (arr, cond) => !anyTrue(arr, cond); +const uniqueByKey = (arrOfObj, key) => flatten((new Map(arrOfObj.map(obj => [obj[key], obj]))).values()); async function main(configPath) { const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); - const sink = config.icsPath == undefined? new GoogleCalendarSink() : new IcalSink(config.icsPath); - const baseDate = moment().startOf('week'); - await BPromise.map(xprod(config.courses, range(config.prefetchWeeks)), async ([course, weeksAhead]) => { - const unfilteredLectures = await SplusApi.getData(course, baseDate.weeks() + weeksAhead); - const lectures = unfilteredLectures.filter(lecture => anyTrue(config.titleWhitelist, isIncluded(lecture.title))); + const events = flatten(await BPromise.map(xprod(config.courses, range(config.prefetchWeeks)), async ([course, weeksAhead]) => { + const week = baseDate.clone().add(weeksAhead, 'weeks').weeks(); + const unfilteredLectures = await SplusApi.getData(course, week); + const lectures = unfilteredLectures.filter(lecture => allFalse(config.titleBlacklist, isIncluded(lecture.title))); + console.log(`fetching course ${course} week ${week}, ${lectures.length} lectures found`); - await BPromise.map(lectures, async (lec: ILecture) => { - let beginDate = baseDate.clone(); + return lectures.map((lec: ILecture) => { + const beginDate = baseDate.clone(); beginDate.add(moment.duration({ days: lec.day + 1, // for moment: 1 = Monday hours: lec.begin, weeks: weeksAhead, })); - let endDate = baseDate.clone(); + const endDate = baseDate.clone(); endDate.add(moment.duration({ days: lec.day + 1, hours: lec.end, weeks: weeksAhead, })); - const event: IEvent = { + + const uid = sha256(JSON.stringify({ lec, beginDate, endDate })).substr(0, 16); + return { + uid, + start: beginDate.toDate(), + end: endDate.toDate(), + timestamp: moment().toDate(), summary: lec.title, description: lec.lecturer + (lec.info !== '' ? ' - ' : '') + lec.info, location: lec.room, - start: beginDate.toDate(), - end: endDate.toDate(), }; - - await sink.createEvent(event); - - console.log(lec.title, beginDate.toISOString(), endDate.toISOString()); }); - }); + }, { concurrency: 1 })); // splus session breaks when sending multiple concurrent calls - await sink.commit(); + // ref. https://www.npmjs.com/package/ical-generator + const cal = ical({ events: uniqueByKey(events, 'uid') }).toString(); + fs.writeFileSync(config.icsPath, cal.toString()); } main(process.argv[2] || './config-example.json').catch(console.log); -- cgit v1.3.1