tracer.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #!/usr/bin/env python3
  2. import socket
  3. import re
  4. from random import randint, choice
  5. import sys, os
  6. import time
  7. import subprocess
  8. import tracery
  9. import traceback
  10. from tracery.modifiers import base_english
  11. import json
  12. import random
  13. DB = {}
  14. def grammar(rules):
  15. try:
  16. res = tracery.Grammar(rules)
  17. res.add_modifiers(base_english)
  18. return res
  19. except Exception as e:
  20. print(e)
  21. def load_rules(path):
  22. try:
  23. with open(path) as f:
  24. return json.loads(f.read())
  25. except Exception as e:
  26. print(e)
  27. def populate():
  28. global DB
  29. DB = {}
  30. for subdir in os.listdir("/home"):
  31. d = f"/home/{subdir}/.tracery"
  32. if os.path.isdir(d):
  33. for p in os.listdir(d):
  34. rule = d + "/" + p
  35. name = p.replace(".json", "")
  36. # print(p, rule, name)
  37. if p in DB:
  38. DB[name].append(grammar(load_rules(rule)))
  39. else:
  40. DB[name] = [grammar(load_rules(rule))]
  41. populate()
  42. print(DB)
  43. def generate(rule):
  44. populate()
  45. if rule in DB:
  46. g = random.choice(DB[rule])
  47. return g.flatten("#origin#")
  48. def listify(col):
  49. if type(col) == type([]):
  50. return col
  51. else:
  52. return [col]
  53. def shuffle(col):
  54. a = random.choice(list(col))
  55. b = random.choice(list(col))
  56. if "origin" in [a, b]:
  57. print("origin discard")
  58. return col
  59. col[a], col[b] = col[b], col[a]
  60. return col
  61. def fuse(argv):
  62. populate()
  63. raw = {}
  64. for gk in argv:
  65. if gk in DB:
  66. g = random.choice(DB[gk]).raw
  67. for k in g:
  68. if k in raw:
  69. raw[k] = listify(raw[k]) + listify(g[k])
  70. else:
  71. raw[k] = g[k]
  72. for i in range(20):
  73. raw = shuffle(raw)
  74. return grammar(raw).flatten("#origin#")
  75. server = "127.0.0.1"
  76. channels = ["#bots", "#meta", "#team"]
  77. if len(sys.argv) > 1:
  78. for c in sys.argv[1:]:
  79. channels.append("#" + c)
  80. botnick = "tracer"
  81. def rawsend(msg):
  82. print(msg)
  83. ircsock.send(f"{msg}\r\n".encode())
  84. def send(chan, msg):
  85. # This is the send message function, it simply sends messages to the channel.
  86. rawsend(f"PRIVMSG #{chan} :{msg}")
  87. def think(chan, nick, msg):
  88. words = re.split("[ \t\s]+", msg)
  89. if len(words) > 0 and nick != "tracer":
  90. if words[0] == "!!list":
  91. res = ""
  92. for k in DB:
  93. res += k + " "
  94. send(chan, res[:475])
  95. elif words[0] == "!!fuse":
  96. if "|" in words:
  97. res = fuse(words[1 : words.index("|")])
  98. if res:
  99. send(chan, " ".join(words[words.index("|") + 1 :]) + " " + res)
  100. else:
  101. res = fuse(words[1:])
  102. if res:
  103. send(chan, res[0:475])
  104. elif words[0] == "!!source":
  105. send(chan, "https://tildegit.org/ben/tracer")
  106. elif words[0] == "!botlist" or words[0] == "!!help":
  107. send(
  108. chan,
  109. "helo i'm a tracery bot that makes cool things from tracery grammars in your ~/.tracery. see http://tracery.io for more info",
  110. )
  111. elif words[0][0:2] == "!!":
  112. print(words)
  113. res = generate(words[0][2:])
  114. if res:
  115. if len(words) >= 3:
  116. if words[1] == "|":
  117. send(chan, " ".join(words[2:]) + " " + res)
  118. else:
  119. send(chan, res)
  120. else:
  121. send(chan, res)
  122. if __name__ == "__main__":
  123. ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  124. ircsock.connect((server, 6667)) # Here we connect to the server using port 6667
  125. rawsend(f"NICK {botnick}") # here we actually assign the nick to the bot
  126. rawsend(f"USER {botnick} 0 * :tracery bot") # user authentication
  127. while 1:
  128. msg = ircsock.recv(2048).decode().split("\r\n")
  129. for ircmsg in msg:
  130. print(ircmsg)
  131. if "PING" in ircmsg:
  132. rawsend(ircmsg.replace("I", "O", 1))
  133. if "INVITE" in ircmsg:
  134. chan = ircmsg.split(":")[-1]
  135. rawsend(f"JOIN {chan}")
  136. if "001" in ircmsg:
  137. for c in channels:
  138. rawsend(f"JOIN {c}")
  139. rawsend(f"MODE {botnick} +B")
  140. m = re.match(
  141. ":(?P<nick>[^ ]+)!.*PRIVMSG #(?P<chan>\w+) :(?P<msg>.*)", ircmsg
  142. )
  143. if m and m.groupdict():
  144. m = m.groupdict()
  145. try:
  146. think(m["chan"], m["nick"], m["msg"])
  147. except Exception as e:
  148. print("ERROR" + str(m))
  149. print(e)
  150. traceback.print_exc()