From 18c5b3ceac115200f994c440b78ceccda9a9862d Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Mon, 4 Jun 2012 00:08:25 +0200 Subject: wip --- atom-bot/index.js | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++ atom-bot/package.json | 27 ++++++++ 2 files changed, 193 insertions(+) create mode 100644 atom-bot/index.js create mode 100644 atom-bot/package.json (limited to 'atom-bot') 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 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" + } + ] +} -- cgit v1.2.3