diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js new file mode 100644 index 00000000..4007bc9a --- /dev/null +++ b/modules/default/calendar/calendarfetcher.js @@ -0,0 +1,187 @@ +/* Magic Mirror + * Node Helper: Calendar - CalendarFetcher + * + * By Michael Teeuw http://michaelteeuw.nl + * MIT Licensed. + */ + +var ical = require("ical"); +var moment = require("moment"); + +var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumberOfDays) { + var self = this; + + var reloadTimer = null; + var events = []; + + var fetchFailedCallback = function() {}; + var eventsReceivedCallback = function() {}; + + /* fetchCalendar() + * Initiates calendar fetch. + */ + var fetchCalendar = function() { + + clearTimeout(reloadTimer); + reloadTimer = null; + + ical.fromURL(url, {}, function(err, data) { + if (err) { + fetchFailedCallback(self, err); + scheduleTimer(); + return; + } + + //console.log(data); + newEvents = []; + + var limitFunction = function(date, i) {return i < maximumEntries;}; + + for (var e in data) { + var event = data[e]; + var now = new Date(); + var today = moment().startOf("day").toDate(); + var future = moment().startOf("day").add(maximumNumberOfDays, "days").toDate(); + + + + // FIXME: + // Ugly fix to solve the facebook birthday issue. + // Otherwise, the recurring events only show the birthday for next year. + var isFacebookBirthday = false; + if (typeof event.uid !== "undefined") { + if (event.uid.indexOf("@facebook.com") !== -1) { + isFacebookBirthday = true; + } + } + + if (event.type === "VEVENT") { + + var startDate = (event.start.length === 8) ? moment(event.start, "YYYYMMDD") : moment(new Date(event.start)); + if (event.start.length === 8) { + startDate = startDate.startOf("day"); + } + + if (typeof event.rrule != "undefined" && !isFacebookBirthday) { + var rule = event.rrule; + // console.log("Repeating event ..."); + + // Check if the timeset is set to this current time. + // If so, the RRULE line does not contain any BYHOUR, BYMINUTE, BYSECOND params. + // This causes the times of the recurring event to be incorrect. + // By adjusting the timeset property, this issue is solved. + + + if (rule.timeset[0].hour == now.getHours(), + rule.timeset[0].minute == now.getMinutes(), + rule.timeset[0].second == now.getSeconds()) { + + rule.timeset[0].hour = startDate.format("H"); + rule.timeset[0].minute = startDate.format("m"); + rule.timeset[0].second = startDate.format("s"); + } + + var dates = rule.between(today, future, true, limitFunction); + + for (var d in dates) { + startDate = moment(new Date(dates[d])); + newEvents.push({ + title: (typeof event.summary.val !== "undefined") ? event.summary.val : event.summary, + startDate: startDate.format("x"), + fullDayEvent: (event.start.length === 8) + + }); + } + } else { + // console.log("Single event ..."); + // Single event. + if (startDate >= today && startDate <= future) { + newEvents.push({ + title: (typeof event.summary.val !== "undefined") ? event.summary.val : event.summary, + startDate: startDate.format("x"), + fullDayEvent: (event.start.length === 8) + }); + } + } + } + } + + newEvents.sort(function(a, b) { + return a.startDate - b.startDate; + }); + + events = newEvents.slice(0, maximumEntries); + + self.broadcastEvents(); + scheduleTimer(); + }); + }; + + /* scheduleTimer() + * Schedule the timer for the next update. + */ + var scheduleTimer = function() { + //console.log('Schedule update timer.'); + clearTimeout(reloadTimer); + reloadTimer = setTimeout(function() { + fetchCalendar(); + }, reloadInterval); + }; + + /* public methods */ + + /* startFetch() + * Initiate fetchCalendar(); + */ + this.startFetch = function() { + fetchCalendar(); + }; + + /* broadcastItems() + * Broadcast the exsisting events. + */ + this.broadcastEvents = function() { + //console.log('Broadcasting ' + events.length + ' events.'); + eventsReceivedCallback(self); + }; + + /* onReceive(callback) + * Sets the on success callback + * + * argument callback function - The on success callback. + */ + this.onReceive = function(callback) { + eventsReceivedCallback = callback; + }; + + /* onError(callback) + * Sets the on error callback + * + * argument callback function - The on error callback. + */ + this.onError = function(callback) { + fetchFailedCallback = callback; + }; + + /* url() + * Returns the url of this fetcher. + * + * return string - The url of this fetcher. + */ + this.url = function() { + return url; + }; + + /* events() + * Returns current available events for this fetcher. + * + * return array - The current available events for this fetcher. + */ + this.events = function() { + return events; + }; + +}; + + +module.exports = CalendarFetcher; \ No newline at end of file diff --git a/modules/default/calendar/debug.js b/modules/default/calendar/debug.js new file mode 100644 index 00000000..22d23066 --- /dev/null +++ b/modules/default/calendar/debug.js @@ -0,0 +1,33 @@ +/* CalendarFetcher Tester + * use this script with `node debug.js` to test the fetcher without the need + * of starting the MagicMirror core. Adjust the values below to your desire. + * + * By Michael Teeuw http://michaelteeuw.nl + * MIT Licensed. + */ + +var CalendarFetcher = require("./calendarfetcher.js"); + +var url = 'https://github.com/MichMich/MagicMirror/files/217285/reachcalendar.txt'; +var fetchInterval = 60 * 60 * 1000; +var maximumEntries = 10; +var maximumNumberOfDays = 365; + +console.log('Create fetcher ...'); + +fetcher = new CalendarFetcher(url, fetchInterval, maximumEntries, maximumNumberOfDays); + +fetcher.onReceive(function(fetcher) { + console.log(fetcher.events()); + console.log('------------------------------------------------------------'); +}); + +fetcher.onError(function(fetcher, error) { + console.log("Fetcher error:"); + console.log(error); +}); + +fetcher.startFetch(); + +console.log('Create fetcher done! '); + diff --git a/modules/default/calendar/node_helper.js b/modules/default/calendar/node_helper.js index 89df6ec5..1d558d29 100644 --- a/modules/default/calendar/node_helper.js +++ b/modules/default/calendar/node_helper.js @@ -6,179 +6,8 @@ */ var NodeHelper = require("node_helper"); -var ical = require("ical"); -var moment = require("moment"); var validUrl = require("valid-url"); - -var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumberOfDays) { - var self = this; - - var reloadTimer = null; - var events = []; - - var fetchFailedCallback = function() {}; - var eventsReceivedCallback = function() {}; - - /* fetchCalendar() - * Initiates calendar fetch. - */ - var fetchCalendar = function() { - - clearTimeout(reloadTimer); - reloadTimer = null; - - ical.fromURL(url, {}, function(err, data) { - if (err) { - fetchFailedCallback(self, err); - scheduleTimer(); - return; - } - - //console.log(data); - newEvents = []; - - var limitFunction = function(date, i) {return i < maximumEntries;}; - - for (var e in data) { - var event = data[e]; - var now = new Date(); - var today = moment().startOf("day"); - - //console.log(event); - - // FIXME: - // Ugly fix to solve the facebook birthday issue. - // Otherwise, the recurring events only show the birthday for next year. - var isFacebookBirthday = false; - if (typeof event.uid !== "undefined") { - if (event.uid.indexOf("@facebook.com") !== -1) { - isFacebookBirthday = true; - } - } - - if (event.type === "VEVENT") { - var startDate = (event.start.length === 8) ? moment(event.start, "YYYYMMDD") : moment(new Date(event.start)); - if (event.start.length === 8) { - startDate = startDate.startOf("day"); - } - - if (typeof event.rrule != "undefined" && !isFacebookBirthday) { - var rule = event.rrule; - - // Check if the timeset is set to this current time. - // If so, the RRULE line does not contain any BYHOUR, BYMINUTE, BYSECOND params. - // This causes the times of the recurring event to be incorrect. - // By adjusting the timeset property, this issue is solved. - - if (rule.timeset[0].hour == now.getHours(), - rule.timeset[0].minute == now.getMinutes(), - rule.timeset[0].second == now.getSeconds()) { - - rule.timeset[0].hour = startDate.format("H"); - rule.timeset[0].minute = startDate.format("m"); - rule.timeset[0].second = startDate.format("s"); - } - - var dates = rule.between(today, today.add(maximumNumberOfDays, "days") , true, limitFunction); - //console.log(dates); - for (var d in dates) { - startDate = moment(new Date(dates[d])); - newEvents.push({ - title: (typeof event.summary.val !== "undefined") ? event.summary.val : event.summary, - startDate: startDate.format("x"), - fullDayEvent: (event.start.length === 8) - - }); - } - } else { - // Single event. - if (startDate >= today && startDate <= today.add(maximumNumberOfDays, "days")) { - newEvents.push({ - title: (typeof event.summary.val !== "undefined") ? event.summary.val : event.summary, - startDate: startDate.format("x"), - fullDayEvent: (event.start.length === 8) - }); - } - } - } - } - - newEvents.sort(function(a, b) { - return a.startDate - b.startDate; - }); - - events = newEvents.slice(0, maximumEntries); - - self.broadcastEvents(); - scheduleTimer(); - }); - }; - - /* scheduleTimer() - * Schedule the timer for the next update. - */ - var scheduleTimer = function() { - //console.log('Schedule update timer.'); - clearTimeout(reloadTimer); - reloadTimer = setTimeout(function() { - fetchCalendar(); - }, reloadInterval); - }; - - /* public methods */ - - /* startFetch() - * Initiate fetchCalendar(); - */ - this.startFetch = function() { - fetchCalendar(); - }; - - /* broadcastItems() - * Broadcast the exsisting events. - */ - this.broadcastEvents = function() { - //console.log('Broadcasting ' + events.length + ' events.'); - eventsReceivedCallback(self); - }; - - /* onReceive(callback) - * Sets the on success callback - * - * argument callback function - The on success callback. - */ - this.onReceive = function(callback) { - eventsReceivedCallback = callback; - }; - - /* onError(callback) - * Sets the on error callback - * - * argument callback function - The on error callback. - */ - this.onError = function(callback) { - fetchFailedCallback = callback; - }; - - /* url() - * Returns the url of this fetcher. - * - * return string - The url of this fetcher. - */ - this.url = function() { - return url; - }; - - /* events() - * Returns current available events for this fetcher. - * - * return array - The current available events for this fetcher. - */ - this.events = function() { - return events; - }; - -}; +var CalendarFetcher = require("./calendarfetcher.js"); module.exports = NodeHelper.create({ // Override start method.