From fd500ac41170521a975c06e6c8a1d0b0358c020d Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Wed, 20 Apr 2016 14:39:38 +0200 Subject: [PATCH 1/2] Allow the subscription to multiple news feeds in one newsfeed instance. --- config/config.js.sample | 8 +- modules/default/newsfeed/README.md | 62 +++++++++++- modules/default/newsfeed/fetcher.js | 12 ++- modules/default/newsfeed/newsfeed.js | 128 ++++++++++++++++++------ modules/default/newsfeed/node_helper.js | 27 +++-- 5 files changed, 192 insertions(+), 45 deletions(-) diff --git a/config/config.js.sample b/config/config.js.sample index 084bf01788..99ab2ead2f 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -56,7 +56,13 @@ var config = { module: 'newsfeed', position: 'bottom_bar', config: { - feedUrl: 'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml', + feeds: [ + { + title: "New York Times", + url: "http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml" + } + ], + showSourceTitle: true, showPublishDate: true } }, diff --git a/modules/default/newsfeed/README.md b/modules/default/newsfeed/README.md index ae6ee06138..936e5c2cbf 100644 --- a/modules/default/newsfeed/README.md +++ b/modules/default/newsfeed/README.md @@ -14,6 +14,18 @@ modules: [ // The config property is optional. // If no config is set, an example calendar is shown. // See 'Configuration options' for more information. + + feeds: [ + { + title: "New York Times", + url: "http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml", + }, + { + title: "BBC + ", + url: "http://feeds.bbci.co.uk/news/video_and_audio/news_front_page/rss.xml?edition=uk", + }, + ] } } ] @@ -35,12 +47,25 @@ The following properties can be configured: - feedUrl - The url of the feed used for the headlines.
-
Default value: 'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml' + feeds + An array of feed urls that will be used as source.
+ More info about this object can be found below. +
Default value: [ + { + title: "New York Times", + url: "http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml", + } + ] + + showSourceTitle + Display the title of the source.
+
Possible values: true or false +
Default value: true + + showPublishDate Display the publish date of an headline.
@@ -77,9 +102,40 @@ The following properties can be configured:
Default value: 2000 (2.5 seconds) + + + + + +The `feeds` property contains an array with multiple objects. These objects have the following properties: + + + + + + + + + + + + + + + + + + + + diff --git a/modules/default/newsfeed/fetcher.js b/modules/default/newsfeed/fetcher.js index 3208145760..b155a80c8e 100644 --- a/modules/default/newsfeed/fetcher.js +++ b/modules/default/newsfeed/fetcher.js @@ -46,11 +46,13 @@ var Fetcher = function(url, reloadInterval, encoding) { var regex = /(<([^>]+)>)/ig; description = description.replace(regex, ""); - items.push({ - title: item.title, - description: description, - pubdate: item.pubdate, - }); + if (item.title && description && item.pubdate) { + items.push({ + title: item.title, + description: description, + pubdate: item.pubdate, + }); + } }); parser.on("end", function() { diff --git a/modules/default/newsfeed/newsfeed.js b/modules/default/newsfeed/newsfeed.js index ef0073e6a5..5d27a50a20 100644 --- a/modules/default/newsfeed/newsfeed.js +++ b/modules/default/newsfeed/newsfeed.js @@ -11,13 +11,19 @@ Module.register("newsfeed",{ // Default module config. defaults: { - feedUrl: "http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml", + feeds: [ + { + title: "New York Times", + url: "http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml", + encoding: "UTF-8" //ISO-8859-1 + } + ], + showSourceTitle: true, showPublishDate: true, showDescription: false, reloadInterval: 5 * 60 * 1000, // every 5 minutes updateInterval: 10 * 1000, animationSpeed: 2.5 * 1000, - encoding: "UTF-8" //ISO-8859-1 }, // Define required scripts. @@ -36,21 +42,20 @@ Module.register("newsfeed",{ this.loaded = false; this.activeItem = 0; - this.fetchNews(); + this.registerFeeds(); }, // Override socket notification handler. socketNotificationReceived: function(notification, payload) { if (notification === "NEWS_ITEMS") { - if (payload.url === this.config.feedUrl) { - this.newsItems = payload.items; - if (!this.loaded) { - this.scheduleUpdateInterval(); - } + this.generateFeed(payload); - this.loaded = true; + if (!this.loaded) { + this.scheduleUpdateInterval(); } + + this.loaded = true; } }, @@ -58,12 +63,11 @@ Module.register("newsfeed",{ getDom: function() { var wrapper = document.createElement("div"); - // wrapper.className = "small"; - // for (var n in this.newsItems) { - // var item = this.newsItems[n]; - // wrapper.innerHTML += item.title + '
'; - // } - // return wrapper; + if (this.config.feedUrl) { + wrapper.className = "small bright"; + wrapper.innerHTML = "The configuration options for the newsfeed module have changed.
Please check the documentation."; + return wrapper; + } if (this.activeItem >= this.newsItems.length) { this.activeItem = 0; @@ -71,12 +75,16 @@ Module.register("newsfeed",{ if (this.newsItems.length > 0) { - if (this.config.showPublishDate) { - var timestamp = document.createElement("div"); - timestamp.className = "light small dimmed"; - timestamp.innerHTML = this.capitalizeFirstLetter(moment(new Date(this.newsItems[this.activeItem].pubdate)).fromNow() + ":"); - //timestamp.innerHTML = this.config.feedUrl; - wrapper.appendChild(timestamp); + if (this.config.showSourceTitle || this.config.showPublishDate) { + var sourceAndTimestamp = document.createElement("div"); + sourceAndTimestamp.className = "light small dimmed"; + + if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== '') sourceAndTimestamp.innerHTML = this.newsItems[this.activeItem].sourceTitle; + if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== '' && this.config.showPublishDate) sourceAndTimestamp.innerHTML += ', '; + if (this.config.showPublishDate) sourceAndTimestamp.innerHTML += moment(new Date(this.newsItems[this.activeItem].pubdate)).fromNow(); + if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== '' || this.config.showPublishDate) sourceAndTimestamp.innerHTML += ':'; + + wrapper.appendChild(sourceAndTimestamp); } var title = document.createElement("div"); @@ -99,16 +107,78 @@ Module.register("newsfeed",{ return wrapper; }, - /* fetchNews(compliments) - * Requests new data from news proxy. + /* registerFeeds() + * registers the feeds to be used by the backend. */ - fetchNews: function() { - Log.log("Add news feed to fetcher: " + this.config.feedUrl); - this.sendSocketNotification("ADD_FEED", { - url: this.config.feedUrl, - reloadInterval: this.config.reloadInterval, - encoding: this.config.encoding + + registerFeeds: function() { + for (var f in this.config.feeds) { + var feed = this.config.feeds[f]; + this.sendSocketNotification("ADD_FEED", { + feed: feed, + config: this.config + }); + } + }, + + /* registerFeeds() + * Generate an ordered list of items for this configured module. + * + * attribute feeds object - An object with feeds returned by the nod helper. + */ + generateFeed: function(feeds) { + var newsItems = []; + for (var feed in feeds) { + var feedItems = feeds[feed]; + if (this.subscribedToFeed(feed)) { + for (var i in feedItems) { + var item = feedItems[i]; + item.sourceTitle = this.titleForFeed(feed); + newsItems.push(item); + } + } + } + newsItems.sort(function(a,b) { + var dateA = new Date(a.pubdate); + var dateB = new Date(b.pubdate); + return dateB - dateA; }); + + this.newsItems = newsItems; + }, + + /* subscribedToFeed(feedUrl) + * Check if this module is configured to show this feed. + * + * attribute feedUrl string - Url of the feed to check. + * + * returns bool + */ + subscribedToFeed: function(feedUrl) { + for (var f in this.config.feeds) { + var feed = this.config.feeds[f]; + if (feed.url === feedUrl) { + return true; + } + } + return false; + }, + + /* subscribedToFeed(feedUrl) + * Returns title for a specific feed Url. + * + * attribute feedUrl string - Url of the feed to check. + * + * returns string + */ + titleForFeed: function(feedUrl) { + for (var f in this.config.feeds) { + var feed = this.config.feeds[f]; + if (feed.url === feedUrl) { + return feed.title || ''; + } + } + return ''; }, /* scheduleUpdateInterval() diff --git a/modules/default/newsfeed/node_helper.js b/modules/default/newsfeed/node_helper.js index 4233ead38a..82f1c19e56 100644 --- a/modules/default/newsfeed/node_helper.js +++ b/modules/default/newsfeed/node_helper.js @@ -13,14 +13,14 @@ module.exports = NodeHelper.create({ // Subclass start method. start: function() { console.log("Starting module: " + this.name); - this.fetchers = []; }, // Subclass socketNotificationReceived received. socketNotificationReceived: function(notification, payload) { if (notification === "ADD_FEED") { - this.createFetcher(payload.url, payload.reloadInterval, payload.encoding); + this.createFetcher(payload.feed, payload.config); + return; } }, @@ -32,9 +32,13 @@ module.exports = NodeHelper.create({ * attribute reloadInterval number - Reload interval in milliseconds. */ - createFetcher: function(url, reloadInterval, encoding) { + createFetcher: function(feed, config) { var self = this; + var url = feed.url || ''; + var encoding = feed.encoding || 'UTF-8'; + var reloadInterval = config.reloadInterval || 5 * 60 * 1000; + if (!validUrl.isUri(url)) { self.sendSocketNotification("INCORRECT_URL", url); return; @@ -46,10 +50,7 @@ module.exports = NodeHelper.create({ fetcher = new Fetcher(url, reloadInterval, encoding); fetcher.onReceive(function(fetcher) { - self.sendSocketNotification("NEWS_ITEMS", { - url: fetcher.url(), - items: fetcher.items() - }); + self.broadcastFeeds(); }); fetcher.onError(function(fetcher, error) { @@ -68,5 +69,17 @@ module.exports = NodeHelper.create({ } fetcher.startFetch(); + }, + + /* broadcastFeeds() + * Creates an object with all feed items of the different registered feeds, + * and broadcasts these using sendSocketNotification. + */ + broadcastFeeds: function() { + var feeds = {}; + for (var f in this.fetchers) { + feeds[f] = this.fetchers[f].items(); + } + this.sendSocketNotification("NEWS_ITEMS", feeds); } }); From fa38ad3a74e08bee5b140c397aef4786d541d7d5 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Wed, 20 Apr 2016 15:19:36 +0200 Subject: [PATCH 2/2] Fix for #207 --- modules/default/calendar/calendarfetcher.js | 24 ++++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js index 96f5588e12..771ee5b3f2 100644 --- a/modules/default/calendar/calendarfetcher.js +++ b/modules/default/calendar/calendarfetcher.js @@ -43,8 +43,6 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe var today = moment().startOf("day").toDate(); var future = moment().startOf("day").add(maximumNumberOfDays, "days").subtract(1,"seconds").toDate(); // Subtract 1 second so that events that start on the middle of the night will not repeat. - - // FIXME: // Ugly fix to solve the facebook birthday issue. // Otherwise, the recurring events only show the birthday for next year. @@ -57,6 +55,8 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe if (event.type === "VEVENT") { + //console.log(event); + var startDate = (event.start.length === 8) ? moment(event.start, "YYYYMMDD") : moment(new Date(event.start)); var endDate; if (typeof event.end !== "undefined") { @@ -65,6 +65,9 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe endDate = startDate; } + // calculate the duration f the event for use with recurring events. + var duration = parseInt(endDate.format("x")) - parseInt(startDate.format("x")); + if (event.start.length === 8) { startDate = startDate.startOf("day"); } @@ -75,12 +78,15 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe 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"), - endDate: endDate.format("x"), - fullDayEvent: isFullDayEvent(event) - }); + endDate = moment(parseInt(startDate.format("x")) + duration, 'x'); + if (endDate.format("x") > now) { + newEvents.push({ + title: (typeof event.summary.val !== "undefined") ? event.summary.val : event.summary, + startDate: startDate.format("x"), + endDate: endDate.format("x"), + fullDayEvent: isFullDayEvent(event) + }); + } } } else { // console.log("Single event ..."); @@ -119,6 +125,8 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe return a.startDate - b.startDate; }); + //console.log(newEvents); + events = newEvents.slice(0, maximumEntries); self.broadcastEvents();
OptionDescription
titleThe name of the feed source to be displayed above the news items.
+
This property is optional. +
urlThe url of the feed used for the headlines.
+
Example: 'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml' +
encoding The encoding of the news feed.
+
This property is optional.
Possible values:'UTF-8', 'ISO-8859-1', etc ...
Default value: 'UTF-8'