summaryrefslogtreecommitdiff
path: root/atom-bot
diff options
context:
space:
mode:
Diffstat (limited to 'atom-bot')
-rw-r--r--atom-bot/index.js166
-rw-r--r--atom-bot/package.json27
2 files changed, 193 insertions, 0 deletions
diff --git a/atom-bot/index.js b/atom-bot/index.js
new file mode 100644
index 0000000..37d073c
--- /dev/null
+++ b/atom-bot/index.js
@@ -0,0 +1,166 @@
+/*
+ * Possible strategies for updating the topic:
+ *
+ * o Set the topic unconditionally when the feed changes. This makes
+ * it possible for users to change the topic and it won't be
+ * overridden until the feed changes.
+ *
+ * o Set the topic on any topic change (making the feed control the
+ * entire topic)
+ *
+ * o Support a delimiter so it can control only a part of the topic,
+ * like "<>". Example
+ *
+ * Next meeting, sat 1900 <> DATA FROM FEED.
+ *
+ * A regexp selecting the are to be updated might conver it.
+ *
+ * o If the bot changed the topic the last time, it's probably safe to
+ * just update it.
+ */
+
+require('tinycolor');
+var node_irc = require('../node_modules/node-irc/IRC.js')
+ , cron = require('cron').CronJob
+ , parser = require('blindparser')
+ , events = require('events')
+ , _ = require('underscore');
+
+var parserOptions = {};
+
+var config;
+var cronJobs = [];
+
+var state = {
+ channelTopic: undefined,
+ irc: undefined,
+ updatingFeed: false,
+ feeds: [],
+ newest: {
+ timestamp: 0,
+ text: undefined
+ }
+};
+module.exports.state = state;
+
+var eventEmitter = new events.EventEmitter;
+
+function startIrc() {
+ irc = new node_irc.IRC(config.host, config.port);
+ irc.on('raw', function(data) { console.log(data) });
+ irc.on('connected', function(server) {
+ console.log('Connected to ' + server);
+ irc.join(config.channel, function(error) {
+ irc.notice(config.channel, 'well hello yall');
+ });
+ });
+ irc.topic = function(channel, topic) {
+ irc._socket.write('topic ' + channel + ' :' + topic + '\r\n');
+ };
+
+ irc.on('topic', function(channel, topic) {
+ console.log("new topic: " + topic);
+ /* If we're not storing this, it is possible for people to set
+ * the topic after the bot has set it and it will persist (until
+ * next update from the feed).
+ topic = t;
+ */
+
+ state.channelTopic = topic;
+ });
+}
+
+function updateFeed(feedState) {
+ console.log("Fetching " + feedState.url);
+ if(feedState.updatingFeed)
+ console.log("Already working");
+ feedState.updatingFeed = true;
+
+ parser.parseURL(feedState.url, parserOptions, function(err, feed) {
+// console.log("Fetched " + feedState.url + ", status=" + (err ? "failure" : "success"));
+ if(err) {
+ console.log(err);
+ return;
+ }
+ var newest = processFeed(feed);
+ if(typeof newest == "object") {
+ eventEmitter.emit("feedChanged", feedState.url, newest);
+ }
+ feedState.updatingFeed = false;
+ });
+}
+
+function processFeed(feed) {
+ // Extracts the username from the feed.
+ // TODO: Use something better than blindparser to parse atom so that
+ // each entry has an author too to get the full name.
+ if(typeof feed.items[0] == "undefined") {
+ console.log("feed does not contain any items", feed);
+ return undefined;
+ }
+ var match = /^http:\/\/twitter.com\/([a-zA-Z0-9_]+)\/.*$/.exec(feed.items[0].link)
+ if(match.length != 2) {
+ return undefined;
+ }
+ return {
+ text: feed.items[0].title,
+ author: match[1],
+ timestamp: feed.items[0].date
+ };
+}
+module.exports.processFeed = processFeed;
+
+eventEmitter.on("feedChanged", function(url, newest) {
+ state.feeds[url] = newest;
+
+ if(state.newest.timestamp >= newest.timestamp) {
+// console.log("oold: " + newest.text);
+ return;
+ }
+
+ var text = newest.author + ": " + newest.text;
+ console.log("New topic", newest.timestamp, url, text);
+ state.newest = newest;
+ if(config.connect && state.topic != text) {
+ irc.topic(config.channel, text);
+ }
+});
+
+eventEmitter.on("configUpdated", function(c) {
+ setup();
+});
+
+function setup() {
+ console.log("Stopping " + cronJobs.length + " cron jobs");
+ _.each(cronJobs, function(job) { job.stop(); });
+ cronJobs = [];
+ _.each(config.feeds, function(feed) {
+ var state = {
+ url: feed,
+ updatingFeed: false,
+ last: undefined
+ };
+ var job = new cron("*/10 * * * *", function() {
+ updateFeed(state);
+ }, function() {}, true);
+ cronJobs.push(job);
+ });
+}
+
+function start(c) {
+ config = c;
+ startIrc();
+ setup();
+ if(config.connect) {
+ console.log('Connecting to ' + config.host + ':' + config.port);
+ irc.connect(config.nick);
+ } else {
+ console.log('Not connecting to IRC');
+ }
+}
+
+module.exports.start = start;
+
+module.exports.emit = function(config) {
+ eventEmitter.emit("configUpdated", config);
+}
diff --git a/atom-bot/package.json b/atom-bot/package.json
new file mode 100644
index 0000000..a060290
--- /dev/null
+++ b/atom-bot/package.json
@@ -0,0 +1,27 @@
+{
+ "author": {
+ "name": "Trygve Laugstøl",
+ "email": "trygvis@inamo.no",
+ "url": "https://github.com/trygvis"
+ },
+ "name": "atom-bot",
+ "description": "IRC Bot that changes topic to the latest <entry> in a set of atom feeds",
+ "keywords": [
+ "irc",
+ "chat"
+ ],
+ "version": "0.0.1",
+ "engines": {
+ "node": ">=0.6.18"
+ },
+ "dependencies": {
+ "tinycolor": "0.0.1",
+ "underscore": "1.3.3"
+ },
+ "licenses": [
+ {
+ "type": "Apache Software License, version 2",
+ "url": "http://apache.org/licenses/LICENSE-2.0"
+ }
+ ]
+}