tracer/tracer.py

178 lines
4.4 KiB
Python

#!/usr/bin/env python3
from random import randint, choice
from tracery.modifiers import base_english
import configparser
import glob
import json
import os
import random
import re
import socket
import subprocess
import sys
import time
import traceback
import tracery
DB = {}
config = configparser.ConfigParser(
converters={"list": lambda x: [i.strip() for i in x.split(",")]}
)
config.read("config.ini")
bot = config["irc"]
def grammar(rules):
try:
res = tracery.Grammar(rules)
res.add_modifiers(base_english)
return res
except Exception as e:
print(e)
def load_rules(path):
try:
with open(path) as f:
return json.loads(f.read())
except Exception as e:
print(e)
def populate():
global DB
DB = {}
for p in glob.glob("/home/*/.tracery/*"):
name, ext = os.path.splitext(p)
if name.startswith(".") or ext not in (".json", ""):
continue
if p in DB:
DB[name].append(grammar(load_rules(p)))
else:
DB[name] = [grammar(load_rules(p))]
populate()
def generate(rule):
populate()
if rule in DB:
g = random.choice(DB[rule])
return g.flatten("#origin#")
def listify(col):
if type(col) == type([]):
return col
else:
return [col]
def shuffle(col):
a = random.choice(list(col))
b = random.choice(list(col))
if "origin" in [a, b]:
return col
col[a], col[b] = col[b], col[a]
return col
def fuse(argv):
populate()
raw = {}
for gk in argv:
if gk in DB:
g = random.choice(DB[gk]).raw
for k in g:
if k in raw:
raw[k] = listify(raw[k]) + listify(g[k])
else:
raw[k] = g[k]
for i in range(20):
raw = shuffle(raw)
return grammar(raw).flatten("#origin#")
def rawsend(msg):
print(msg)
ircsock.send(f"{msg}\r\n".encode())
def send(chan, msg):
rawsend(f"PRIVMSG #{chan} :{msg}")
def think(chan, nick, msg):
words = re.split("[ \t\s]+", msg)
if len(words) > 0 and nick != bot["nick"]:
if words[0] == "!!list":
res = ""
for k in DB:
res += k + " "
send(chan, res[:475])
elif words[0] == "!!fuse":
if "|" in words:
res = fuse(words[1 : words.index("|")])
if res:
send(chan, " ".join(words[words.index("|") + 1 :]) + " " + res)
else:
res = fuse(words[1:])
if res:
send(chan, res[0:475])
elif words[0] == "!!source":
send(chan, "https://tildegit.org/ben/tracer")
elif words[0] == "!botlist" or words[0] == "!!help":
send(
chan,
"helo i'm a tracery bot that makes cool things from tracery grammars in your ~/.tracery. see http://tracery.io for more info",
)
elif words[0][0:2] == "!!":
print(words)
res = generate(words[0][2:])
if res:
if len(words) >= 3:
if words[1] == "|":
send(chan, " ".join(words[2:]) + " " + res)
else:
send(chan, res)
else:
send(chan, res)
if __name__ == "__main__":
ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ircsock.connect((bot["server"], int(bot["port"])))
rawsend("NICK %s" % bot["nick"])
rawsend("USER %s 0 * :tracery bot" % bot["nick"])
while 1:
for msg in ircsock.recv(2048).decode().split("\r\n"):
print(msg)
if "PING" in msg:
rawsend(msg.replace("I", "O", 1))
if "INVITE" in msg:
chan = msg.split(":")[-1]
rawsend(f"JOIN {chan}")
if "001" in msg:
for c in bot.getlist("channels"):
rawsend(f"JOIN {c}")
rawsend("MODE %s +B" % bot["nick"])
m = re.match(
":(?P<nick>[^ ]+)!.*PRIVMSG #(?P<chan>\w+) :(?P<msg>.*)", msg
)
if m and m.groupdict():
m = m.groupdict()
try:
think(m["chan"], m["nick"], m["msg"])
except Exception as e:
print("ERROR" + str(m))
print(e)
traceback.print_exc()