Initial commit of the generic reddit bot
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
CLIENT_ID=Your Client ID
|
||||
CLIENT_SECRET=Your Client Secret
|
||||
REFRESH_TOKEN=The refresh Token
|
||||
BOT_NAME=Name of your Bot.
|
||||
SUBREDDIT=The subreddit, where the bots operates on
|
||||
POLL_LIMIT=Limit of posts it polls
|
||||
POLL_TIME=The time the bot looks for new posts (in ms)
|
||||
AUTOMOD_ID=The ID of the automod (of the user the bot will reply to)
|
||||
REST_URL=URL of the rest interface, where the post text gets sent to
|
||||
DEVELOPER=Your reddit user account name
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
.env
|
||||
*.log
|
||||
@@ -1,3 +1,4 @@
|
||||
# generic-reddit-bot
|
||||
Generic reddit bot, which replies to a comment from each post in a subreddit.
|
||||
The text from the post will be send to a rest url (which can be configured in an .env file), which handles the text manipulation if needed.
|
||||
Generic reddit bot, which replies to a comment from each post in a subreddit.
|
||||
|
||||
The text from the post will be send to a rest url (which can be configured in an .env file), which handles the text manipulation if needed.
|
||||
|
||||
Generated
+1029
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "generic-reddit-bot",
|
||||
"version": "1.0.0",
|
||||
"description": "Generic reddit bot",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "start src/server.js",
|
||||
"debug": "node src/server.js DEBUG",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "\u0016https://github.com/StarAppeal/generic-reddit-bot"
|
||||
},
|
||||
"author": "starappeal, tsomic",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"dateformat": "^3.0.3",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"snoostorm": "^1.3.0",
|
||||
"snoowrap": "^1.21.0",
|
||||
"winston": "^3.2.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
var express = require('express');
|
||||
|
||||
var application = express();
|
||||
|
||||
module.exports = application;
|
||||
@@ -0,0 +1,54 @@
|
||||
const {
|
||||
createLogger,
|
||||
format,
|
||||
transports
|
||||
} = require('winston');
|
||||
|
||||
const logger = createLogger({
|
||||
level: 'info',
|
||||
format: format.combine(
|
||||
format.timestamp({
|
||||
format: 'DD.MM.YYYY HH:mm:ss'
|
||||
}),
|
||||
format.errors({
|
||||
stack: true
|
||||
}),
|
||||
format.splat(),
|
||||
format.json()
|
||||
),
|
||||
defaultMeta: {
|
||||
service: process.env.BOT_NAME
|
||||
},
|
||||
transports: [
|
||||
//
|
||||
// - Write to all logs with level `info` and below to `quick-start-combined.log`.
|
||||
// - Write all logs error (and below) to `quick-start-error.log`.
|
||||
//
|
||||
new transports.File({
|
||||
filename: 'error.log',
|
||||
level: 'error'
|
||||
}),
|
||||
new transports.File({
|
||||
filename: 'info.log',
|
||||
level: 'info'
|
||||
}),
|
||||
new transports.File({
|
||||
filename: 'combined.log'
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
//
|
||||
// If we're not in production then **ALSO** log to the `console`
|
||||
// with the colorized simple format.
|
||||
//
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
logger.add(new transports.Console({
|
||||
format: format.combine(
|
||||
format.colorize(),
|
||||
format.simple()
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
module.exports = logger;
|
||||
@@ -0,0 +1,21 @@
|
||||
const {
|
||||
SubmissionStream
|
||||
} = require("snoostorm");
|
||||
|
||||
const Snoowrap = require('snoowrap');
|
||||
const Snoostorm = require('snoostorm');
|
||||
|
||||
const r = new Snoowrap({
|
||||
userAgent: 'linux:'+process.env.BOT_NAME+':1.0 (by ' + process.env.DEVELOPER + ')',
|
||||
clientId: process.env.CLIENT_ID,
|
||||
clientSecret: process.env.CLIENT_SECRET,
|
||||
refreshToken: process.env.REFRESH_TOKEN
|
||||
});
|
||||
|
||||
const submissionstream = new SubmissionStream(r, {
|
||||
subreddit: process.env.SUBREDDIT,
|
||||
limit: process.env.POLL_LIMIT * 1, // small hack to change it from string to a number
|
||||
pollTime: process.env.POLL_TIME * 1 // same as above
|
||||
});
|
||||
|
||||
module.exports = {stream: submissionstream, wrap: r};
|
||||
@@ -0,0 +1,82 @@
|
||||
const dateFormat = require('dateformat');
|
||||
const streamConfig = require("../config/streamConfig")
|
||||
const logger = require("../config/logger");
|
||||
|
||||
const axios = require('axios');
|
||||
|
||||
const alreadyReplied = postId =>
|
||||
streamConfig.wrap.getMe().getComments({
|
||||
limit: process.env.POLL_LIMIT * 2 // removed posts won't get streamed, but the comments to these removed posts still show up.
|
||||
}).then(comments => {
|
||||
for (comment of comments) {
|
||||
if (comment.link_id.includes(postId)) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
function startStream() {
|
||||
streamConfig.stream.on("item", post => {
|
||||
logger.info("found post with id: " + post.id + " posted at: " + dateFormat(new Date(post.created_utc * 1000), "dd.mm.yyyy hh:MM:ss"));
|
||||
streamConfig.wrap.getSubmission(post.id).comments.then(async (comments) => {
|
||||
if (await alreadyReplied(post.id)) {
|
||||
logger.info("Already replied to this post, gonna skip.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
checkForAutomodComment(comments, 5000).then(c => replyToComment(post, c)).catch(e => logger.error(e));
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function checkForAutomodComment(comments, wait, i = 1) {
|
||||
logger.info('Searching for Automod comment...');
|
||||
var c;
|
||||
for (comment of comments) {
|
||||
if (comment.author_fullname === process.env.AUTOMOD_ID) {
|
||||
c = comment;
|
||||
}
|
||||
}
|
||||
if (!c) {
|
||||
logger.info('No Automod Comment found, checking again soon...');
|
||||
logger.info('This was try #' + i);
|
||||
if (i === 20) {
|
||||
logger.info('Not found after 20 tries, doubling wait time');
|
||||
wait *= 2;
|
||||
}
|
||||
await new Promise(r => setTimeout(r, wait));
|
||||
return checkForAutomodComment(post, wait, i + 1)
|
||||
} else {
|
||||
logger.info('Automod comment found!');
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
function replyToComment(post, comment) {
|
||||
if (process.argv[2] === 'DEBUG') {
|
||||
console.log("I would reply but im locally started so I do not. Sorry mate");
|
||||
return;
|
||||
}
|
||||
let url = process.env.REST_URL;
|
||||
let objectToSend = {
|
||||
text: post.selftext
|
||||
};
|
||||
logger.info("post requesting to url " + url);
|
||||
logger.info(JSON.stringify(objectToSend));
|
||||
axios.post(url, objectToSend).then(response => {
|
||||
let result = response.data;
|
||||
logger.info("Didn't reply to post with ID: " + post.id + "... reply to it now!");
|
||||
comment.reply(result.result);
|
||||
logger.info('Text of reply was: ' + result.result);
|
||||
logger.info("post request took " + result.timeNeeded + "ms!");
|
||||
}).catch(error => {
|
||||
logger.error(error);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
startStream: startStream
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
require('dotenv').config();
|
||||
|
||||
const app = require('./app');
|
||||
const http = require('http');
|
||||
const roboter = require("./roboter/genericBoter");
|
||||
|
||||
var port = process.argv[2] === 'DEBUG' ? 81 : process.env.PORT;
|
||||
|
||||
http.createServer(app).listen(port, function() {
|
||||
console.log("App listens on port: " + this.address().port);
|
||||
roboter.startStream();
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
npm run debug
|
||||
pause
|
||||
Reference in New Issue
Block a user