3
0
mirror of https://github.com/reality/dbot.git synced 2024-12-27 21:22:38 +01:00
dbot/modules/reddit/reddit.js
2015-03-28 12:55:06 +00:00

344 lines
14 KiB
JavaScript

/**
* Module Name: reddit
* Description: Various reddit functionality
*/
var _ = require('underscore')._,
request = require('request');
var reddit = function(dbot) {
this.ApiRoot = 'http://reddit.com/';
this.UserAgent = 'dbot by u/realitone';
this.ints = [];
this.internalAPI = {
'getChannelFeeds': function(server, cName, callback) {
this.db.read('reddit_feeds', cName + '.' + server, function(err, cFeeds) {
if(err || !cFeeds) {
callback(null, {
'id': cName + '.' + server,
'server': server,
'channel': cName,
'feeds': {}
});
} else {
callback(null, cFeeds);
}
});
}.bind(this),
'updateChannelFeeds': function(cFeeds, callback) {
this.db.update('reddit_feeds', cFeeds.id, cFeeds, callback);
}.bind(this),
'reloadChannelFeeds': function() {
var channels = [],
checkTimes = [];
for(i=0;i<this.ints.length;i++) {
clearInterval(this.ints[i]);
}
this.ints = [];
this.db.scan('reddit_feeds', function(channel) {
if(channel) {
channels.push(channel);
}
}, function() {
_.each(channels, function(channel) {
checkTimes[channel.id] = {};
_.each(channel.feeds, function(feed) {
checkTimes[channel.id][feed.subreddit] = Date.now();
var intervalId = setInterval(function() {
this.api.getNewPosts(feed.subreddit, checkTimes[channel.id][feed.subreddit], function(err, posts) {
if(!err && posts.length > 0) {
_.each(posts, function(post) {
dbot.say(channel.server, channel.channel, dbot.t('about_new_post', {
'title': _.unescape(post.title.trim()),
'poster': post.author,
'subreddit': post.subreddit,
'comments': post.num_comments,
'score': post.score,
'up': post.ups,
'down': post.downs,
'url': this.ApiRoot + post.id
}));
}, this);
checkTimes[channel.id][feed.subreddit] = Date.now();
}
}.bind(this));
}.bind(this), feed.interval);
this.ints.push(intervalId);
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this)
};
this.api = {
'getSubredditInfo': function(name, callback) {
request.get({
'url': this.ApiRoot + 'r/' + name + '/about.json',
'json': true,
'headers': {
'User-Agent': this.UserAgent
}
}, function(err, response, body) {
var data = null;
if(_.has(body, 'data')) data = body.data;
callback(data);
});
},
'getPostInfo': function(name, callback) {
request.get({
'url': this.ApiRoot + 'comments/' + name + '.json',
'json': true,
'headers': {
'User-Agent': this.UserAgent
}
}, function(err, response, body) {
if(body[0] && _.has(body[0], 'data')) {
callback(body[0].data.children[0].data);
}
});
},
'getCommentInfo': function(post, name, callback) {
request.get({
'url': this.ApiRoot + 'comments/' + post + '.json',
'qs': {
'comment': name
},
'json': true,
'headers': {
'User-Agent': this.UserAgent
}
}, function(err, response, body) {
if(body[1] && _.has(body[1], 'data')) {
callback(body[1].data.children[0].data);
}
});
},
'getNewPosts': function(sr, last, callback) {
request.get({
'url': this.ApiRoot + 'r/' + sr + '/new.json',
'json': true,
'headers': {
'User-Agent': this.UserAgent
}
}, function(err, response, body) {
if(!err && body && body.kind === 'Listing') {
var posts = _.pluck(body.data.children, 'data');
newPosts = _.filter(posts, function(post) {
return post.created_utc > (last / 1000);
});
callback(null, newPosts);
} else {
callback(true, null);
}
});
},
'getTopPosts': function(sr, callback) {
request.get({
'url': this.ApiRoot + 'r/' + sr + '/top.json',
'json': true,
'headers': {
'User-Agent': this.UserAgent
}
}, function(err, response, body) {
if(!err && body && body.kind === 'Listing') {
var posts = _.pluck(body.data.children, 'data');
callback(null, posts);
} else {
callback(true, null);
}
});
}
};
this.commands = {
'~question': function(event) {
this.api.getTopPosts('askreddit', function(err, posts) {
if(!err) {
var qPost = posts[_.random(0, posts.length - 1)];
event.reply('Question: ' + qPost.title.trim());
}
});
},
'~squestion': function(event) {
this.api.getNewPosts('askscience', 0, function(err, posts) {
if(!err) {
var qPost = posts[_.random(0, posts.length - 1)];
event.reply('Question: ' + qPost.title.trim());
}
});
},
'~r': function(event) {
var sr = event.params[1].trim();
this.api.getNewPosts(sr, 0, function(err, posts) {
if(!err) {
var qPost = posts[_.random(0, posts.length -1)];
event.reply(dbot.t('about_post', {
'title': _.unescape(qPost.title.trim()),
'poster': qPost.author,
'subreddit': qPost.subreddit,
'comments': qPost.num_comments,
'score': qPost.score,
'up': qPost.ups,
'down': qPost.downs,
'url': qPost.url
}));
} else {
event.reply('Could not find that subreddit');
}
});
},
'~addredditfeed': function(event) {
var channel = event.input[1],
subreddit = event.input[2].replace('r/', ''),
interval = event.input[3] * 60000;
this.internalAPI.getChannelFeeds(event.server, channel, function(err, channel) {
if(!err) {
if(!_.has(channel.feeds, subreddit)) {
channel.feeds[subreddit] = {
'subreddit': subreddit,
'interval': interval
};
this.internalAPI.updateChannelFeeds(channel, function() {
this.internalAPI.reloadChannelFeeds();
}.bind(this));
event.reply(dbot.t('added_channel_feed', {
'subreddit': subreddit,
'interval': interval / 60000,
'channel': channel.channel
}));
} else {
event.reply(dbot.t('feed_already_watched'));
}
} else {
if(err === 'NoSuchChannel') {
event.reply(dbot.t('no_such_channel'));
}
}
}.bind(this));
},
'~rmredditfeed': function(event) {
var channel = event.input[1],
subreddit = event.input[2].replace('r/', '');
this.internalAPI.getChannelFeeds(event.server, channel, function(err, channel) {
if(!err && channel && _.has(channel.feeds, subreddit)) {
delete channel.feeds[subreddit];
this.internalAPI.updateChannelFeeds(channel, function() {
this.internalAPI.reloadChannelFeeds();
}.bind(this));
event.reply(dbot.t('removed_channel_feed', {
'subreddit': subreddit,
'channel': channel.channel
}));
} else {
event.reply(dbot.t('no_such_feed'));
}
}.bind(this));
}
};
this.commands['~addredditfeed'].regex = [/^addredditfeed ([^ ]+) ([^ ]+) ([^ ]+)$/, 4];
this.commands['~rmredditfeed'].regex = [/^rmredditfeed ([^ ]+) ([^ ]+)$/, 3];
this.commands['~addredditfeed'].access = 'moderator';
this.commands['~rmredditfeed'].access = 'moderator';
this.onDestroy = function() {
for(i=0;i<this.ints.length;i++) {
clearInterval(this.ints[i]);
}
}.bind(this);
this.onLoad = function() {
this.internalAPI.reloadChannelFeeds();
var rHandler = function(matches, name, callback) {
if(matches[6]) { // It's a comment
this.api.getCommentInfo(matches[4], matches[6], function(info) {
if(info) {
var infoString = dbot.t('about_comment', {
'poster': info.author,
'subreddit': info.subreddit,
'comments': info.num_comments,
'score': info.ups - info.downs,
'up': info.ups,
'down': info.downs
});
if(info.over_18) infoString += " " + dbot.t("nsfw");
callback(infoString);
}
});
} else if(matches[4]) { // It's a post
this.api.getPostInfo(matches[4], function(info) {
if(info) {
var infoString = dbot.t('about_post', {
'title': _.unescape(info.title.trim()),
'poster': info.author,
'subreddit': info.subreddit,
'comments': info.num_comments,
'score': info.score,
'up': info.ups,
'down': info.downs,
'url': this.ApiRoot + matches[4]
});
if(info.over_18) infoString += " " + dbot.t("nsfw");
callback(infoString);
}
}.bind(this));
} else if(matches[2]) { // It's a subreddit
this.api.getSubredditInfo(matches[2], function(info) {
if(info) {
var infoString = dbot.t('about_subreddit', {
'display_name': info.display_name,
'subscribers': info.subscribers,
'active': info.accounts_active
});
if(info.over18) infoString += dbot.t("nsfw");
callback(infoString);
}
});
}
}.bind(this);
dbot.api.link.addHandler(this.name, // I'm so sorry, Jesus.
/https?:\/\/([a-z]+\.)?reddit\.com\/r\/([a-zA-Z0-9]+)(\/comments\/([a-zA-Z0-9]+)?\/([a-zA-Z0-9_]+)\/([a-zA-Z0-9_]+)?)?/,
rHandler);
dbot.api.link.addHandler(this.name + 'short',
/https?:\/\/([a-z]\.)?redd.it\/([a-zA-Z0-9]+)/,
function(match, name, callback) {
this.api.getPostInfo(match[2], function(info) {
if(info) {
var infoString = dbot.t('about_post', {
'title': _.unescape(info.title.trim()),
'poster': info.author,
'subreddit': info.subreddit,
'comments': info.num_comments,
'score': info.score,
'up': info.ups,
'down': info.downs,
'url': this.ApiRoot + match[2]
});
if(info.over_18) infoString += " " + dbot.t("nsfw");
callback(infoString);
}
}.bind(this));
}.bind(this));
}.bind(this);
};
exports.fetch = function(dbot) {
return new reddit(dbot);
}