replace.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. ##NEEDS
  2. #adding a bold character for '<user> MEANT so say'
  3. from event import Event
  4. import requests
  5. try:
  6. from basemodule import BaseModule
  7. except ImportError:
  8. from modules.basemodule import BaseModule
  9. class Replace(BaseModule):
  10. def post_init(self):
  11. self.bot.mem_store['replace'] = {}
  12. replace = Event("__.r__")
  13. replace.define(msg_definition=".*")
  14. replace.subscribe(self)
  15. self.bot.register_event(replace, self)
  16. self.help = ".r <search string> | <replacement text> OR s/<search string>/<replacement string>"
  17. self.MAX_BUFFER_SIZE = 300
  18. self.MAX_HISTORY_SIZE = 10
  19. def add_buffer(self, event=None, debug=False):
  20. """Takes a channel name and line passed to it and stores them in the bot's mem_store dict
  21. for future access. The dict will have channel as key. The value to that key will be a list
  22. of formatted lines of activity.
  23. If the buffer size is not yet exceeded, lines are just added. If the buffer
  24. is maxed out, the oldest line is removed and newest one inserted at the beginning.
  25. """
  26. if debug:
  27. print "Line: " + event.line
  28. print "Verb: " + event.verb
  29. print "Channel: " + event.channel
  30. print ""
  31. if not event:
  32. return
  33. #there are certain things we want to record in history, like nick changes and quits
  34. #these often add to the humor of a quote. however, these are not specific to a channel
  35. #in IRC and our bot does not maintain a userlist per channel. Therefore, when nick
  36. #changes and quits occur, we will add them to every buffer. This is not technically
  37. #correct behavior and could very well lead to quits/nick changes that are not visible
  38. #showing up in a quote, but it's the best we can do at the moment
  39. if not event.channel:
  40. #discard events with unwanted verbs
  41. if event.verb not in ["QUIT", "NICK"]:
  42. return
  43. try:
  44. for chan in self.bot.mem_store['replace'].keys():
  45. if len(self.bot.mem_store['replace'][chan]) >= self.MAX_BUFFER_SIZE:
  46. self.bot.mem_store['replace'][chan].pop()
  47. line = self.format_line(event)
  48. if line:
  49. self.bot.mem_store['replace'][chan].insert(0, line)
  50. except KeyError, IndexError:
  51. print "Replace add_buffer() error when no event channel"
  52. #now we continue with normal, per channel line addition
  53. #create a dictionary associating the channel with an empty list if it doesn't exist yet
  54. # END if not event.channel:
  55. else:
  56. if event.channel not in self.bot.mem_store['replace']:
  57. self.bot.mem_store['replace'][event.channel] = []
  58. try:
  59. #check for the length of the buffer. if it's too long, pop the last item
  60. if len(self.bot.mem_store['replace'][event.channel]) >= self.MAX_BUFFER_SIZE:
  61. self.bot.mem_store['replace'][event.channel].pop()
  62. #get a line by passing event to format_line
  63. #insert the line into the first position in the list
  64. line = self.format_line(event)
  65. if line:
  66. self.bot.mem_store['replace'][event.channel].insert(0, line)
  67. except IndexError:
  68. print "Replace add_buffer() error. Couldn't access the list index."
  69. def format_line(self, event):
  70. """Takes an event and formats a string appropriate for quotation from it"""
  71. #format all strings based on the verb
  72. if event.verb == "":
  73. return ''
  74. elif event.verb == "PRIVMSG":
  75. #special formatting for ACTION strings
  76. if event.msg.startswith('\001ACTION'):
  77. #strip out the word ACTION from the msg
  78. return ' * %s %s\n' % (event.user, event.msg[7:])
  79. else:
  80. return '<%s> %s\n' % (event.user, event.msg)
  81. else:
  82. #no matching verbs found. just ignore the line
  83. return ''
  84. def get_replacement_message(self, channel=None, find_msg=''):
  85. """Looks through the mem_store to find the most recent message containing find_msg"""
  86. if not channel:
  87. #print "couldnt find channel"
  88. return None
  89. #must have at least one msg to search for and channel to look it up in
  90. if len(find_msg) == 0 or not channel:
  91. #print "find_msg is empty"
  92. return None
  93. #search for a matching string and saves the index of that entry.
  94. #Searches from most recent to oldest.
  95. found_index = -1
  96. for index, line in enumerate(self.bot.mem_store['replace'][channel]):
  97. message = line
  98. msg_index = message.find(">")
  99. message = message[msg_index:]
  100. #print line
  101. #if the current entry of mem_store contains our string, we set the index and then BREAK to stop looking
  102. if find_msg.decode('utf-8','ignore') in message:
  103. found_index = index
  104. break
  105. #check to see if index values are positive. if not, string was not found and we're done
  106. if found_index == -1 :
  107. #print "couldnt find a good match"
  108. return None
  109. #returns the entire line
  110. submission = self.bot.mem_store['replace'][channel][found_index]
  111. return submission
  112. def handle(self, event):
  113. #first we see if we're going to try a replace or just add a line to the mem_store
  114. if event.msg.startswith(".r "):
  115. #split the msg with '.r ' stripped off beginning and divide into a search string and replace string
  116. string_token = event.msg[3:].split('|', 1)
  117. find_msg = string_token[0].rstrip()
  118. try:
  119. replace_msg = string_token[1].lstrip() #if there's nothing after the pipe, then this resolves to '' which is fine
  120. except IndexError:
  121. return
  122. #looking for a message containing our search string
  123. newString = self.get_replacement_message(event.channel, find_msg)
  124. #because the mem_store line shows "<user> message", we have to split up the username and their message
  125. #this actually works to our advantage so we dont have to do additional calls to find out who sent what
  126. msg_index = newString.find(">")
  127. message = newString[msg_index + 2:]
  128. message = message.replace(find_msg, replace_msg)
  129. user = newString[1:msg_index]
  130. #pybot sends the new replacement message to the chat
  131. self.say(event.channel, user + " MEANT to say: " + message)
  132. # because both .r and s// are valid formats now
  133. if event.msg.startswith("s/"):
  134. #alternative notation: s/<substring to replace>/<substring to replace with>
  135. string_token = event.msg[2:].split('/', 1)
  136. find_msg = string_token[0]
  137. try:
  138. replace_msg = string_token[1]
  139. except IndexError:
  140. return
  141. #looking for a message containing our search string
  142. newString = self.get_replacement_message(event.channel, find_msg)
  143. #because the mem_store line shows "<user> message", we have to split up the username and their message
  144. #this actually works to our advantage so we dont have to do additional calls to find out who sent what
  145. msg_index = newString.find(">")
  146. message = newString[msg_index + 2:]
  147. message = message.replace(find_msg, replace_msg)
  148. user = newString[1:msg_index]
  149. #pybot sends the new replacement message to the chat
  150. self.say(event.channel, user + " MEANT to say: " + message)
  151. if event.user != self.bot.NICK :
  152. self.add_buffer(event)