Skip to content
Snippets Groups Projects
calendar.js 4.34 KiB
Newer Older
Kasalehlia's avatar
Kasalehlia committed
var httpreq = require('httpreq');
var ical = require('ical.js');
var Mustache = require('mustache');
var time = require('time');
Kasalehlia's avatar
Kasalehlia committed

var URL = 'https://stratum0.org/kalender/termine.ics';
var TEMPLATE = '';
require('fs').readFile('modules/calendar/template.mustache', 'utf-8', function (err, data) {
    TEMPLATE = data;
});
var CALENDAR;

var TZOFFSET = new time.Date().getTimezoneOffset()*60;

Kasalehlia's avatar
Kasalehlia committed
function pad(n, width, z) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}

function parseDate(s) {
    var i = parseInt;
    if (s.indexOf('T') > -1) {
        return new Date(i(s.substr(0,4)), i(s.substr(4,2))-1, i(s.substr(6,2)),
            i(s.substr(9,2)), i(s.substr(11,2)), i(s.substr(13,2)));
    } else {
        return new Date(i(s.substr(0,4)), i(s.substr(4,2))-1, i(s.substr(6,2)));
    }
}

function getData(count, cb) {
    httpreq.get(URL, function (err, res) {
        var ics = res.body.replace(/[0-9]{8}T[0-9]{6}/g, '$&Z');
        var cal = new ical.Component(ical.parse(ics));
        var rawEvents = cal.getAllSubcomponents('vevent').map(function (raw) {
            return new ical.Event(raw);
        });
        var events = [];
        var ev, p = function (p) {return ev.component.getFirstPropertyValue(p);};
        for (var i in rawEvents) {
            ev = rawEvents[i];
            if (ev.isRecurring()) {
                var iter = ev.iterator();
                var duration = p('dtend').toUnixTime()-p('dtstart').toUnixTime();
                for (var i = 0; i < 100; i++) {
                    var next = iter.next();
                    if (next === undefined) {break;}
                    var start = next.toUnixTime()+TZOFFSET;
Kasalehlia's avatar
Kasalehlia committed
                    events.push({
                        title: p('summary'),
                        start: start,
                        end: start + duration
                    });
                }
            } else {
                events.push({
                    title: p('summary'),
                    start: p('dtstart').toUnixTime()+TZOFFSET,
                    end: p('dtend').toUnixTime()+TZOFFSET,
Kasalehlia's avatar
Kasalehlia committed
                });
            }
        }
        events.sort(function (a, b) {
            return a.start - b.start;
        });
        var threshold = Date.now()/1000 - 5*60*60; //show 5 hours ago
        var i;
        for (i in events) {
            if (events[i].end > threshold) {
                i = parseInt(i);
                break;
            }
        }
        var now = new Date();
        cb(events.slice(i, i+count).map(function (ev) {
            var start = new Date(ev.start*1000);
            if (start.getMonth() == now.getMonth() && start.getDate() == now.getDate()) {
                ev.startRendered = pad(start.getHours(),2)+':'+pad(start.getMinutes(),2);
            } else {
                ev.startRendered = DOW[start.getDay()]+', '+pad(start.getDate(),2)
Kasalehlia's avatar
Kasalehlia committed
                    +'.'+pad(start.getMonth()+1,2)+'. '+pad(start.getHours(),2)
Kasalehlia's avatar
Kasalehlia committed
                    +':'+pad(start.getMinutes(),2);
            }
            var end = new Date(ev.end*1000);
            if (ev.end - ev.start >= 60*60*24) {
                ev.endRendered = DOW[end.getDay()]+' '+pad(end.getHours(),2)
                    +':'+pad(end.getMinutes(),2);
            } else {
                ev.endRendered = pad(end.getHours(),2)+':'+pad(end.getMinutes(),2);
            }
            var dur = Math.floor((ev.end-ev.start)/60);
            ev.duration = pad(Math.floor(dur/60),2)+':'+pad((dur%60),2)
            if (start.getTime() < now.getTime()) {
                if (end.getTime() < now.getTime()) {
                    ev.past = true;
                } else {
                    ev.now = true;
                }
            }
            return ev
        }));
    });
}

module.exports = function (io) {
Kasalehlia's avatar
Kasalehlia committed
    function update(firstRunCallback) {
        getData(8, function (data) {
            CALENDAR = data;
            io.emit('calendar', Mustache.render(TEMPLATE, CALENDAR));
Kasalehlia's avatar
Kasalehlia committed
            if (firstRunCallback) {
                firstRunCallback()
                firstRunCallback = null;
            }
Kasalehlia's avatar
Kasalehlia committed
    update(function () {
        var pushToClients = function (sock) {
            sock.emit('calendar', Mustache.render(TEMPLATE, CALENDAR));
Kasalehlia's avatar
Kasalehlia committed
        };
Kasalehlia's avatar
Kasalehlia committed
        io.on('connect', pushToClients);
        pushToClients(io);
    });
    setInterval(update, 600000);
Kasalehlia's avatar
Kasalehlia committed
}