2019-05-28 16:16:58 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
2019-01-29 02:33:35 +00:00
|
|
|
from random import randint, choice
|
|
|
|
from tracery.modifiers import base_english
|
2020-02-24 15:47:57 +00:00
|
|
|
import configparser
|
|
|
|
import glob
|
2020-03-11 18:10:44 +00:00
|
|
|
import irctokens
|
2019-01-29 02:33:35 +00:00
|
|
|
import json
|
2020-02-24 15:47:57 +00:00
|
|
|
import os
|
2019-01-29 02:33:35 +00:00
|
|
|
import random
|
2020-02-24 15:47:57 +00:00
|
|
|
import re
|
|
|
|
import socket
|
|
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
import time
|
|
|
|
import traceback
|
|
|
|
import tracery
|
2019-01-29 02:33:35 +00:00
|
|
|
|
|
|
|
DB = {}
|
2020-02-24 15:47:57 +00:00
|
|
|
config = configparser.ConfigParser(
|
|
|
|
converters={"list": lambda x: [i.strip() for i in x.split(",")]}
|
|
|
|
)
|
|
|
|
config.read("config.ini")
|
|
|
|
bot = config["irc"]
|
2019-01-29 02:33:35 +00:00
|
|
|
|
2020-02-24 16:32:56 +00:00
|
|
|
# read account info if it exists
|
|
|
|
if os.path.isfile("account.ini"):
|
|
|
|
account = configparser.ConfigParser()
|
|
|
|
account.read("account.ini")
|
|
|
|
account = account["nickserv"]
|
|
|
|
|
2019-05-28 17:31:21 +00:00
|
|
|
|
2019-01-29 02:33:35 +00:00
|
|
|
def grammar(rules):
|
|
|
|
try:
|
|
|
|
res = tracery.Grammar(rules)
|
|
|
|
res.add_modifiers(base_english)
|
|
|
|
return res
|
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
|
|
|
|
2019-05-28 17:31:21 +00:00
|
|
|
|
2019-01-29 02:33:35 +00:00
|
|
|
def load_rules(path):
|
|
|
|
try:
|
|
|
|
with open(path) as f:
|
|
|
|
return json.loads(f.read())
|
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
|
|
|
|
2019-05-28 17:31:21 +00:00
|
|
|
|
2019-01-29 02:33:35 +00:00
|
|
|
def populate():
|
|
|
|
global DB
|
|
|
|
DB = {}
|
2020-02-24 15:47:57 +00:00
|
|
|
for p in glob.glob("/home/*/.tracery/*"):
|
|
|
|
name, ext = os.path.splitext(p)
|
2020-02-24 16:32:56 +00:00
|
|
|
name = os.path.basename(name)
|
2020-02-24 15:47:57 +00:00
|
|
|
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))]
|
2019-01-29 02:33:35 +00:00
|
|
|
|
2019-05-28 17:31:21 +00:00
|
|
|
|
2019-01-29 02:33:35 +00:00
|
|
|
populate()
|
|
|
|
|
2019-05-28 17:31:21 +00:00
|
|
|
|
2019-01-29 02:33:35 +00:00
|
|
|
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]
|
|
|
|
|
2019-05-28 17:31:21 +00:00
|
|
|
|
2019-01-29 02:33:35 +00:00
|
|
|
def shuffle(col):
|
2019-06-25 02:58:42 +00:00
|
|
|
a = random.choice(list(col))
|
|
|
|
b = random.choice(list(col))
|
2019-05-28 17:31:21 +00:00
|
|
|
if "origin" in [a, b]:
|
2019-01-29 02:33:35 +00:00
|
|
|
return col
|
2019-05-28 17:47:59 +00:00
|
|
|
col[a], col[b] = col[b], col[a]
|
2019-01-29 02:33:35 +00:00
|
|
|
return col
|
|
|
|
|
2019-05-28 17:31:21 +00:00
|
|
|
|
2019-01-29 02:33:35 +00:00
|
|
|
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:
|
2019-05-28 17:31:21 +00:00
|
|
|
raw[k] = listify(raw[k]) + listify(g[k])
|
2019-01-29 02:33:35 +00:00
|
|
|
else:
|
|
|
|
raw[k] = g[k]
|
|
|
|
for i in range(20):
|
|
|
|
raw = shuffle(raw)
|
|
|
|
return grammar(raw).flatten("#origin#")
|
|
|
|
|
|
|
|
|
2020-03-11 18:10:44 +00:00
|
|
|
def _send(line):
|
|
|
|
print(f"> {line.format()}")
|
|
|
|
e.push(line)
|
|
|
|
while e.pending():
|
|
|
|
e.pop(s.send(e.pending()))
|
2019-01-29 02:33:35 +00:00
|
|
|
|
|
|
|
|
2019-05-28 17:31:21 +00:00
|
|
|
def send(chan, msg):
|
2020-03-11 18:10:44 +00:00
|
|
|
_send(irctokens.format("PRIVMSG", [chan, msg]))
|
2019-01-29 02:33:35 +00:00
|
|
|
|
|
|
|
|
2020-03-11 18:10:44 +00:00
|
|
|
def think(line):
|
|
|
|
chan = line.params.pop(0)
|
|
|
|
words = line.params[0].split(" ")
|
2020-03-11 18:16:17 +00:00
|
|
|
nick = irctokens.Hostmask(line.source).nickname
|
2020-03-11 18:10:44 +00:00
|
|
|
|
2020-02-24 15:47:57 +00:00
|
|
|
if len(words) > 0 and nick != bot["nick"]:
|
2019-01-29 02:33:35 +00:00
|
|
|
if words[0] == "!!list":
|
|
|
|
res = ""
|
|
|
|
for k in DB:
|
2019-05-28 17:31:21 +00:00
|
|
|
res += k + " "
|
2019-05-28 16:16:58 +00:00
|
|
|
send(chan, res[:475])
|
2019-01-29 02:33:35 +00:00
|
|
|
elif words[0] == "!!fuse":
|
|
|
|
if "|" in words:
|
2019-05-28 17:31:21 +00:00
|
|
|
res = fuse(words[1 : words.index("|")])
|
2019-01-29 02:33:35 +00:00
|
|
|
if res:
|
2019-05-28 17:31:21 +00:00
|
|
|
send(chan, " ".join(words[words.index("|") + 1 :]) + " " + res)
|
2019-01-29 02:33:35 +00:00
|
|
|
else:
|
|
|
|
res = fuse(words[1:])
|
|
|
|
if res:
|
2019-05-28 17:31:21 +00:00
|
|
|
send(chan, res[0:475])
|
2019-05-28 17:40:51 +00:00
|
|
|
elif words[0] == "!!source":
|
|
|
|
send(chan, "https://tildegit.org/ben/tracer")
|
2019-05-28 17:47:59 +00:00
|
|
|
elif words[0] == "!botlist" or words[0] == "!!help":
|
2019-05-28 17:40:51 +00:00
|
|
|
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",
|
|
|
|
)
|
2019-01-29 02:33:35 +00:00
|
|
|
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)
|
|
|
|
|
2019-05-28 17:31:21 +00:00
|
|
|
|
2019-01-29 02:33:35 +00:00
|
|
|
if __name__ == "__main__":
|
2020-03-11 18:10:44 +00:00
|
|
|
d = irctokens.StatefulDecoder()
|
|
|
|
e = irctokens.StatefulEncoder()
|
|
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
s.connect((bot["server"], int(bot["port"])))
|
|
|
|
|
|
|
|
_send(irctokens.format("USER", [bot["nick"], "0", "*", "tracery bot"]))
|
|
|
|
_send(irctokens.format("NICK", [bot["nick"]]))
|
2019-05-28 16:16:58 +00:00
|
|
|
|
2020-03-11 18:10:44 +00:00
|
|
|
while True:
|
|
|
|
lines = d.push(s.recv(1024))
|
2019-05-28 17:31:21 +00:00
|
|
|
|
2020-03-11 18:10:44 +00:00
|
|
|
if lines == None:
|
|
|
|
print("! disconnected")
|
|
|
|
break
|
2019-05-28 17:31:21 +00:00
|
|
|
|
2020-03-11 18:10:44 +00:00
|
|
|
for line in lines:
|
|
|
|
print(f"< {line.format()}")
|
2019-05-28 18:09:43 +00:00
|
|
|
|
2020-03-11 18:10:44 +00:00
|
|
|
if line.command == "PING":
|
|
|
|
_send(irctokens.format("PONG", [line.params[0]]))
|
|
|
|
|
|
|
|
elif line.command == "001":
|
|
|
|
_send(irctokens.format("MODE", [bot["nick"], "+B"]))
|
2020-02-24 16:32:56 +00:00
|
|
|
if account is not None:
|
2020-03-11 18:10:44 +00:00
|
|
|
_send(
|
|
|
|
irctokens.format(
|
|
|
|
"SQUERY",
|
|
|
|
[
|
|
|
|
"NickServ",
|
|
|
|
"IDENTIFY",
|
|
|
|
account["username"],
|
|
|
|
account["password"],
|
|
|
|
],
|
|
|
|
)
|
2020-02-24 16:32:56 +00:00
|
|
|
)
|
2020-03-11 18:10:44 +00:00
|
|
|
_send(irctokens.format("JOIN", bot.getlist("channels")))
|
|
|
|
|
|
|
|
elif line.command == "INVITE":
|
|
|
|
_send(irctokens.format("JOIN", [line.params[0]]))
|
2019-05-28 17:31:21 +00:00
|
|
|
|
2020-03-11 18:10:44 +00:00
|
|
|
elif line.command == "PRIVMSG":
|
2019-05-28 17:31:21 +00:00
|
|
|
try:
|
2020-03-11 18:10:44 +00:00
|
|
|
think(line)
|
2019-05-28 17:31:21 +00:00
|
|
|
except Exception as e:
|
2020-03-11 18:10:44 +00:00
|
|
|
print("ERROR", line)
|
2019-05-28 17:31:21 +00:00
|
|
|
print(e)
|
2019-06-25 02:58:42 +00:00
|
|
|
traceback.print_exc()
|