Advertisement
Guest User

Frowtch Bot

a guest
Mar 22nd, 2018
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.97 KB | None | 0 0
  1. import socket, signal, datetime
  2. import xml.etree.ElementTree as ET
  3.  
  4. HOST="irc.twitch.tv"
  5. PORT=6667
  6. NICK="frowtch"
  7. PASS="oauth:t77l7kas71630g2dot1t2fnwqb8iy1"
  8. IDENT="frowtch"
  9. REALNAME="frowtch"
  10. INIT_CHANNEL="#frowtch"
  11. ADMIN="frowtch"
  12. SAVE_FILE='data.xml'
  13. MIN_DELAY=datetime.timedelta(0,1,500000) # 1.5 second delay between sent messages
  14.  
  15. # channel_info = {channel : Info()}
  16. channel_info = dict()
  17. time_last_sent = datetime.datetime.now()
  18.  
  19. class Info():
  20.  
  21. users = set()
  22. ignlist=[]
  23. queue = []
  24. players = set()
  25.  
  26. def __init__(self, trusted = set(), size = 1, toggle = True, connect = True):
  27. self.trusted = trusted
  28. self.size = size
  29. self.toggle = toggle
  30. self.connect = connect
  31.  
  32. def __str__(self):
  33. return 'Trusted: ' + str(self.trusted) + ' | Size: ' + str(self.size) + ' | Toggle: ' + str(self.toggle) + ' | Connect: ' + str(self.connect)
  34.  
  35. def join(self):
  36. self.connect = True
  37.  
  38. def part(self):
  39. self.users.clear()
  40. self.queue_clear()
  41. self.connect = False
  42.  
  43. def is_trusted(self, user):
  44. return user in self.trusted
  45.  
  46. def trust(self, user, flag):
  47. if flag:
  48. self.trusted.add(user)
  49. elif user in self.trusted:
  50. self.trusted.remove(user)
  51.  
  52. def new_group(self):
  53. # Add old group back into queue if still in room
  54. for name in self.players:
  55. if name in self.users and name not in self.queue:
  56. self.queue.append(name)
  57.  
  58. self.players.clear()
  59.  
  60. temp = 0
  61. while len(self.queue) > 0 and temp < self.size:
  62. self.players.add(self.queue.pop(0))
  63. temp += 1
  64.  
  65. def add(self, user):
  66. self.users.add(user)
  67.  
  68. def remove(self, user):
  69. if user in self.users:
  70. self.users.remove(user)
  71. self.queue_remove(user)
  72.  
  73. def queue_add(self, user, ign):
  74. if user not in self.queue and user not in self.players:
  75. if ign !="":
  76. self.ignlist.append(user+"["+ign+"]")
  77. self.queue.append(user)
  78. return True
  79. else:
  80. return False
  81.  
  82. def queue_remove(self, user):
  83. if user in self.queue:
  84. del self.ignlist[self.queue.index(user)]
  85. self.queue.remove(user)
  86. return 'Q'
  87.  
  88. if user in self.players:
  89. self.players.remove(user)
  90. if len(self.queue) > 0:
  91. new_player = self.queue.pop(0)
  92. self.players.add(new_player)
  93. return 'R' + new_player
  94. else:
  95. return 'D'
  96.  
  97. return 'N'
  98.  
  99. def queue_size(self):
  100. return len(self.queue)
  101.  
  102. def queue_position(self, user):
  103. return self.queue.index(user) + 1 if user.lower() in self.queue else -1
  104.  
  105. def ignlist_position(self, user):
  106. return self.ignlist.index(user) + 1 if user.lower() in self.ignlist else -1
  107.  
  108. def queue_clear(self):
  109. del self.queue[:]
  110. #self.queue.clear()
  111. self.players.clear()
  112.  
  113. def connect():
  114. global s
  115. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  116. s.connect((HOST, PORT))
  117. s.send(("PASS %s\r\n" % PASS).encode())
  118. s.send(("NICK %s\r\n" % NICK).encode())
  119. s.send(("USER %s %s bla :%s\r\n" % (IDENT, HOST, REALNAME)).encode())
  120.  
  121. for channel in channel_info:
  122. if channel_info[channel].connect:
  123. join(channel)
  124.  
  125. def join(channel):
  126. if channel not in channel_info:
  127. channel_info[channel] = Info()
  128. else:
  129. channel_info[channel].join()
  130. s.send(("JOIN %s\r\n" % channel).encode())
  131.  
  132. def part(channel):
  133. s.send(("PART %s\r\n" % channel).encode())
  134.  
  135. try:
  136. channel_info[channel].part()
  137. save_data()
  138. except KeyError:
  139. print(" > part: No channel_info for %s" % channel)
  140.  
  141. # Save channel_info to an XML file
  142. # TODO clear data from old channels
  143. def save_data():
  144. tree = ET.ElementTree(ET.Element('data'))
  145. root = tree.getroot()
  146.  
  147. for channel in channel_info:
  148. chan = ET.SubElement(root, 'channel', {'name' : channel})
  149. ET.SubElement(chan, 'size').text = str(channel_info[channel].size)
  150. ET.SubElement(chan, 'toggle').text = '1' if channel_info[channel].toggle else '0'
  151. ET.SubElement(chan, 'connect').text = '1' if channel_info[channel].connect else '0'
  152.  
  153. for name in channel_info[channel].trusted:
  154. ET.SubElement(chan, 'trusted', {'name':name})
  155.  
  156. tree.write(SAVE_FILE)
  157. print(" > Data saved to %s" % SAVE_FILE)
  158.  
  159. # Load channel_info from an XML file
  160. def load_data():
  161. try:
  162. tree = ET.ElementTree(None, SAVE_FILE)
  163.  
  164. root = tree.getroot()
  165. for channel in root.findall('channel'):
  166. channel_name = channel.get('name')
  167.  
  168. trust = set()
  169. for trusted in channel.findall('trusted'):
  170. trust.add(trusted.get('name'))
  171.  
  172. size = int(channel.find('size').text)
  173. toggle = True if int(channel.find('toggle').text) == 1 else False
  174. connect = True if int(channel.find('connect').text) == 1 else False
  175.  
  176. channel_info[channel_name] = Info(trust, size, toggle, connect)
  177. print(" > Data loaded from %s" % SAVE_FILE)
  178. except (OSError, IOError) as e:
  179. print(" > %s not found. Creating new %s" % (SAVE_FILE, SAVE_FILE))
  180. save_data()
  181.  
  182. def list_to_str(list):
  183. return ', '.join(list)
  184.  
  185. def parse_msg(msg):
  186. user = msg[0].split('!')[0][1:].strip()
  187. channel = msg[2].strip()
  188. content = ' '.join(msg[3:])[1:].strip()
  189. return user, channel, content
  190.  
  191. def admin_auth(user):
  192. return user==ADMIN
  193.  
  194. def broadcaster_auth(channel, user):
  195. return user==channel[1:]
  196.  
  197. def trusted_auth(channel, user):
  198. return channel_info[channel].is_trusted(user)
  199.  
  200. def sendWhisper(user, message):
  201. messageTemp = "PRIVMSG #jtv :.w " + user + " " + message
  202. s.send((messageTemp + "\r\n").encode('utf-8'))
  203. print("Sent whisper: " + messageTemp)
  204.  
  205.  
  206. # Due to the delay, some messages may be dropped
  207. def send_msg(channel, msg):
  208. global time_last_sent
  209. time_delta = datetime.datetime.now() - time_last_sent
  210. if time_delta > MIN_DELAY:
  211. print(" > send: %s" % msg)
  212. s.send(("PRIVMSG %s :%s\r\n" % (channel, msg)).encode())
  213. time_last_sent = datetime.datetime.now()
  214. else:
  215. print(" > MIN_DELAY: %s" % msg)
  216.  
  217. def main():
  218. load_data()
  219. connect()
  220. join(INIT_CHANNEL)
  221. readbuffer = ""
  222.  
  223. while True:
  224. # Receive data from IRC and spitting it into lines.
  225. readbuffer += s.recv(1024).decode('utf-8', 'replace')
  226.  
  227. if len(readbuffer) == 0:
  228. print(" > Disconnected! Attempting to reconnect...")
  229. connect()
  230.  
  231. temp = readbuffer.split("\n")
  232. readbuffer = temp.pop()
  233.  
  234. for line in temp:
  235. print(line)
  236. message = line.split(" ")
  237.  
  238. if (message[1]=='353'):
  239. temp = message[5:]
  240. temp[0] = temp[0][1:].strip()
  241.  
  242. for name in temp:
  243. user = name.strip()
  244. try:
  245. channel_info[message[4]].add(user)
  246. except KeyError:
  247. print(" > 353: No channel_info for %s" % channel)
  248.  
  249. # elif (message[1]=='JOIN'):
  250. # user, channel, content = parse_msg(message)
  251.  
  252. # try:
  253. # channel_info[channel].add(user)
  254. # except KeyError:
  255. # print(" > JOIN: No channel_info for %s" % channel)
  256.  
  257. # elif (message[1]=='PART'):
  258. # user, channel, content = parse_msg(message)
  259.  
  260. # try:
  261. # channel_info[channel].remove(user)
  262. # except KeyError:
  263. # print(" > PART: No channel_info for %s" % channel)
  264.  
  265. elif (message[1]=='PRIVMSG'):
  266. user, channel, content = parse_msg(message)
  267.  
  268. try:
  269. channel_info[channel].add(user)
  270. except KeyError:
  271. print(" > PRIVMSG: No channel_info for %s" % channel)
  272.  
  273. # Checks if the first character is a !, for commands.
  274. if (content[0]=='!'):
  275. split_content = content.split(' ')
  276. command = split_content[0]
  277. arg = split_content[1] if len(split_content) > 1 else None
  278.  
  279. # Checks what command was queried.
  280.  
  281. # BEGIN Debug commands
  282.  
  283. if (command=='!hello' and admin_auth(user)):
  284. send_msg(channel, "Kappa /")
  285.  
  286. elif (command=='!echo' and admin_auth(user)):
  287. send_msg(channel, content[6:])
  288.  
  289. elif (command=='!users' and admin_auth(user)):
  290. send_msg(channel, "Users: %s" % list_to_str(channel_info[channel].users))
  291.  
  292. elif (command=='!data' and admin_auth(user)):
  293. send_msg(channel, "DEBUG: %s" % channel_info[channel])
  294.  
  295. elif (command=='!quit' and admin_auth(user)):
  296. send_msg(INIT_CHANNEL, "ResidentSleeper /")
  297. s.send(('QUIT\r\n').encode())
  298. s.shutdown(socket.SHUT_RDWR)
  299. print("disconnected")
  300.  
  301. # END Debug commands
  302.  
  303. elif (command=='!trust' and (admin_auth(user) or broadcaster_auth(channel, user))):
  304. if (arg != None):
  305. channel_info[channel].trust(arg, True)
  306. send_msg(channel, "%s is now a trusted user" % arg)
  307. save_data()
  308.  
  309. elif (command=='!untrust' and (admin_auth(user) or broadcaster_auth(channel, user))):
  310. if (arg != None):
  311. channel_info[channel].trust(arg, False)
  312. send_msg(channel, "%s is no longer a trusted user" % arg)
  313. save_data()
  314.  
  315. # elif (command=='!join' and channel == INIT_CHANNEL):
  316. # if arg == None:
  317. # send_msg(channel, "Joining channel: %s" % user)
  318. # join('#'+user)
  319. # elif admin_auth(user):
  320. # send_msg(channel, "Joining channel: %s" % arg)
  321. # join('#'+arg)
  322.  
  323. # elif (command=='!remove'):
  324. # if channel == INIT_CHANNEL:
  325. # send_msg(channel, "Leaving: %s" % user)
  326. # part('#'+user)
  327. # elif admin_auth(user) or broadcaster_auth(channel, user):
  328. # send_msg(channel, "Leaving channel ResidentSleeper /")
  329. # part(channel)
  330.  
  331. # Add user to queue
  332. elif (command=='!join'):
  333. if len(split_content) == 2:
  334. queue_arg = split_content[1]
  335. elif len(split_content) == 3:
  336. queue_arg = split_content[1]+" "+split_content[2]
  337. else:
  338. queue_arg = None
  339. try:
  340. ign = queue_arg if queue_arg != None else user
  341. if channel_info[channel].queue_add(user, ign):
  342. send_msg(channel, "%s added to queue" % user)
  343. else:
  344. send_msg(channel, "%s is #%d in the queue" % (user, channel_info[channel].queue_position(user)))
  345. except KeyError:
  346. print(" > !queue add: No channel_info for %s" % channel)
  347.  
  348. # Remove user from queue or group. Admin can remove queue_arg
  349. elif (command=='!leave'):
  350. queue_arg = split_content[1] if len(split_content) > 1 else None
  351. try:
  352. remove_name = queue_arg if queue_arg != None and (admin_auth(user) or broadcaster_auth(channel, user) or trusted_auth(channel, user)) else user
  353. result = channel_info[channel].queue_remove(remove_name)
  354.  
  355. if result == 'Q':
  356. send_msg(channel, "%s removed from queue" % remove_name)
  357. elif result == 'D':
  358. send_msg(channel, "Dropped: %s" % remove_name)
  359. elif result[0] == 'R':
  360. send_msg(channel, "Replaced %s with %s" % (remove_name, result[1:]))
  361. elif result == 'N':
  362. send_msg(channel, "%s not in queue or group" % remove_name)
  363. except KeyError:
  364. print(" > !queue remove: No channel_info for %s" % channel)
  365.  
  366. # Show user's position in queue
  367. elif (command=='!position'):
  368. queue_arg = split_content[1] if len(split_content) > 1 else None
  369. try:
  370. name = queue_arg if queue_arg != None else user
  371. pos = channel_info[channel].queue_position(name)
  372. if pos > 0:
  373. send_msg(channel, "%s,your position in the queue is #%d out of %d" % (name, pos, channel_info[channel].queue_size()))
  374. else:
  375. send_msg(channel, " %s is not in the queue" % name)
  376. except KeyError:
  377. print(" > !queue position: No channel_info for %s" % channel)
  378.  
  379.  
  380. #BEGIN queue commands
  381.  
  382. # !queue command arg
  383. # Commands: !queue size/add/remove/position/setsize/new
  384. # TODO? add at index, shuffle, autoreplace options
  385. elif (command=='!queue'):
  386. if (arg != None):
  387. queue_command = arg
  388. queue_arg = split_content[2] if len(split_content) > 2 else None
  389.  
  390. if (queue_command=='on' and (admin_auth(user) or broadcaster_auth(channel, user) or trusted_auth(channel, user))):
  391. try:
  392. channel_info[channel].toggle = True
  393. send_msg(channel, "A queue has opened up for viewer games - type !join <IGN> to join! Example: !join Vicksy ")
  394. save_data()
  395. except KeyError:
  396. print(" > !queue on: No channel_info for %s" % channel)
  397.  
  398. elif (queue_command=='off' and (admin_auth(user) or broadcaster_auth(channel, user) or trusted_auth(channel, user))):
  399. try:
  400. channel_info[channel].toggle = False
  401. channel_info[channel].queue_clear()
  402. send_msg(channel, "The queue has been closed! Thanks everyone for playing!")
  403. save_data()
  404. except KeyError:
  405. print(" > !queue off: No channel_info for %s" % channel)
  406.  
  407. elif channel_info[channel].toggle:
  408. # Size of queue
  409. if (queue_command=='size'):
  410. try:
  411. send_msg(channel, "Size: %d" % channel_info[channel].queue_size())
  412. except KeyError:
  413. print(" > !queue size: No channel_info for %s" % channel)
  414.  
  415. # Clear the queue and current group
  416. elif (queue_command=='clear') and (admin_auth(user) or broadcaster_auth(channel, user) or trusted_auth(channel, user)):
  417. channel_info[channel].queue_clear()
  418. send_msg(channel, "Queue cleared")
  419. else:
  420. try:
  421. if channel_info[channel].queue_size() > 0:
  422. queue_message=""
  423. queue_message1=""
  424. for i in channel_info[channel].queue:
  425. pos = channel_info[channel].queue_position(i)
  426. queue_message= queue_message+"#%d: %s " %(pos, i)
  427.  
  428. #if channel_info[channel].queue_size() == 1:
  429. if admin_auth(user) or broadcaster_auth(channel, user) or trusted_auth(channel, user):
  430. for i in channel_info[channel].ignlist:
  431. pos1 = channel_info[channel].ignlist_position(i)
  432. queue_message1= queue_message1+"#%d: %s -- " %(pos1, i)
  433. sendWhisper(user, queue_message1 )
  434. else:
  435. send_msg(channel, queue_message )
  436.  
  437. else:
  438. send_msg(channel, "No one seems to be in queue at the moment, type !join <IGN> to join! ")
  439. except KeyError:
  440. print(" > !queue show: No channel_info for %s" % channel)
  441.  
  442.  
  443. #END queue commands
  444.  
  445. # Reply to PING with a PONG
  446. elif (message[0]=='PING'):
  447. print('PONG')
  448. s.send(('PONG %s\r\n' % line[1]).encode())
  449.  
  450. if __name__ == '__main__':
  451. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement