import urllib, urllib2, sys, pycurl, time, random from BeautifulSoup import BeautifulSoup #Post a notice. Source for 'posted from', replyTo represents message ID you're replying to. #Leave replyTo blank if not a reply. def postNotice(message, source, replyTo): global username, password try: c = pycurl.Curl() dataArray = {'status':message, 'source':source, 'in_reply_to_status_id':replyTo} data = urllib.urlencode(dataArray) c.setopt(pycurl.HTTPHEADER, ['User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Firefox/31.']) c.setopt(pycurl.POST, True) c.setopt(pycurl.WRITEFUNCTION, lambda x: None) c.setopt(pycurl.USERPWD, str(username)+':'+str(password)) c.setopt(pycurl.URL, 'http://rainbowdash.net/api/statuses/update.xml') c.setopt(pycurl.POSTFIELDS, data) text = c.perform() c.close() return None except Exception as e: print e sys.exit() #Check how many posts a user has made. def getNoticeCount(userLink): try: request = urllib2.Request(userLink, headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Firefox/31.'}) response = urllib2.urlopen(request) data = response.read() soup = BeautifulSoup(data) count = int(soup.findAll('dl', attrs={'class':'entity_notices'})[0].find('dd').text) return count except Exception as e: print 'You screwed something up.' print e sys.exit() #Gets HTML for the timeline RSS feed. def getTimeline(): try: request = urllib2.Request('http://rainbowdash.net/api/statuses/public_timeline.rss', headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Firefox/31.'}) response = urllib2.urlopen(request) data = response.read() return data except Exception: time.sleep(10) try: request = urllib2.Request('http://rainbowdash.net/api/statuses/public_timeline.rss', headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Firefox/31.'}) response = urllib2.urlopen(request) data = response.read() return data except Exception as e: print 'Could not get timeline. Check site status or tell the programmer he\'s horrible.' print 'Send him this, if you do:' print e sys.exit() #Gets a list of messages, (noticeID, username) format, and returns it. def getStatuses(): statusList = [] soup = BeautifulSoup(getTimeline()) try: for i in soup.findAll('item'): username = str(i.find('title').text.split(':')[0]) message = (i.find('title').text.split(':')[1]).encode('ascii', 'ignore') noticeID = int(str(i.find('guid').text).split('/')[-1]) statusList.append((noticeID, username, message)) except Exception as e: print 'Could not parse statuses. Tell the programmer he\'s horrible.' print 'Send him this, too:' print e sys.exit() return statusList #Processes a congratulatory message by checking their page, #and getting the correct message to respond to. #Otherwise it may respond to the wrong message if someone posts multiple times in a few seconds. #Also handles if their messages were deleted, reducing their count since last checked. def processCongratulate(user, number): url = 'http://rainbowdash.net/'+str(user)+'/rss' request = urllib2.Request(url, headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Firefox/31.'}) response = urllib2.urlopen(request) data = response.read() soup = BeautifulSoup(data) currentCount = getNoticeCount('http://rainbowdash.net/'+str(user)) targetNotice = (currentCount - number) if(targetNotice >= 0): replyTo = int(str(soup.findAll('item')[targetNotice].attrs[0][1]).split('/')[-1]) return replyTo else: userLink = 'http://rainbowdash.net/' + str(user) userDict[str(user)] = getNoticeCount(userLink) return None #Congratulates people for every 100,000th message it sees on the timeline. def specialCongratulate(user, number): global specialMessages postNotice(random.choice(specialMessages) % (user, number), 'Bot Lounge', number) return None #Congratulates people for every 1,000th message they've posted. def normalCongratulate(user, number, replyTo): global normalMessages, redMessages replyTo = processCongratulate(user, number) if not replyTo: return None if(str(user) == 'redenchilada'): postNotice(random.choice(redMessages) % (user, number), 'Excited Bot Lounge', replyTo) else: postNotice(random.choice(normalMessages) % (user, number), 'Bot Lounge', replyTo) return None #Adds a user to userDict with their post count. def newUserDict(user, replyTo): global userDict, welcomeNew userLink = 'http://rainbowdash.net/' + str(user) userDict[str(user)] = getNoticeCount(userLink) print 'Added ' + str(user) + ' to userDict. Post count: ' + str(userDict[str(user)]) if(userDict[str(user)] % 1000 == 0): normalCongratulate(user, userDict[str(user)], replyTo) elif(userDict[str(user)] == 1 and welcomeNew == 'y'): welcomeNewUser(str(user), replyTo) return None #Increments a user's post count in userDict rather than checking their profile each time. def updateUserDict(user, replyTo): global userDict userDict[str(user)] += 1 if(userDict[str(user)] % 1000 == 0 and userDict[str(user)] != 0): normalCongratulate(user, userDict[str(user)], replyTo) print str(user) + ' posted. New count: ' + str(userDict[str(user)]) return None #Gets newest post from the timeline and returns its ID. def newestNoticeID(): newNoticeID = 0 statusList = getStatuses() for i in statusList: if(i[0] > newNoticeID): newNoticeID = i[0] return newNoticeID #Runs checks on each status it hasn't seen before. #Knows if it's seen a message before based on the message's ID. #Higher ID, newer post. def findNewStatus(): global currentNoticeID, userDict, modList newMessage = False newNoticeID = currentNoticeID statusList = getStatuses() for i in statusList: if(i[0] > currentNoticeID): if('@lvbot welcoming on' in i[2] and i[1] in modList): welcomeponyOn(i[1], i[0]) elif('@lvbot welcoming off' in i[2] and i[1] in modList): welcomeponyOff(i[1], i[0]) if(i[1] in userDict): updateUserDict(i[1], i[0]) elif(i[1] not in userDict): print 'Adding ' + str(i[1]) + ' to userDict.' newUserDict(i[1], i[0]) newMessage = True if(i[0] > newNoticeID): newNoticeID = i[0] if(i[0] % 100000 == 0 and i[0] > currentNoticeID): specialCongratulate(i[1], i[0]) currentNoticeID = newNoticeID return newMessage #Turns welcomepony on/off def welcomeponyOn(username, replyTo): global welcomeNew postNotice('@'+str(username)+' understood! Turning welcomepony function on.', 'Welcomepony function on', replyTo) welcomeNew = 'y' def welcomeponyOff(username, replyTo): global welcomeNew postNotice('@'+str(username)+' understood! Turning welcomepony function off.', 'Welcomepony function off', replyTo) welcomeNew = 'n' #Welcomes new users to be better than WelcomePony def welcomeNewUser(user, replyTo): global welcomeMessages postNotice(random.choice(welcomeMessages) % user, 'Bot Lounge', replyTo) #currentNoticeID represents the most recent notice it read, #userDict stores how many posts each user has. #Special and normal messages for when people reach a 100,000th RDN message, #or 1,000th personal message respectively. welcomeMessages = ['@%s Welcome to RDN! I\'m a bot, but don\'t tell anybody.'] specialMessages = ['@%s Wow. That was RDN\'s %sth dash. That\'s a bunch.', '@%s You made RDN\'s %sth dash. Wow...'] normalMessages = ['@%s Wow, you reached your %sth message. Wow, wow, wow.', '@%s Whoah. %s posts? That\'s about how many times you\'ve posted here. Amazing coincidence.', '@%s Nice job. You reached your %sth post. I wish I had that many.', '@%s Astounding. %s posts. That\'s maybe a hundredth of how many times whats-his-name cried when he played the game [i]To The Moon[/i].'] redMessages = ['@%s Red, you just reached your %sth post.', '@%s You know what, Red? You just hit %s posts. How does it feel?', '@%s Red, hey, listen, hey, listen, Red, listen, you just hit %s posts.'] currentNoticeID = newestNoticeID() modList = ['lvbot', 'thelastgherkin', 'cabal', 'scoot', 'mushi', 'northernnarwhal', 'theyurityphoon', 'razzleberry'] userDict = {'username':'int'} username = str(raw_input('Bot username: ')) password = str(raw_input('Bot password: ')) welcomeNew = str(raw_input('Turn on welcoming function? y/n\n')) wait = 6 findNewStatus() while(1): try: print "Checking..." newMessage = findNewStatus() if(wait <= 38 and not newMessage): wait += 2 elif(newMessage): wait = 6 time.sleep(wait) except Exception as e: print 'The programmer must suck.' print e sys.exit()