Skip to content

Instantly share code, notes, and snippets.

@srsinvasionbot
Created May 6, 2012 13:02
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 srsinvasionbot/e17ba08727519dcc3f0c to your computer and use it in GitHub Desktop.
Save srsinvasionbot/e17ba08727519dcc3f0c to your computer and use it in GitHub Desktop.
Reddit X-Posting Bot
#! /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