Advertisement
Guest User

Untitled

a guest
May 2nd, 2025
10
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.97 KB | None | 0 0
  1. import socket
  2. import threading
  3. import re
  4. import time
  5.  
  6. server = 'irc.retronode.org'
  7. port = 6667
  8. channel = '#downgrade'
  9. botnick = 'PollBot'
  10.  
  11. poll = {
  12. 'question': '',
  13. 'options': [],
  14. 'votes': {},
  15. 'active': False,
  16. 'start_time': None,
  17. 'duration': None,
  18. 'maxvotes': 1,
  19. 'maxselect': 1
  20. }
  21.  
  22. def send_msg(sock, msg):
  23. sock.send((msg + "\r\n").encode('utf-8'))
  24.  
  25. def send_privmsg(sock, target, msg):
  26. send_msg(sock, f"PRIVMSG {target} :{msg}")
  27.  
  28. def parse_poll_command(text):
  29. return re.findall(r'"(.*?)"', text)
  30.  
  31. def poll_results():
  32. tally = [0] * len(poll['options'])
  33. for user_votes in poll['votes'].values():
  34. for v in user_votes:
  35. if 1 <= v <= len(tally):
  36. tally[v - 1] += 1
  37. total = sum(tally)
  38. results = []
  39. for i, count in enumerate(tally):
  40. percent = (count / total * 100) if total > 0 else 0
  41. results.append(f"{i+1}. {poll['options'][i]} - {percent:.1f}%")
  42. return results
  43.  
  44. def handle_vote(user, message):
  45. if not poll['active']:
  46. return "No active poll."
  47. try:
  48. selections = list(map(int, message.strip().split()))
  49. if len(selections) > poll['maxselect']:
  50. return f"You can only select {poll['maxselect']} options per vote."
  51.  
  52. for v in selections:
  53. if v < 1 or v > len(poll['options']):
  54. return f"Invalid option: {v}. Valid options are 1 to {len(poll['options'])}."
  55.  
  56. existing_votes = poll['votes'].get(user, [])
  57. remaining_votes = poll['maxvotes'] - len(existing_votes)
  58. if remaining_votes <= 0:
  59. return f"You have already used all {poll['maxvotes']} of your votes."
  60.  
  61. allowed_votes = selections[:remaining_votes]
  62. poll['votes'].setdefault(user, []).extend(allowed_votes)
  63.  
  64. if len(allowed_votes) < len(selections):
  65. return f"Partial vote registered: only {remaining_votes} votes allowed. Others ignored."
  66. return "Vote registered."
  67. except:
  68. return "Invalid vote format. Use numbers like: 1 or 2 3"
  69.  
  70. def end_poll(sock, target):
  71. poll['active'] = False
  72. results = poll_results()
  73. send_privmsg(sock, target, "Poll ended. Results:")
  74. for r in results:
  75. send_privmsg(sock, target, r)
  76.  
  77. def poll_timer(sock):
  78. while True:
  79. if poll['active'] and poll['duration'] is not None:
  80. if time.time() - poll['start_time'] > poll['duration']:
  81. end_poll(sock, channel)
  82. time.sleep(1)
  83.  
  84. def extract_nick(prefix, message):
  85. if prefix.startswith(":DMconnect_Bridge!"):
  86. match = re.match(r"<([^>]+)>\s+(.*)", message)
  87. if match:
  88. return match.group(1), match.group(2)
  89. else:
  90. return "unknown_bridge_user", message
  91. else:
  92. return prefix.split('!')[0][1:], message
  93.  
  94. def main():
  95. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  96. try:
  97. sock.connect((server, port))
  98. except ConnectionRefusedError:
  99. print("Connection refused — check if the IRC server is reachable.")
  100. return
  101.  
  102. send_msg(sock, f"NICK {botnick}")
  103. send_msg(sock, f"USER {botnick} 0 * :Poll Bot")
  104.  
  105. threading.Thread(target=poll_timer, args=(sock,), daemon=True).start()
  106.  
  107. while True:
  108. resp = sock.recv(2048).decode("utf-8", errors='ignore')
  109. for line in resp.strip().split("\r\n"):
  110. print(line)
  111. if line.startswith("PING"):
  112. send_msg(sock, "PONG " + line.split()[1])
  113. continue
  114.  
  115. parts = line.split()
  116. if len(parts) < 2:
  117. continue
  118.  
  119. if parts[1] == "001":
  120. send_msg(sock, f"JOIN {channel}")
  121. elif parts[1] == "PRIVMSG":
  122. prefix = line.split(' ')[0]
  123. target = parts[2]
  124. message = ' '.join(parts[3:])[1:].strip()
  125. user, message = extract_nick(prefix, message)
  126.  
  127. is_private = target == botnick
  128. reply_target = user if is_private else channel
  129.  
  130. if message.startswith("!poll "):
  131. items = parse_poll_command(message)
  132. if len(items) >= 2:
  133. poll['question'] = items[0]
  134. poll['options'] = items[1:]
  135. poll['votes'] = {}
  136. poll['active'] = False
  137. poll['duration'] = None
  138. send_privmsg(sock, reply_target, f"Poll prepared: {poll['question']}")
  139. for i, opt in enumerate(poll['options']):
  140. send_privmsg(sock, reply_target, f"{i+1}. {opt}")
  141. send_privmsg(sock, reply_target, "Use !start to begin the poll.")
  142. else:
  143. send_privmsg(sock, reply_target, "Format: !poll \"Question?\" \"Option 1\" \"Option 2\" ...")
  144.  
  145. elif message.startswith("!set "):
  146. parts = message.split()
  147. if len(parts) == 3:
  148. key, val = parts[1], parts[2]
  149. if key in ['duration', 'maxvotes', 'maxselect']:
  150. if val.isdigit():
  151. poll[key] = int(val)
  152. send_privmsg(sock, reply_target, f"{key} set to {val}.")
  153. else:
  154. send_privmsg(sock, reply_target, "Value must be a number.")
  155. else:
  156. send_privmsg(sock, reply_target, "Allowed keys: duration, maxvotes, maxselect.")
  157. else:
  158. send_privmsg(sock, reply_target, "Usage: !set <duration|maxvotes|maxselect> <number>")
  159.  
  160. elif message.strip() == "!start":
  161. if poll['question'] and poll['options']:
  162. poll['active'] = True
  163. poll['start_time'] = time.time()
  164. send_privmsg(sock, channel, f"Poll started: {poll['question']}")
  165. for i, opt in enumerate(poll['options']):
  166. send_privmsg(sock, channel, f"{i+1}. {opt}")
  167. send_privmsg(sock, channel, f"Vote by typing numbers. Max votes per user: {poll['maxvotes']}, max options per vote: {poll['maxselect']}")
  168. else:
  169. send_privmsg(sock, reply_target, "Poll not defined yet.")
  170.  
  171. elif message.strip() == "!results":
  172. if poll['active']:
  173. end_poll(sock, reply_target)
  174. else:
  175. send_privmsg(sock, reply_target, "No active poll to end.")
  176.  
  177. elif poll['active'] and re.fullmatch(r"(\d+\s*)+", message.strip()):
  178. result = handle_vote(user, message)
  179. send_privmsg(sock, reply_target, result)
  180.  
  181. if __name__ == "__main__":
  182. main()
  183.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement