178 lines
4.4 KiB
Python
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()
|
|
|