Skip to content

Instantly share code, notes, and snippets.

@noeatnosleep
Forked from GaeaKat/modapplicationposter.py
Last active October 28, 2021 13:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save noeatnosleep/20f5b4f609a6b54d9363058a966f5f74 to your computer and use it in GitHub Desktop.
Save noeatnosleep/20f5b4f609a6b54d9363058a966f5f74 to your computer and use it in GitHub Desktop.
BAD_WORDS = ['jap', 'chink', 'shill', 'asshole', 'cunt', 'fuck', 'idiot', 'retard', 'twat', 'douche', 'cringe', 'jerk', 'boner', 'puna', 'sperm', 'jews', 'gay', 'pedophile', 'pedant', 'stupid', 'cuck', 'whore', 'retard', 'fedora', 'good sir', 'cakeday', 'tree fiddy', 'stupid', 'wank', 'wanc', 'hooker', 'testicl', 'rape', 'rapist', 'penis', 'gangbang', 'slut', 'apefrican', 'ape', 'fuck', 'mod', 'moderator', 'nigga', 'nigger', 'bitch', 'shit', 'cunt', 'dick', 'fag', 'trans', 'dyke', 'kyke', 'kike', 'nig', 'faggot', 'brave', 'fuck you', 'kill', 'ass', 'asshole', 'arse', 'scum', 'stormfront', 'vagina', 'homo']
def run(workbookname, usernamecolletter=None, subreddit=None, badwords=[], notifyme=False, runbackgroundcheck=True,
useragent=None, username=None, password=None):
"""
Main instance
The user that is OAuthed or LoginAuthed must be an approved contributor to the sub to post apps
and must be an approved submitter to the sub. Just making it a mod won't work.
:param usernamecolletter: the letter of the column that denotes the applicant's username.
If not specified, it will make the title have the timestamp instead of the user's name. This
script assumes that the timestamp row is the first row, so it uses appropiate grammar to comply.
:param notifyme: whether or not to send inbox replies to the account that is making the posts. default is False.
:param subreddit: the sub to post to (string or praw.objects.Subreddit object). While it is a
keyword argument, that's only cause technicalities. IT IS REQUIRED.
:param badwords: list of badwords for background checks. Default is BAD_WORDS in this file.
:param runbackgroundcheck: Boolean, whether or not to add a background check to the post.
BACKGROUND CHECKS CAN TAKE SOME TIME. If there is no username found from the spreadsheet, it will be skipped
:param useragent: optional useragent to specify. The default is
'Mod application to subreddit poster posting to /r/{subreddit} by /u/13steinj'
:params username, password: A username and password to specify if you wish to use LoginAuth.
If OAuth is available, OAuth will have priority. If it fails, login auth will be used.
IN PRAW4 LOGIN AUTH WILL BE DEPRECATED, JUST AS A REMINDER IN CASE YOU SAY THIS SCRIPT DOESN'T WORK WHEN IT'S OUT
:returns: The amount of posts made and the sub they were made to.
"""
if subreddit == None:
raise TypeError("run() missing required keyword argument subreddit, dipshit")
import praw
import openpyxl
badwords = badwords or BAD_WORDS
useragent = (useragent or
("Mod application to subreddit "
"poster posting to /r/{0} by /u/13steinj".format(subreddit)))
r = praw.Reddit(useragent)
try:
import OAuth2Util
o = OAuth2Util.OAuth2Util(r)
o.refresh(force=True)
except Exception as e:
if e.__class__ == ImportError and username and password:
print("OAuth2Util not installed, using login")
r.login(username, password)
elif username and password:
print("OAuth2Util failure, attempting to use login")
r.login(username, password)
print("Success")
else:
raise
workbook = openpyxl.load_workbook('{0}.xlsx'.format(workbookname))
sheets = workbook.get_sheet_names()
if len(sheets) > 1:
sheetlist = '\n'.join(['{0}: {1}'.format((sheets.index(i) + 1), i) for i in sheets])
num = input("Which sheet would you like?\n{0}\n".format(sheetlist))
try:
num = int(num)
if num <= 0:
raise IndexError("What a dipshit this user is. If only we could replace them with more code...")
sheet = sheets[num - 1]
except ValueError:
raise ValueError("You had to choose a number, dipshit")
except IndexError:
raise IndexError("That sheet doesn't exist, dipshit.")
else:
sheet = sheets[0]
spreadsheet = workbook[sheet]
rows = list(spreadsheet.rows)
questionrow = rows.pop(0)
questionvals = {cell.column: cell.value for cell in questionrow if cell.value is not None}
if usernamecolletter and usernamecolletter not in questionvals:
raise KeyError("That usernamecolumnletter doesn't exist, dipshit")
rownum = 0
for row in rows:
# clear out username, title, and body for next run
rownum += 1
username = None
body = ''
# make body
for cell in row:
if cell.column not in questionvals:
continue
body += "#{0}\n\n".format(questionvals[cell.column])
body += "{0}\n\n---\n\n".format(cell.value if cell.value else "*No Answer*")
if username:
continue
else:
username = cell.value if cell.column == usernamecolletter else None
if username and username.startswith("/u/"):
username = username[3:]
elif username and username.startswith("u/"):
username = username[2:]
if username and runbackgroundcheck:
body += background_check(r, username, badwords=badwords)
if len(body) > 40000:
bodies = list(_util_bodies(40000, body))
else:
bodies = [body]
titleinfo = "at /u/{0}".format(row[0].value) if not username else "by /u/{0}".format(username)
maintitle = "Moderator Application #{0} {1}".format(rownum, titleinfo)
for body in bodies:
if bodies.index(body) > 0:
title = "{0} Part {1}".format(maintitle, (bodies.index(body) + 1))
else:
title = maintitle
post = r.submit(subreddit, title, text=body, send_replies=notifyme)
print("Submitted {0}".format(post.permalink))
print(
"I've just posted {0} applications, dipshit. I'm done now. Call me when you want me again. But you could at least ask me out to dinner first, you rascal!".format(
rownum))
return rownum, subreddit
def background_check(reddit_session, username, badwords=[], post_sub=None):
"""Run a background check on a username
:param reddit_session: a reddit session via praw, usually r
:param username: username to check
:param badwords: list of badwords to run in the profanitychecker
:param post_sub: if you want to post this check to a sub, this
should be the sub name or the subreddit object of this sub name
:returns: post if post_sub is defined, else a background check string.
"""
from praw.errors import NotFound, Forbidden
import datetime
cannot_submit = reddit_session.user == None and not reddit_session.is_oauth_session()
if cannot_submit and post_sub != None:
raise ValueError("Can't post without being logged in, dipshit")
title = "Background Check: {0}".format(username) if post_sub else None
if username.lower().startswith('/u/'):
username = username[3:]
elif username.lower().startswith('u/'):
username = username[2:]
body = "#Background Check -- /u/{0}:\n\n".format(username) if not title else "/u/{0}:\n\n".format(username)
if title:
print("Running background check on /u/{0}".format(username))
user = reddit_session.get_redditor(username)
try:
dumblist = list(user.get_overview())
except NotFound:
body += "Account doesn't exist or deleted or shadowbanned"
return body
except Forbidden:
body += "Account permanently suspended"
return body
ucreated = datetime.datetime.fromtimestamp(user.created_utc)
utimeago = "Account made {0} ago".format(str(datetime.datetime.now() - ucreated))
utimeon = "on " + str(ucreated)
utimetext = " ".join([utimeago, utimeon])
body += utimetext + "\n\n"
posts = list(user.get_submitted(limit=None))
try:
timepost = posts[100]
timepostnum = 100
timepostord = _util_ordinal(timepostnum)
timepostpre = timepostord + " post"
timepostdate = datetime.datetime.fromtimestamp(timepost.created_utc)
timeago = "made {0} ago".format(str(datetime.datetime.now() - timepostdate))
timeon = "on " + str(timepostdate)
timeposttext = " ".join([timepostpre, timeago, timeon])
except IndexError:
try:
timepost = posts[-1]
timepostnum = (posts.index(timepost) + 1)
timepostord = _util_ordinal(timepostnum)
timepostpre = "last({0}) post".format(timepostord)
timepostdate = datetime.datetime.fromtimestamp(timepost.created_utc)
timeago = "made {0} ago".format(str(datetime.datetime.now() - timepostdate))
timeon = "on " + str(timepostdate)
timeposttext = " ".join([timepostpre, timeago, timeon])
except IndexError:
timeposttext = "User has not made a single post, or all are deleted"
body += timeposttext + "\n\n"
comments = list(user.get_comments(limit=None))
totalprofanities, specificprofanities = profanitycheck(badwords, posts, comments)
orderedprofanities = sorted(specificprofanities.keys(), key=str.lower)
profanitytable = "Profanity | Times Used\n---|---"
for word in orderedprofanities:
profanitytable += "\n"
profanitytable += "{0} | {1}".format(word, specificprofanities[word])
profanitytable += "\n**Total** | {0}".format(totalprofanities)
if specificprofanities:
body += "Profanities used in the last 1000 posts and comments:\n\n"
body += profanitytable + "\n\n"
totalsubs, subhistory = historycheck(posts, comments)
orderedsubs = sorted(subhistory.keys(), key=str.lower)
historytable = "Subreddit | Times Used\n---|---"
for subreddit in orderedsubs:
historytable += '\n'
historytable += "/r/{0} | {1}".format(subreddit, subhistory[subreddit])
historytable += "\n**Total** | {0}".format(totalsubs)
body += "Subreddit history over last 1000 posts and comments:\n\n"
body += historytable + "\n\n"
if title:
post = reddit_session.submit(post_sub, title, text=body)
return post
return body
def _util_ordinal(value):
"""
Converts zero or a *postive* integer (or their string
representations) to an ordinal value.
http://code.activestate.com/recipes/576888-format-a-number-as-an-ordinal/
"""
try:
value = int(value)
except ValueError:
return value
if value % 100 // 10 != 1:
if value % 10 == 1:
ordval = u"%d%s" % (value, "st")
elif value % 10 == 2:
ordval = u"%d%s" % (value, "nd")
elif value % 10 == 3:
ordval = u"%d%s" % (value, "rd")
else:
ordval = u"%d%s" % (value, "th")
else:
ordval = u"%d%s" % (value, "th")
return ordval
def _util_bodies(num, string):
"""Produce `num`-character chunks from `string`."""
for start in range(0, len(string), num):
yield string[start:start + num]
def profanitycheck(badwords, *args):
"""
Profanity Checker
:param badwords: list of badwords. Recommended to not contain endings i.e "ing",
"ed" for best results, as containing those may make for duplicates.
:param args: comma delimited list of iters of posts or comments
:returns: dict of word: usagecount for each word in badwords
"""
import re
from bs4 import BeautifulSoup
obj_list = []
html_list = []
check_list = []
profanity_usage = {}
for l in args:
obj_list += l
html_list += [obj.selftext_html for obj in obj_list if hasattr(obj, 'selftext_html')]
html_list += [obj.body_html for obj in obj_list if hasattr(obj, 'body_html')]
for html in html_list:
if html == None:
continue
check_list += BeautifulSoup(html).get_text().split()
badwordtotalusage = 0
for word in badwords:
badwordusage = 0
for check in check_list:
if re.search(word.lower(), check.lower()):
badwordusage += 1
if badwordusage:
profanity_usage[word] = badwordusage
badwordtotalusage += badwordusage
return badwordtotalusage, profanity_usage
def historycheck(*args):
"""
Subreddit History Checker
:param args: comma delimited list of iters of posts or comments
"""
obj_list = []
subreddit_history = {}
for l in args:
obj_list += l
for Thing in obj_list:
subtotal = subreddit_history.get(Thing.subreddit.display_name, 0)
subreddit_history.update({Thing.subreddit.display_name: (subtotal + 1)})
totalsubs = 0
for num in subreddit_history.values():
totalsubs += num
return totalsubs, subreddit_history
def main():
import getpass
global BAD_WORDS
filename = "input"
usercolumn=None
subredditName=None
notifyme=False
runbackgroundcheck=False
username=None
password=None
print("Mod Application Checker")
newbadwords=input("Bad Words (["+','.join(BAD_WORDS)+"]):")
if(newbadwords):
newbadwordsList=newbadwords.split(',')
if(newbadwordsList is not None):
BAD_WORDS=newbadwordsList
print("Bad words is now: "+','.join(BAD_WORDS))
fileloc=input("What is the xlsx name, without the xlsx extention ("+filename+")")
if(fileloc):
filename=fileloc
print("Input file name is: "+filename)
userColumnInput=input("What Column number is the user name? (None)")
if(userColumnInput):
usercolumn=userColumnInput
print("User Name column is: "+str(usercolumn))
while(subredditName==None):
subredditInput=input("Subreddit name, without the leading r/")
if(subredditInput):
subredditName=subredditInput
print("Subreddit Name r/"+subredditName)
notifyInput=input("Should user be notified? (false)")
if(notifyInput and not notifyInput=="false"):
notifyme=True
print("Notify me? "+str(notifyme))
backgroundInput = input("Should background check be run? (false)")
if (backgroundInput and not backgroundInput == "false"):
runbackgroundcheck = True
print("run Background check? " + str(runbackgroundcheck))
while(username==None):
usernameInput=input("Username to login: ")
if(usernameInput):
username=usernameInput
print("Username is: "+username)
while(password==None):
passwordInput=input("Password: ")
if(passwordInput):
password=passwordInput
print("Running")
run(fileloc,usercolumn,subredditName,BAD_WORDS,notifyme,runbackgroundcheck,None,username,password)
if __name__ == "__main__":
main()

