Created
September 29, 2017 09:43
-
-
Save creesch/93257450cdd70994019329c5af27efb9 to your computer and use it in GitHub Desktop.
Modmail discord feed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
global.configuration = { | |
DEBUG: true, | |
modmailChannelWebhook: 'webhook url goes here', | |
// States go here, colors are hex colors with # replaced with 0x | |
modmailStates: [ | |
{ | |
'state': 'mod', | |
'color': '0x46d160', | |
'subreddits': 'history' | |
},{ | |
'state': 'new', | |
'color': '0x0dd3bb', | |
'subreddits': 'history' | |
},{ | |
'state': 'highlighted', | |
'color': '0xffb000', | |
'subreddits': 'history' | |
},{ | |
'state': 'notifications', | |
'color': '0x24a0ed', | |
'subreddits': 'history' | |
} | |
], | |
redditConfig: { | |
userAgent: '/u/FILLINYOURNAMEHERE discord modmail feed', | |
oauth: { | |
type: 'script', | |
key: 'YOURKEY', | |
secret: 'YOURSECRET', | |
username: 'USERNAME', | |
password: 'PASSWORD', | |
// make sure to set all the scopes you need. We are lazy so we do ALLTHESCOPES | |
scope: ['account', 'creddits', 'edit', 'flair', 'history', 'identity', 'livemanage', 'modconfig', 'modcontributors', 'modflair', 'modlog', 'modmail', 'modothers', 'modposts', 'modself', 'modwiki', 'mysubreddits', 'privatemessages', 'read', 'report', 'save', 'submit', 'subscribe', 'vote', 'wikiedit', 'wikiread'] | |
} | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Configuration goes here. | |
require('./config.js'); | |
if (!configuration.DEBUG) { | |
console.log = function() {}; | |
} | |
const fs = require('fs'); | |
const axios = require('axios'); | |
const snooCore = require('snoocore'); | |
const reddit = new snooCore(configuration.redditConfig); | |
// Object where we store the ids of conversations we have already seen. Is filled on restart from a json file on disk. | |
let modmailChecked = {}; | |
// New modmail is a bit weird in the structure. There is a list of authors where one of them has "isOp" set to true. | |
// this is a quick and dirty method to give us the name of OP when we feed the function the authors object. | |
function getOp(authorObject) { | |
let opName; | |
for (let key in authorObject) { | |
if (authorObject.hasOwnProperty(key)) { | |
const currentAuthor = authorObject[key]; | |
// isOp is true, we have a name. | |
if (currentAuthor.isOp) { | |
opName = currentAuthor.name; | |
} | |
} | |
} | |
// As I said, quick and dirty we simply assume we have the name now and return it. | |
return opName; | |
} | |
// reddit related errrors, for debugging and such. | |
reddit.on('error', function(error) { | |
console.error('REDDIT ERROR:'); | |
console.error(error); | |
}); | |
reddit.on('ENOTFOUND', function(error) { | |
console.error('REDDIT ERROR:'); | |
console.error(error); | |
}); | |
// The "heavy" lifting happens here. Gets the conversations for the subreddits and state given. | |
// Then if there are new things it outputs those to the discord webhook with the color given. | |
function getConversations(subreddits, state, color) { | |
// Call the api | |
reddit('/api/mod/conversations').get({ | |
sort: 'recent', | |
state: state, | |
entity: subreddits | |
}).then(function(result) { | |
// We are interested in the conversations. | |
const conversations = result.conversations; | |
// In order to avoid discord rate limits we store new conversations in this array and send them all at once with one request once done. | |
let embeds = []; | |
// Itterate over the conversations. | |
for (let key in conversations) { | |
if (conversations.hasOwnProperty(key)) { | |
// If we haven't checked it before we can process it. | |
if (!modmailChecked[state].includes(key)) { | |
const currentConversation = conversations[key]; | |
// Lets determine the name we want to attach to the embed. | |
const opName = getOp(currentConversation.authors) | |
// Here we build up the message preview. For now we simply show the raw markdown. | |
const messagePreviewID = currentConversation.objIds[0].id; | |
const messagePreview = result.messages[messagePreviewID].bodyMarkdown; | |
// Build up and push the embed object to the embeds array. | |
embeds.push({ | |
title: currentConversation.subject, | |
url: `https://mod.reddit.com/mail/mod/${key}`, | |
author: { | |
name: `${state} - modmail from /u/${opName}`, | |
url: `https://reddit.com/user/${opName}` | |
}, | |
description: messagePreview, | |
color: parseInt(color) | |
}); | |
// Let's avoid that our history array gets annoyingly long. | |
if (modmailChecked[state].length > 100) { | |
modmailChecked[state].shift(); | |
} | |
modmailChecked[state].push(key); | |
} | |
} | |
} | |
// Fire the webhook | |
if (embeds.length > 0) { | |
axios.post(configuration.modmailChannelWebhook, { | |
embeds: embeds | |
}); | |
} | |
}).catch(function(error) { | |
console.log('reddit error:'); | |
console.log(error); | |
}); | |
} | |
// This function goes over the configuration.modmailStates array and is also responsible for looping and storing the modmailChecked in a local json file. | |
function getModmail() { | |
fs.writeFile('modmailChecked.json', JSON.stringify(modmailChecked), 'utf8', function(err, data) { | |
if (err) { | |
throw err; | |
} | |
}); | |
// Go over each state and fire the getConversations function. | |
configuration.modmailStates.forEach(function(state) { | |
getConversations(state.subreddits, state.state, state.color) | |
}); | |
// check for new modmail every twenty seconds. | |
setTimeout(getModmail, 20000); | |
} | |
// This check really not needed, but maybe someone else wants to use this in the future and this makes it easier to set up. | |
// Hello future user! | |
// This checks for the excistence of the "modmailChecked.json" file and fills the "modmailChecked" object with the contents. | |
if (fs.existsSync('modmailChecked.json')) { | |
fs.readFile('modmailChecked.json', 'utf8', function(err, data) { | |
if (err) { | |
throw err; | |
} | |
modmailChecked = JSON.parse(data); | |
getModmail(); | |
}); | |
// This makes the "modmailChecked.json" file if it doesn't exists yet and builds the modmailChecked object. | |
} else { | |
configuration.modmailStates.forEach(function(state) { | |
modmailChecked[state.state] = []; | |
}); | |
fs.writeFile('modmailChecked.json', JSON.stringify(modmailChecked), 'utf8', function(err, data) { | |
if (err) { | |
throw err; | |
} | |
getModmail(); | |
}); | |
} | |
// Let's gracefully exit when needed. | |
process.on('SIGINT', function() { | |
console.log('\nGracefully shutting down from SIGINT (Ctrl-C)'); | |
fs.writeFile('modmailChecked.json', JSON.stringify(modmailChecked), 'utf8', function(err, data) { | |
if (err) { | |
throw err; | |
} | |
process.exit(); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "modmailDiscordFeed", | |
"version": "0.1.0", | |
"description": "Checks modmail and outputs new conversation to a discord channel", | |
"main": "modmailbot.js", | |
"scripts": { | |
"start": "node modmailbot.js" | |
}, | |
"keywords": [ | |
"discord", | |
"bot", | |
"modmail", | |
"reddit" | |
], | |
"author": "creesch", | |
"license": "MIT", | |
"dependencies": { | |
"axios": "^0.16.2", | |
"snoocore": "^3.3.1" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment