2016-12-03 03:04:38 +02:00
//external library imports
2016-11-01 01:28:17 +02:00
var Dns = require ( "dns" ) ; //for connectivity checking
var Url = require ( "url" ) ; //for url parsing
var Uri = require ( "urijs" ) ; //for finding urls within message strings
var FeedRead = require ( "feed-read" ) ; //for rss feed reading
2017-01-08 09:09:28 +02:00
var JsonFile = require ( "jsonfile" ) ; //reading/writing json
2017-03-30 04:17:47 +03:00
var Console = require ( "console" ) ;
2016-12-03 03:04:38 +02:00
//my imports
2016-11-01 01:28:17 +02:00
var Config = require ( "./config.json" ) ; //config file containing other settings
2016-11-01 19:23:39 +02:00
2017-03-30 04:17:47 +03:00
module . exports = {
onReady : ( ) => {
Actions . checkPastMessagesForLinks ( ) ; //we need to check past messages for links on startup, but also on reconnect because we don't know what has happened during the downtime
2017-01-08 07:00:07 +02:00
2017-01-10 00:55:05 +02:00
//set the interval function to check the feed
2017-01-08 07:24:48 +02:00
intervalFunc = ( ) => {
2017-01-08 07:41:10 +02:00
Feed . check ( ( err , articles ) => {
2017-03-30 04:17:47 +03:00
Links . validate ( err , articles , Actions . post ) ;
2017-01-08 07:41:10 +02:00
} ) ;
2017-01-08 07:24:48 +02:00
} ;
2016-12-03 02:56:31 +02:00
2017-03-30 04:17:47 +03:00
setInterval ( ( ) => { intervalFunc ( ) ; } , Config . pollingInterval ) ;
2016-12-03 02:56:31 +02:00
} ,
2017-03-30 04:17:47 +03:00
onMessage : function ( bot , user , userID , channelID , message ) {
2017-01-22 22:42:26 +02:00
//contains a link, and is not the latest link from the rss feed
if ( channelID === Config . channelID && Links . messageContainsLink ( message ) && ( message !== Links . latestFromFeedlatestFeedLink ) ) {
2017-03-30 04:17:47 +03:00
Console . info ( "Detected posted link in this message: " + message , "Discord.io" ) ;
2017-01-08 09:45:22 +02:00
2017-01-22 22:42:26 +02:00
//extract the url from the string, and cache it
Uri . withinString ( message , function ( url ) {
Links . cache ( Links . standardise ( url ) ) ;
return url ;
} ) ;
}
2016-12-03 02:56:31 +02:00
2017-01-08 07:24:48 +02:00
} ,
2017-03-30 04:17:47 +03:00
commands : [
2017-01-09 23:57:32 +02:00
{
2017-03-30 04:17:47 +03:00
command : Config . userCommands . subscribe ,
type : "equals" ,
action : ( bot , user , userID , channelID , message ) => { if ( Config . allowSubscriptions ) Subscriptions . subscribe ( bot , user , userID , channelID , message ) ; } ,
channelIDs : [ Config . channelID ]
2017-01-09 23:57:32 +02:00
} ,
{
2017-03-30 04:17:47 +03:00
command : Config . userCommands . unsubscribe ,
type : "equals" ,
action : ( bot , user , userID , channelID , message ) => { if ( Config . allowSubscriptions ) Subscriptions . unsubscribe ( bot , user , userID , channelID , message ) ; } ,
channelIDs : [ Config . channelID ]
2017-01-09 23:57:32 +02:00
} ,
{
2017-03-30 04:17:47 +03:00
command : Config . userCommands . help ,
type : "equals" ,
action : ( bot , user , userID , channelID , message ) => {
bot . sendMessage ( {
2017-01-09 23:57:32 +02:00
to : Config . channelID ,
message : Config . userCommands . join ( " + " )
} ) ;
} ,
2017-03-30 04:17:47 +03:00
channelIDs : [ Config . channelID ]
2017-01-09 23:57:32 +02:00
} ,
{
2017-03-30 04:17:47 +03:00
command : Config . developerCommands . logUpload ,
type : "equals" ,
action : ( bot , user , userID , channelID , message ) => {
bot . uploadFile ( {
2017-01-09 23:57:32 +02:00
to : channelID ,
file : Config . logFile
} ) ;
} ,
userIDs : Config . developers
} ,
{
2017-03-30 04:17:47 +03:00
command : Config . developerCommands . cacheList ,
type : "equals" ,
action : ( bot , user , userID , channelID , message ) => {
bot . sendMessage ( {
2017-01-09 23:57:32 +02:00
to : channelID ,
message : Links . cached . join ( ", " )
} ) ;
} ,
userIDs : Config . developers
}
]
2016-12-03 02:56:31 +02:00
} ;
2016-11-01 01:28:17 +02:00
2017-03-30 04:17:47 +03:00
var Actions = {
post : ( bot , link ) => {
//send a messsage containing the new feed link to our discord channel
bot . sendMessage ( {
to : Config . channelID ,
message : Subscriptions . mention ( ) + link
} ) ;
} ,
checkPastMessagesForLinks : ( bot ) => {
var limit = 100 ;
Console . info ( "Attempting to check past " + limit + " messages for links" ) ;
//get the last however many messsages from our discord channel
bot . getMessages ( {
channelID : Config . channelID ,
limit : limit
} , function ( err , messages ) {
if ( err ) Console . error ( "Error fetching discord messages." , err ) ;
else {
Console . info ( "Pulled last " + messages . length + " messages, scanning for links" ) ;
var messageContents = messages . map ( ( x ) => { return x . content ; } ) . reverse ( ) ; //extract an array of strings from the array of message objects
for ( var messageIdx in messageContents ) {
var message = messageContents [ messageIdx ] ;
if ( Links . messageContainsLink ( message ) ) //test if the message contains a url
//detect the url inside the string, and cache it
Uri . withinString ( message , function ( url ) {
Links . cache ( url ) ;
return url ;
} ) ;
}
}
} ) ;
} ,
} ;
2017-01-08 09:45:22 +02:00
var Subscriptions = {
2017-03-30 04:17:47 +03:00
subscribe : function ( bot , user , userID , channelID , message ) {
bot . addToRole ( {
2017-01-22 20:08:40 +02:00
serverID : Config . serverID ,
2017-01-22 19:11:12 +02:00
userID : userID ,
roleID : Config . subscribersRoleID
2017-01-22 20:23:09 +02:00
} ,
( err ) => {
2017-03-30 04:17:47 +03:00
if ( err ) Console . log ( err ) ; //log the error if there is an error
2017-01-22 20:23:09 +02:00
else { //else go ahead and confirm subscription
2017-03-30 04:17:47 +03:00
Console . info ( "Subscribed user " + ( user ? user + "(" + userID + ")" : userID ) ) ;
2017-01-22 20:23:09 +02:00
2017-03-30 04:17:47 +03:00
bot . sendMessage ( {
2017-01-22 20:23:09 +02:00
to : channelID ,
message : "You have successfully subscribed"
2017-03-30 04:17:47 +03:00
} , ( err , response ) => { setTimeout ( ( ) => { bot . deleteMessage ( { channelID : channelID , messageID : response . id } ) ; } , Config . messageDeleteDelay ) ; } ) ; //delete the subscription confirmation message after a delay
2017-01-22 20:23:09 +02:00
}
} ) ;
2017-01-10 01:23:14 +02:00
2017-01-08 09:45:22 +02:00
} ,
2017-01-22 19:11:12 +02:00
2017-03-30 04:17:47 +03:00
unsubscribe : function ( bot , user , userID , channelID , message ) {
bot . removeFromRole ( {
2017-01-22 20:08:40 +02:00
serverID : Config . serverID ,
2017-01-22 19:11:12 +02:00
userID : userID ,
roleID : Config . subscribersRoleID
2017-01-22 20:23:09 +02:00
} ,
( err ) => {
2017-03-30 04:17:47 +03:00
if ( err ) Console . log ( err ) ; //log the error if there is an error
2017-01-22 20:23:09 +02:00
else { //else go ahead and confirm un-subscription
2017-03-30 04:17:47 +03:00
Console . info ( "Unsubscribed user " + ( user ? user + "(" + userID + ")" : userID ) ) ;
2017-01-22 20:23:09 +02:00
2017-03-30 04:17:47 +03:00
bot . sendMessage ( {
2017-01-22 20:23:09 +02:00
to : channelID ,
message : "You have successfully unsubscribed"
2017-03-30 04:17:47 +03:00
} , ( err , response ) => { setTimeout ( ( ) => { bot . deleteMessage ( { channelID : channelID , messageID : response . id } ) ; } , Config . messageDeleteDelay ) ; } ) ; //delete the un-subscription confirmation message after a delay
2017-01-22 20:23:09 +02:00
}
} ) ;
2017-01-08 18:01:07 +02:00
} ,
2017-01-22 19:11:12 +02:00
mention : function ( ) {
2017-01-22 20:24:18 +02:00
return Config . allowSubscriptions ? "<@&" + Config . subscribersRoleID + "> " : "" ;
2017-01-08 09:45:22 +02:00
}
} ;
2016-12-03 02:23:15 +02:00
var YouTube = {
url : {
share : "http://youtu.be/" ,
full : "http://www.youtube.com/watch?v=" ,
2017-01-08 07:24:48 +02:00
createFullUrl : function ( shareUrl ) {
2016-12-03 03:52:16 +02:00
return shareUrl . replace ( YouTube . url . share , YouTube . url . full ) ;
2016-12-03 02:23:15 +02:00
} ,
2017-01-08 07:24:48 +02:00
createShareUrl : function ( fullUrl ) {
2016-12-03 03:52:16 +02:00
var shareUrl = fullUrl . replace ( YouTube . url . full , YouTube . url . share ) ;
2016-12-02 23:53:13 +02:00
2017-01-08 07:24:48 +02:00
if ( shareUrl . includes ( "&" ) ) shareUrl = shareUrl . slice ( 0 , fullUrl . indexOf ( "&" ) ) ;
2016-12-03 02:23:15 +02:00
return shareUrl ;
}
} ,
} ;
var Links = {
2016-12-30 16:54:10 +02:00
standardise : function ( link ) {
2016-12-30 17:40:03 +02:00
link = link . replace ( "https://" , "http://" ) ; //cheaty way to get around http and https not matching
2017-01-04 21:06:29 +02:00
if ( Config . youtubeMode ) link = link . split ( "&" ) [ 0 ] ; //quick way to chop off stuff like &feature=youtube etc
2016-12-30 17:40:03 +02:00
return link ;
2016-12-30 16:54:10 +02:00
} ,
messageContainsLink : function ( message ) {
var messageLower = message . toLowerCase ( ) ;
2016-12-30 17:24:12 +02:00
return messageLower . includes ( "http://" ) || messageLower . includes ( "https://" ) || messageLower . includes ( "www." ) ;
2016-12-30 16:54:10 +02:00
} ,
2016-12-03 02:23:15 +02:00
cached : [ ] ,
2017-01-08 07:24:48 +02:00
latestFeedLink : "" ,
2016-12-03 02:23:15 +02:00
cache : function ( link ) {
2016-12-30 16:54:10 +02:00
link = Links . standardise ( link ) ;
2016-12-03 03:52:16 +02:00
2017-01-08 07:24:48 +02:00
if ( Config . youtubeMode ) link = YouTube . url . createShareUrl ( link ) ;
2016-12-03 03:52:16 +02:00
2016-12-03 02:23:15 +02:00
//store the new link if not stored already
2017-01-08 07:24:48 +02:00
if ( ! Links . isCached ( link ) ) {
2016-12-03 03:37:02 +02:00
Links . cached . push ( link ) ;
2017-03-30 04:17:47 +03:00
Console . info ( "Cached URL: " + link ) ;
2016-12-03 02:23:15 +02:00
}
2017-01-08 07:24:48 +02:00
2017-01-08 07:27:49 +02:00
if ( Links . cached . length > Config . numLinksToCache ) Links . cached . shift ( ) ; //get rid of the first array element if we have reached our cache limit
2016-12-03 02:23:15 +02:00
} ,
2017-01-08 07:24:48 +02:00
isCached : function ( link ) {
2016-12-30 16:54:10 +02:00
link = Links . standardise ( link ) ;
2017-01-08 07:24:48 +02:00
if ( Config . youtubeMode )
return Links . cached . includes ( YouTube . url . createShareUrl ( link ) ) ;
2016-12-03 03:37:02 +02:00
return Links . cached . includes ( link ) ;
2016-12-03 02:56:31 +02:00
} ,
2017-01-08 07:24:48 +02:00
validate : function ( err , articles , callback ) {
2017-03-30 04:17:47 +03:00
if ( err ) Console . error ( "FEED ERROR: Error reading RSS feed." , err ) ;
2016-12-03 02:56:31 +02:00
else {
2017-01-08 08:18:05 +02:00
var latestLink = Links . standardise ( articles [ 0 ] . link ) ;
2017-01-08 08:37:30 +02:00
if ( Config . youtubeMode ) latestLink = YouTube . url . createShareUrl ( latestLink ) ;
2016-12-03 02:56:31 +02:00
2017-01-08 07:24:48 +02:00
//make sure we don't spam the latest link
2017-01-08 10:48:47 +02:00
if ( latestLink === Links . latestFeedLink )
2017-01-08 07:24:48 +02:00
return ;
2016-12-02 02:55:39 +02:00
2017-01-08 07:24:48 +02:00
//make sure the latest link hasn't been posted already
if ( Links . isCached ( latestLink ) ) {
2017-03-30 04:17:47 +03:00
Console . info ( "Didn't post new feed link because already detected as posted " + latestLink ) ;
2016-12-02 02:40:33 +02:00
}
2017-01-08 08:37:30 +02:00
else {
callback ( latestLink ) ;
2016-12-02 02:55:39 +02:00
2017-01-08 08:37:30 +02:00
Links . cache ( latestLink ) ; //make sure the link is cached, so it doesn't get posted again
}
2017-01-08 08:44:08 +02:00
2017-01-08 07:24:48 +02:00
Links . latestFeedLink = latestLink ; //ensure our latest feed link variable is up to date, so we can track when the feed updates
2016-11-01 01:28:17 +02:00
}
}
2016-12-03 02:56:31 +02:00
} ;
2016-11-05 03:08:17 +02:00
2016-12-03 02:56:31 +02:00
var Feed = {
urlObj : Url . parse ( Config . feedUrl ) ,
2017-01-08 07:24:48 +02:00
check : function ( callback ) {
2016-12-30 17:37:13 +02:00
Dns . resolve ( Feed . urlObj . host , function ( err ) { //check that we have an internet connection (well not exactly - check that we have a connection to the host of the feedUrl)
2017-03-30 04:17:47 +03:00
if ( err ) Console . error ( "CONNECTION ERROR: Cannot resolve host." , err ) ;
2017-01-08 07:41:10 +02:00
else FeedRead ( Config . feedUrl , callback ) ;
2016-12-03 02:56:31 +02:00
} ) ;
}
2016-12-03 03:37:02 +02:00
} ;
2017-03-30 04:17:47 +03:00
var intervalFunc = ( ) => { } ; //do nothing by default