Named theinfo.md because if it was README.md github gists has a bug that changes the title name of the gist to README.md

praw and openpyxl must be installed. BeautifulSoup's requirement is dependant on whether or not a profanity check is run, but better safe than sorry. OAuth2Util is optional. In a terminal with root access:

pip3 install openpyxl
pip3 install praw
pip3 install praw-OAuth2Util
pip3 install BeautifulSoup4

Recommended usage is as follows:

Place the Microsoft Office(xlsx) (not Microsoft Office Legacy(xls), those don't work as well or may not at all, don't know) and this script in the same folder. If you have an OAuth2Util oauth.ini, put that in here to. The script will attempt to use OAuth if it can, else it will default to the username ad password arguments, if possible, else raise an error.

To run, either:

Open python3 in a terminal, depending on the OS it's either python3 or py -3. Type

>>> from modapplicationposter import run
>>> run('nameofworkbookwithoutxlsx', 'columnletterforusernamesifapplicable',
... subreddit='subreddityouarepostingtowithout/r/' **kw)

You can also do this in a terminal/cmd:

python3 -c "from modapplicationposter import run; run('nameofworkbookwithoutxlsx', 'columnletterforusernamesifapplicable', subreddit='subreddityouarepostingtowithout/r/' **kw)"

Note: Like above, you may need to replace python3 with py -3

**kw are any of the other params as mentioned by the docstring in modapplicationposter.py.

For profanity checks, words in the badwords list SHOULD NOT have both themselves and themselves endings attached, uch as doing ['fuck', 'fucking'], as there will be skewed results.

This may take some time, even more if background checks are enabled, so set it to run, and put up netflix and chill while watching it just in case

Note: If you get some weird language when you get an error, it's because I was drunk when I first wrote this, and when I continued and was sober, I found it funny and kept it in.

Also: READ THE DOCSTRINGS

Running a plain background check is the same running the main instance, just fit the paramaters accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment