minerbot/minerbot.py.save

381 lines
14 KiB
Plaintext

import socket,random,subprocess,threading,time,cPickle,string,time,prss,randwords,pstocks,chaninfo,primefac,re;
import os.path as fs;
from email.mime.text import MIMEText;
#with open("zws.txt","rb") as f:
# zws = f.readAll()
zws = ""
class NotRunningException (Exception):
pass;
log_format = "{} [{}] {}: {}"
def filterNick(nick):
if len(nick) == 1:
print "Either "+nick+" is not a nick, or the person who has that nick needs a longer nick."
return nick
s = nick[0]+zws+nick[1:]
return s.encode('utf-8')
def log(channel, nick, message):
with open("/home/minerobber/log.txt","ab") as fh:
fh.write(log_format.format(time.strftime("%Y-%m-%d %H:%M:%S"),channel,nick,message))
with open("/home/minerobber/logs/"+time.strftime("%Y-%m-%d")+".txt","ab") as fh:
fh.write(log_format.format(time.strftime("%Y-%m-%d %H:%M:%S"),channel,nick,message))
def logPublic(channel, nick, message):
with open("/home/minerobber/public_html/public_msgs.txt","ab") as fh:
fh.write(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())+" ["+channel+"] "+nick+": "+message)
def announce(channel, nick, ann, prssfeed):
prssfeed.addItem("Announcement by {} in {}".format(channel, nick),"https://tilde.town/~{}".format(nick),ann)
with open(fs.expanduser("~/public_html/announcements/rss.xml"),"wb") as rss:
rss.write(prssfeed.make())
with open(fs.expanduser("~/public_html/announcements/index.text"),"ab") as html:
html.write('{}, while in {}, announced: "{}" \n'.format(nick, channel, ann));
subprocess.check_output(["make -C ~/public_html/announcements -B"],shell=True)
cPickle.dump(prssfeed,open("/home/minerobber/misc/annrss","wb"))
def logJoin(channel,nick):
with open("/home/minerobber/log.txt","ab") as fh:
fh.write(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())+" "+nick+" joined "+channel)
def logPart(channel,nick):
with open("/home/minerobber/log.txt","ab") as fh:
fh.write(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())+" "+nick+" left "+channel)
class minerbot:
def __init__(self, name, user, owner):
self.name = name;
self.owner = owner;
self.user = user;
self.running = False;
self.reload = 0;
def begin(self, server, port, channels):
# declare variables here
self.irc = socket.socket();
self.randWordsList = randwords.corpus;
self.userList = [];
if fs.isfile("/home/minerobber/userList"):
self.load();
self.running = True;
self.channels = channels;
self.emailTemplate = ["~{0} wanted me to tell you:\n"]
self.rss = prss.PageRSS("Announcements","https://tilde.town/~minerobber/announcements","Announcements made by tilde.town members in IRC.",time.localtime())
if fs.isfile("/home/minerobber/misc/annrss"):
self.rss = cPickle.load(open("/home/minerobber/misc/annrss"))
# self.guessgameplaying = False;
# self.gg_players = {};
# self.gg_state = "not-active";
# self.gg_votes = {}
# connecting, as well as main loop
self.irc.connect((server, port));
self.irc.send("NICK " + self.name + "\r\n");
self.irc.send("USER " + self.user + " 8 * Making an IRC bot is fun!\r\n");
for chan in channels:
self.irc.send("JOIN " + chan + "\r\n");
while self.running:
data = self.irc.recv(4096);
#print data;
if data.find("PING") != -1:
self.irc.send("PONG " + data.split()[1] + "\r\n");
elif data.find("NAMES") != -1 and not fs.isfile("/home/minerobber/userList"):
users = data[5:-3]
for name in users.split(" "):
table = []
table.append(name)
table.append(0)
self.userList.append(table);
elif data.find("JOIN") != -1:
logJoin(data.split(" ")[2],data.split(" ")[0].split("!")[0][1:])
if data.split(" ")[2] == "#music" and data.split(" ")[0].split("!")[0][1:] != self.nick:
self.say(data.split(" ")[2],"Hello, "+data.split(" ")[0].split("!")[0][1:]+"! If you want to listen along, the URL is: https://tilde.town/~kc/jukebot/listen")
elif data.find("PART") != -1:
logPart(data.split(" ")[2],data.split(" ")[0].split("!")[0][1:])
elif data.find("PRIVMSG") != -1:
self.spokento(data)
self.save()
return self.reload;
def runCMD(self, cmd):
i = subprocess.check_output([cmd],shell=True)
if "\n" in i:
i.replace("\n","; ")
return i;
def sendEmail(self, channel, sender, recipient, text):
msg = MIMEText("~{0} wanted me to tell you:\n> {1}".format(sender,text))
msg["From"] = "minerbot-messages@tilde.town"
msg["To"] = "{0}@tilde.town".format(recipient)
msg["Subject"] = "Message from ~{0}".format(sender)
msg["Cc"] = "{0}@tilde.town".format(sender)
mail = subprocess.Popen("{0} -t -oi".format(which("sendmail")).split(" "),stdin=subprocess.PIPE)
mail.communicate(msg.as_string())
self.say(channel,"Mail sent!")
# mail.close()
def spokento(self, data):
if not self.running:
raise Exception("spokento was prematurely called.");
data_parts = data.split(" ",3);
id = data_parts[0];
nick = id.split("!")[0][1:];
message = data_parts[3][1:];
channel = data_parts[2];
print "[" + channel + "] " + nick + ": " + message;
log(channel, nick, message)
self.rss.pubDate = time.localtime()
if message.find(self.owner) != -1:
logPublic(channel,nick,message)
elif message.find("!log") == 0:
logPublic(channel,nick,message.split(" ",2)[1])
if message.find("!quit") == 0 and nick == self.owner:
self.irc.send("QUIT :beep boop I'm a bot.\r\n");
self.running = False;
elif message.find("!rollcall") == 0:
self.say(channel,"Hey! I'm " + self.name + "! Use '!help' to see a list of my commands.")
elif message.find("!twitch ") == 0:
mparts = message.split(" ")
if len(mparts) == 2:
c = chaninfo.ChannelInfo(mparts[1][:-2],"h7lvoe263k42haljbhlbv2ag1nzt5nd")
if not c.isOnline():
return
verb = "playing"
if c.getDisplay():
verb = "being"
self.say(channel, '{} is {} {}. Status: "{}"; Viewers: {!s}'.format(c.channel,verb,c.getGame(),c.getStatus(),c.getViewers()))
elif message.strip == "!last5said":
with open("/home/minerobber/log.txt") as f:
lines = []
for line in f:
lines.append(line.strip())
for line in lines[:-5]:
self.say(nick,line)
elif message.find("!dicegame") == 0:
message_parts = message.split(" ",2)
sides = 6
choice = int(random.uniform(1,sides))
b_choice = int(random.uniform(1,sides))
if b_choice > choice:
winMSG = "I win!"
else:
if b_choice == choice:
winMSG = "It's a tie!"
else:
winMSG = "You win!"
self.say(channel,"You rolled a " + str(choice) + ", and I rolled a " + str(b_choice) + ". " + winMSG)
elif channel == self.name and nick == self.owner:
print(self.owner + " used the global to say: \"" + message + "\"")
for chan in self.channels:
self.say(chan,"[GLOBAL] " + message)
elif message.find("!online") == 0:
results = self.runCMD("onlinepeople4irc")
leet = string.maketrans("aelosiuUc","43105|Uu(")
self.say(channel, results.translate(leet))
elif message.find("!reload") == 0 and self.owner == nick:
self.irc.send("QUIT :Reloading bot code...\r\n");
self.reload = 1;
self.running = False;
# elif message.find("!shop") == 0:
#nyi
elif message.find("!tbadmin") == 0 and self.owner == nick:
message_parts = message.split(" ")
if message_parts[1] == "add":
for i in self.userList:
if message_parts[2] == i[0]:
i[1] += int(message_parts[3])
self.save()
elif message_parts[1] == "rm":
for i in self.userList:
if message_parts[2] == i[0]:
i[1] += int(message_parts[3])
self.save()
elif message_parts[1] == "view":
for i in self.userList:
if message_parts[2] == i[0]:
self.say(channel,i[0] + " has " + str(i[1]) + " tildebucks.")
elif message.find("!announce ") == 0:
announce(channel, nick, " ".join(message.split(" ")[1:]), self.rss)
# elif message.find("!guessing_game") == 0 and self.gg_state == "not-active":
# thread = threading.Thread(target=self.playGuessingGame, args=(channel));
# elif message.find("!join_guessing_game") == 0 and self.gg_state == "player-wait":
# self.gg_players.append(nick);
elif message.find("!save") == 0 and nick == self.owner:
self.save()
elif message.find("!load") == 0 and nick == self.owner:
self.load()
#elif message.find("!money") == 0:
# for i in self.userList:
# if i[0] == nick:
# self.say(channel,(nick + " has " + str(i[1]) + " tildebucks."))
elif message.find("!update-qdb-commits") == 0 and self.owner == nick:
self.say(channel, self.runCMD("/home/minerobber/qdb-commits-gen.sh"))
elif message.find("!run ") == 0 and self.owner == nick:
prog = message.split(" ",1)[1]
nprog = which(prog.split(" ",1)[0])
if nprog is None:
self.say(channel,"Error: program does not exist!")
else:
self.say(channel,self.runCMD(prog.replace(prog.split(" ",1)[0],nprog)))
elif message.find("!tell") == 0:
parts = message.split(" ",2)
if not len(parts) == 3:
self.say(channel,"Usage: !tell <user> <message>")
else:
self.sendEmail(channel,nick,parts[1],parts[2][:-2])
# elif message.find("!get-gg-state") == 0 and self.owner == nick:
# self.say(channel, "GG-State: " + self.gg_state)
elif message.find("!getStock") == 0:
ticker = pstocks.StockTicker(format="{0} ({1}) is currently priced at {2}. (a change of {3})")
parts = message.split(" ")
if len(parts) < 2:
self.say(channel, "Usage: '!getStock <ticker>'")
return
for symbol in parts[1:]:
ticker.addSymbol(symbol)
for message in ticker.getTickerValues():
self.say(channel,message)
elif message.find("!mbtilde ") == 0:
if nick != self.owner:
self.say(channel,"Don't tell me what to do!")
return
if channel != "#bots":
self.say(channel,"Remember: tildebot only awards tildes in \#bots.")
parts = message.split(" ",2)
parts = [s.rstrip() for s in parts]
if parts[1] == "request":
self.say("#bots","!tilde")
if parts[1] == "add":
nums = [int(s) for s in parts[2].split(" ")]
self.say(channel,"{!s}".format(sum(nums)))
if parts[1] == "sub":
nums = [int(s) for s in parts[2].split(" ",1)]
self.say(channel,"{!s}".format(nums[1]-nums[0]))
if parts[1] == "mult":
nums = [int(s) for s in parts[2].split(" ",1)]
self.say(channel,"{!s}".format(nums[1]*nums[0]))
if parts[1] == "divide":
nums = [int(s) for s in parts[2].split(" ",1)]
try:
self.say(channel,"{!s}".format(nums[0]/nums[1]))
except ZeroDivisionError:
self.say(channel,"Bugger off!")
if parts[1] == "mod":
nums = [int(s) for s in parts[2].split(" ",1)]
self.say(channel,"{!s}".format(nums[0]%nums[1]))
if parts[1] == "factor":
self.say(channel,"{!s},{!s}".format(*list(primefac.primefac(int(parts[2]))))
elif message.find("!rpg") and channel=="#rpg":
parts = message.split(" ")
if len(parts) < 2:
self.say(channel,"Usage: !rpg <action> [parameters]")
if parts[1]=="roll" and len(parts)==3:
descriptor = parts[2].rstrip()
t = re.match(descriptor,r"^(\d+)d(\d+)$")
if not t:
self.say(channel,"Usage: !rpg roll <amount of dice>d<number of sides on each>")
self.say(channel,"Example: !rpg roll 1d100")
number = t.match(0)
sides =
# elif message.find("!helpme") == 0:
# help_parts = message.split(" ",2)
# if len(help_parts) < 2:
# self.say(channel,"Commands: 'dicegame', 'online', 'tell';")
# else:
# if help_parts[1] == "dicegame":
# self.say(channel,"Play a dice game against " + self.name + ". Usage: '!dicegame'")
# elif help_parts[1] == "online":
# self.say(channel,"Returns a list of online users, as well as a user count. Usage: '!online'")
# elif help_parts[1] == "tell":
# self.say(channel,"Sends a user an email to let them know of something. Usage: '!tell <user> <thing to tell them>'")
# elif help_parts[1] == "words":
# self.say(channel,"Generates a random string of words. Usage: '!words'")
# elif help_parts[1] == "getStock":
# self.say(channel,"Gets stock info for a specific ticker. Usage: '!getStock <ticker>'")
# elif self.gg_state == "player-wait-vote" and message.find("!guess"):
# if nick in self.gg_players:
# for i in self.gg_votes:
# if i[0] == nick:
# return;
# self.gg_votes.append({nick,int(message.split(" ")[1])})
# if self.gg_state == "player-wait-vote":
# playerDouble = {};
# for i in self.gg_votes:
# if i[0] in self.gg_players:
# playerDouble.append(i[0])
# if self.gg_players == playerDouble:
# self.gg_state = "all-voted"
# self.randWordsList.append(message)
def say(self, chan, message):
self.irc.send("PRIVMSG " + chan + " :" + message + "\r\n")
if chan.find("#") == 0:
log(chan, self.name, message)
def playGuessingGame(self,chan):
self.gg_players = []
self.say(chan, "Generating number to guess...")
gg_number = random.uniform(1,100)
self.gg_state = "player-wait"
self.say(chan, "Game will start soon! To join, type \"!join_guessing_game\"")
wait(15, True)
self.gg_state = "started"
self.say(chan, "The game has started!")
playerString = "Players: "
for player in self.gg_players:
playerString += player + " "
self.say(chan, playerString)
self.say(chan,"How to play: guess a number between 1 and 100.")
self.gg_state = "player-wait-vote"
while not self.gg_state == "all-voted":
wait(5,False)
correct_players = [];
for i in self.gg_votes:
if gg_number == i[1]:
correct_players.append(i[0])
correctVoteString = "Winners: "
for player in correct_players:
correctVoteString += player + " "
self.say(chan, correctVoteString)
self.say(chan, "All of the winners get 3 tildebucks!")
for user in self.userList:
if user[0] in correct_players:
user[1] += 3;
self.save()
self.gg_state = "not-active"
def save(self):
cPickle.dump(self.userList, open("/home/minerobber/userList","wb"))
def load(self):
cPickle.load(open("/home/minerobber/userList","rb"))
def num(s):
try:
int(s)
except ValueError:
float(s)
def wait(s, minutes):
if minutes:
time.sleep(s * 60)
else:
time.sleep(s)
def which(s):
import os
def is_exe(fpath):
return fs.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = fs.split(s)
if fpath:
if is_exe(program):
return program
else:
for path in os.environ["PATH"].split(os.pathsep):
path = path.strip('"')
exe_file = os.path.join(path, s)
if is_exe(exe_file):
return exe_file
return None;