From a105b34ab53963ab651810f33caa2ee51869b1c7 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 1 Jun 2012 19:29:08 +0200 Subject: o Initial import. --- lib/arktekk-bot.js | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/irc.js | 12 ++++ 2 files changed, 177 insertions(+) create mode 100644 lib/arktekk-bot.js create mode 100644 lib/irc.js (limited to 'lib') diff --git a/lib/arktekk-bot.js b/lib/arktekk-bot.js new file mode 100644 index 0000000..3a00c7f --- /dev/null +++ b/lib/arktekk-bot.js @@ -0,0 +1,165 @@ +/* + * 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. + */ + +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/lib/irc.js b/lib/irc.js new file mode 100644 index 0000000..935d2b3 --- /dev/null +++ b/lib/irc.js @@ -0,0 +1,12 @@ +module.exports.nickGenerator = function(nick) { + var nickCount = 0; + var nickAdditions = [ '', '^', '-', '_', '\\', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]; + + return function() { + if (nickCount == nickAdditions.length) { + nickCount = 0; + } + + return nick + nickAdditions[nickCount++]; + } +} -- cgit v1.2.3