irc.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. # -*- coding:utf-8 -*-
  2. import socket
  3. import re
  4. from time import sleep
  5. class noaIRC(object):
  6. def __init__(self, host, port, user, key, channel):
  7. """
  8. Authentificate the bot over Twitch IRC
  9. """
  10. self.__channel = channel
  11. self.__compiledBanWords = []
  12. # configure socket and try to join IRC channel
  13. self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  14. self.__sock.connect((host, port))
  15. self.__sock.settimeout(1)
  16. self.__sock.send("PASS {}\r\n".format(key).encode("utf-8"))
  17. self.__sock.send("NICK {}\r\n".format(user).encode("utf-8"))
  18. self.__sock.send("JOIN {}\r\n".format(channel).encode("utf-8"))
  19. def setPattern(self, pattern):
  20. """
  21. Allow to set message pattern in order to check whether the posted message
  22. is a real message and not service message
  23. """
  24. self.__message_pattern = re.compile(r"%s" % pattern)
  25. def setMySQLconnector(self, connector):
  26. """
  27. Allow to set mysql connector get persistance
  28. """
  29. self.__mysql = connector
  30. def __getAllowedCommands(self, command):
  31. rights = {
  32. "ban" : ["admin"],
  33. "rban" : ["admin"],
  34. "quote" : ["admin", "default"]
  35. }
  36. return rights[command] if command in rights.keys() else None
  37. def __isAuthorized(self, command, username):
  38. """
  39. Return whether user is authorized to use command
  40. """
  41. # Get user role
  42. allowedGroups = self.__getAllowedCommands(command)
  43. if not allowedGroups:
  44. return False
  45. if 'default' in allowedGroups:
  46. return True
  47. for allowedGroup in allowedGroups:
  48. if username in self.__mysql.getUsers()[allowedGroup]:
  49. return True
  50. def __chat(self, msg):
  51. """
  52. Send a chat message to the server.
  53. Keyword arguments:
  54. sock -- the socket over which to send the message
  55. msg -- the message to be sent
  56. """
  57. self.__sock.send("PRIVMSG %s :%s\r\n" % (self.__channel, msg.encode('utf-8')))
  58. def __timeout(self, username, timeout=5):
  59. """
  60. Timeout a user
  61. """
  62. self.__chat(u"Timeout %ds %s (warning)" % (timeout, username))
  63. self.__sock.send("PRIVMSG %s :/timeout %s 5 \r\n" % (self.__channel, username))
  64. def __call(self, command, parameters, username):
  65. """
  66. Execute a command
  67. """
  68. if not self.__isAuthorized(command, username):
  69. return
  70. # Remove final carriage return
  71. parameters = parameters.replace("\r", "")
  72. # Moderation
  73. if command == 'ban' and len(parameters) :
  74. banword = parameters.split(' ')[0].replace("\r", "")
  75. if banword in ['***', '']:
  76. return
  77. self.__compiledBanWords.append(re.compile(r'%s'%(banword)))
  78. self.__mysql.addSwearword(banword)
  79. self.__chat(u"Mot interdit ajouté")
  80. if command == "rban" and len(parameters):
  81. banword = parameters.split(' ')[0]
  82. index = self.__mysql.delSwearword(banword)
  83. if index is not None:
  84. del self.__compiledBanWords[index]
  85. self.__chat(u"Mot interdit supprimé")
  86. # Quoting system
  87. if command == 'quote' and len(parameters) :
  88. if parameters.startswith("#"):
  89. index = int(parameters[1:]) - 1
  90. if index < 0:
  91. return
  92. message = self.__mysql.getQuote(index)
  93. if message:
  94. self.__chat(message)
  95. else:
  96. self.__mysql.addQuote(parameters)
  97. def __parseMessage(self, message, username):
  98. """
  99. Check message
  100. """
  101. # check swearword
  102. groups = self.__mysql.getUsers()
  103. for swearword in self.__compiledBanWords:
  104. if swearword.search(message) is not None and not username in groups['admin'] and not username in groups['moderator']:
  105. self.__timeout(username)
  106. # command pattern
  107. command_pattern = re.compile(r'^!(\w+)\s?(.*)')
  108. matches = re.search(command_pattern, message)
  109. if matches:
  110. command = matches.group(1)
  111. parameters = matches.group(2)
  112. self.__call(command, parameters, username)
  113. def run(self):
  114. """
  115. Core loop
  116. """
  117. # Compile ban patterns
  118. for banword in self.__mysql.getSwearwords():
  119. self.__compiledBanWords.append(re.compile(r'%s'%(banword)))
  120. while True:
  121. try:
  122. response = self.__sock.recv(1024).decode("utf-8")
  123. except socket.error, e:
  124. continue
  125. else:
  126. if response == "PING :tmi.twitch.tv\r\n":
  127. self.__sock.send("PONG :tmi.twitch.tv\r\n".encode("utf-8"))
  128. print "pong"
  129. else:
  130. matches = re.search(self.__message_pattern, response)
  131. if matches:
  132. username = matches.group(1)
  133. message = matches.group(2)
  134. self.__parseMessage(message, username)
  135. sleep(0.1)