-
-
Save srsinvasionbot/e17ba08727519dcc3f0c to your computer and use it in GitHub Desktop.
Reddit X-Posting Bot
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
#! /usr/bin/env python | |
######################################################################################## | |
# X-Posting Bot v0.2 # | |
# ================== # | |
# # | |
# See xbot.py -h for usage. # | |
# # | |
# The Reddit API python wrapper is required for this script. # | |
# See https://github.com/mellort/reddit_api # | |
# # | |
# This program is free software: you can redistribute it and/or modify # | |
# it under the terms of the GNU General Public License as published by # | |
# the Free Software Foundation, either version 3 of the License, or # | |
# (at your option) any later version. # | |
# # | |
# This program is distributed in the hope that it will be useful, # | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
# GNU General Public License for more details. # | |
# # | |
# You should have received a copy of the GNU General Public License # | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
# # | |
######################################################################################## | |
try: | |
import reddit | |
except ImportError: | |
raise ImportError('Reddit API python wrapper is required. See https://github.com/mellort/reddit_api for more details.') | |
import sys, time, argparse, string, os | |
######################################################################################## | |
# Initialisation & Global Variables #################################################### | |
######################################################################################## | |
parser = argparse.ArgumentParser(description='X-Posting Bot v0.2. A copy and past bot for reddit.',epilog='Associated files to be located in the run directory:\n\t \'black\': Blacklisting text file. The bot will not cross post submissions on this list. \'nope\': A listing of links already x-posted by the bot. \'bot.on\': A lock-file created when the bot is running, deleted on bot exit') | |
parser.add_argument('--username', help='Reddit Username',required=True) | |
parser.add_argument('--password', help='Reddit Password',required=True) | |
parser.add_argument('--paste', help='Subreddit to post stories.',required=True) | |
parser.add_argument('--copy', nargs='+', help='Subreddits containing original content.',required=True) | |
parser.add_argument('--depth',type=int,help='Depth to scrape subs defined in --copy',default=None) | |
args = parser.parse_args() | |
username = args.username | |
passwd = args.password | |
paste = args.paste | |
copy = args.copy | |
depth = args.depth | |
wait = 30 | |
######################################################################################## | |
# Sub Routines ######################################################################### | |
######################################################################################## | |
# 1. Subreddit scraping function. | |
def get_sub(r, copy, depth): | |
stories = {} | |
for sub in copy: | |
stories[sub] = list(r.get_subreddit(sub).get_hot(limit=depth)) | |
time.sleep(wait) | |
return stories | |
# 2. Presubmitted Post Removal Function | |
def remove_submitted(stories): | |
try: | |
nope = open('nope').read().splitlines() | |
except IOError: | |
raise IOError('File \'nope\' is required in the run directory.') | |
else: | |
for key in stories.keys(): | |
for link in nope: | |
for k in range(len(stories[key])-1,-1,-1): | |
if stories[key][k].url.encode('iso-8859-1') == link: | |
stories[key].pop(k) | |
return stories | |
# 3. Duplicate removal function. Credit Tim Peters (http://code.activestate.com/recipes/52560/) | |
def remove_dupes(q): | |
for key in stories.keys(): | |
n = len(q[key]) | |
q[key].sort() | |
assert n > 0 | |
last = q[key][0] | |
lasti = i = 1 | |
while i < n: | |
if q[key][i] != last: | |
q[key][lasti] = last = q[key][i] | |
lasti += 1 | |
i += 1 | |
return q | |
# 4. Update nopelist. | |
def update_nopelist(stories): | |
try: | |
nopefile = open('nope','a') | |
except IOError as e: | |
raise IOError('Unable to open \'nope\' for writing: '+str(e)) | |
for key in stories: | |
for link in stories[key]: | |
try: | |
nopefile.write(str(link.url.encode('iso-8859-1'))+'\n') | |
except: | |
e = sys.exc_info()[1] | |
print "fail: ",str(e),link.permalink | |
nopefile.close() | |
# 5. Cross-Posting Function | |
def xpost(r,stories,paste): | |
for sub in stories.keys(): | |
for link in stories[sub]: | |
print link | |
time.sleep(wait) | |
while True: | |
try: | |
if link.is_self == False: | |
submitted = r.submit(paste, '['+sub+']'+link.title.encode('iso-8859-1')[:300-len(paste)-2], url=link.url) | |
else: | |
submitted = r.submit(paste, '['+sub+']'+link.title.encode('iso-8859-1')[:300-len(paste)-2], text=link.selftext.encode('iso-8859-1')) | |
except reddit.errors.RateLimitExceeded: | |
sys.stdout.write(".") | |
sys.stdout.flush() | |
time.sleep(wait) | |
continue | |
except reddit.errors.ExceptionList as e: | |
print "fail: "+str(e) | |
break | |
else: | |
break | |
time.sleep(wait) | |
while True: | |
try: | |
submitted.add_comment('['+sub+' Original Submission]('+link.permalink+'), originally submitted by ['+link.author.name+'](/u/'+link.author.name+').') | |
except reddit.errors.RateLimitExceeded: | |
sys.stdout.write("-") | |
sys.stdout.flush() | |
time.sleep(wait) | |
continue | |
except reddit.errors.ExceptionList: | |
print "fail: "+str(e) | |
break | |
else: | |
break | |
######################################################################################## | |
# Main Routine ######################################################################### | |
######################################################################################## | |
# General error handler | |
try: | |
# Check for current instance, run bot if no instance found | |
try: | |
tmpfile = open("bot.on",'r') | |
tmpfile.close() | |
except IOError: | |
print "=======================================\n\t X-Posting Bot v0.2\n=======================================" | |
print str(time.asctime(time.localtime()))+" - Logging into Reddit" | |
r = reddit.Reddit(user_agent='/u/'+username+' - X-Posting Bot v0.2') | |
r.login(username,passwd) | |
# Create temporary lockfile | |
tmpfile = open("bot.on",'w') | |
tmpfile.close() | |
print str(time.asctime(time.localtime()))+" - Getting Subreddits" | |
stories = get_sub(r,copy,depth) | |
print str(time.asctime(time.localtime()))+" - Preparing List" | |
stories = remove_submitted(remove_dupes(stories)) | |
print str(time.asctime(time.localtime()))+" - Updating Submission List" | |
update_nopelist(stories) | |
print str(time.asctime(time.localtime()))+" - Cross-Posting Links" | |
xpost(r,stories,paste) | |
# Delete lockfile | |
os.system("rm bot.on") | |
print "* Fin" | |
else: | |
raise Warning("xbot: Already Running or unrecovered crash.") | |
except: | |
exc_type, exc_obj, exc_tb = sys.exc_info() | |
print "General Runtime Error: " + exc_type.__name__ + " @ line: " + str(exc_tb.tb_lineno) | |
os.system("rm bot.on") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment