An IRC bot built for tubes
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

144 行
4.1KB

  1. #!/usr/bin/python3
  2. # See the LICENSE file for licensing information
  3. import re
  4. from time import sleep
  5. from random import choice
  6. nick = 'seddy'
  7. server = 'chat.freenode.net'
  8. channel = '#example'
  9. gecos = 'A text processing bot'
  10. receive = '/tmp/{0}.in'.format(server)
  11. send = '/tmp/{0}.out'.format(server)
  12. parse_msg = re.compile('.* PRIVMSG ' + channel + ' :(.*)')
  13. parse_sed = re.compile('(?<!\\\\)/')
  14. is_sed = re.compile('^s/.*/.*')
  15. ping = re.compile('PING :(.*)')
  16. class Queue:
  17. size = 0
  18. data = []
  19. head = 0
  20. tail = 0
  21. count = 0
  22. def __init__(self, size):
  23. self.size = size
  24. self.data = [None]*size
  25. def enqueue(self, s):
  26. if not self.full():
  27. self.count += 1
  28. self.data[self.tail] = s
  29. self.tail = (self.tail + 1) % self.size
  30. def dequeue(self):
  31. if not self.empty():
  32. self.count -= 1
  33. s = self.data[self.head]
  34. self.head = (self.head + 1) % self.size
  35. return s
  36. def full(self):
  37. return self.size == self.count
  38. def empty(self):
  39. return self.head == self.count
  40. def find(self, s, f=0):
  41. i = self.tail-1
  42. while True:
  43. if i == -1:
  44. i = self.size-1
  45. if re.search(s, self.data[i], f):
  46. return self.data[i]
  47. i -= 1
  48. if i == self.tail-1 or self.data[i] is None:
  49. return False
  50. def msg_replace(find, replace, msg, f, n=1):
  51. try:
  52. if msg[:7] == '\x01ACTION':
  53. res = '\x01ACTION {0}'.format(re.sub(find, replace, msg[8:], count=n, flags=f))
  54. else:
  55. res = re.sub(find, replace, msg, count=n, flags=f)
  56. except:
  57. return False
  58. return res
  59. def seddy(sed, history, parser):
  60. f = 0
  61. regex = parser.split(sed)
  62. if len(regex) < 4:
  63. return False
  64. if 'i' in regex[3]:
  65. f |= re.I
  66. try:
  67. msg = history.find(regex[1], f)
  68. except:
  69. return False
  70. if "g" in regex[3]:
  71. res = msg_replace(regex[1], regex[2], msg, f, n=0)
  72. else:
  73. res = msg_replace(regex[1], regex[2], msg, f)
  74. if res:
  75. res = res.replace('\0', re.search(regex[1], msg, f).group(0))
  76. return res
  77. def notice(msg, channel):
  78. with open(send, 'w', encoding='utf-8') as g:
  79. g.write('NOTICE ' + channel + ' :' + msg + '\r\n')
  80. def privmsg(msg, channel):
  81. if msg[:7] == '\x01ACTION':
  82. with open(send, 'w', encoding='utf-8') as g:
  83. g.write('PRIVMSG ' + channel + ' :' + '\x01' +
  84. ''.join(c for c in msg if c.isprintable()) + '\x01\r\n')
  85. else:
  86. with open(send, 'w', encoding='utf-8') as g:
  87. g.write('PRIVMSG ' + channel + ' :' +
  88. msg.replace('\n', ' ',).replace('\r', '') + '\r\n')
  89. if __name__ == "__main__":
  90. history = Queue(48)
  91. with open(send, 'w', encoding='utf-8') as f:
  92. f.write('NICK ' + nick + '\r\n')
  93. f.write('USER ' + nick + ' * 8 :' + gecos + '\r\n')
  94. sleep(5)
  95. f.write('JOIN ' + channel + '\r\n')
  96. with open(receive, 'r', encoding='utf-8') as f:
  97. for line in f:
  98. if 'PING' in line:
  99. with open(send, 'w', encoding='utf-8') as g:
  100. g.write('PONG {0}\r\n'.format(ping.split(line)[1]))
  101. continue
  102. m = parse_msg.match(line)
  103. try:
  104. msg = m.group(1)
  105. except:
  106. continue
  107. if history.full():
  108. history.dequeue()
  109. if 'PRIVMSG' in line and not is_sed.match(msg):
  110. history.enqueue(msg)
  111. if '.bots' in msg[:5] or '.bot ' + nick in msg[:5 + len(nick)]:
  112. notice("I was written to correct your mistakes.", channel)
  113. if '.source ' + nick in msg[:8 + len(nick)]:
  114. notice('[Python] https://github.com/sys-fs/seddy', channel)
  115. elif is_sed.match(msg):
  116. res = seddy(msg, history, parse_sed)
  117. if res:
  118. res = re.sub('\\\\/', '/', res)
  119. if history.full():
  120. history.dequeue()
  121. history.enqueue(res)
  122. privmsg(res, channel)