516 lines
15 KiB
Python
Executable File
516 lines
15 KiB
Python
Executable File
#!/usr/bin/python3 -u
|
|
|
|
import socket
|
|
import ssl
|
|
import sys
|
|
import os
|
|
from time import sleep
|
|
import launch
|
|
import threading
|
|
import re
|
|
import json
|
|
import requests
|
|
from datetime import datetime, timedelta
|
|
import konfuzius
|
|
import fml
|
|
import string
|
|
import random
|
|
from nslookup import nslookup
|
|
import rss
|
|
|
|
version = "v0.9"
|
|
|
|
# IRC settings
|
|
host = ""
|
|
port =
|
|
nick = "huan"
|
|
password = ""
|
|
chan = ""
|
|
fefe_chans = [""]
|
|
|
|
# fml endpoint
|
|
fml_url = "http://www.fmylife.com/random"
|
|
|
|
# Chat colors
|
|
b = "\x0312"
|
|
c = "\x0311"
|
|
y = "\x038"
|
|
r = "\x034"
|
|
g = "\x033"
|
|
|
|
# global variable for the socket, see connect()
|
|
irc = None
|
|
|
|
# Currency API
|
|
def get_exchange():
|
|
url = "https://www.bitstamp.net/api/v2/ticker/eurusd"
|
|
try:
|
|
r = requests.get(url)
|
|
data = json.loads(r.text)
|
|
return float(data["last"])
|
|
except:
|
|
pass
|
|
|
|
|
|
def calc_currency(curr, value):
|
|
eurusd = get_exchange()
|
|
if curr == "eur":
|
|
rate = value * eurusd
|
|
return rate
|
|
elif curr == "usd":
|
|
rate = value / eurusd
|
|
return rate
|
|
else:
|
|
raise Exception("wrong input")
|
|
|
|
|
|
def safeexit():
|
|
sys.exit(0)
|
|
|
|
|
|
def connect(host, port):
|
|
global irc
|
|
print("Connecting to "+host+":"+str(port))
|
|
context = ssl.create_default_context()
|
|
with socket.create_connection((host, port), timeout=180) as sock:
|
|
irc = context.wrap_socket(sock, server_hostname=host)
|
|
|
|
|
|
def sendRaw(data):
|
|
irc.send(bytes(data, "UTF-8"))
|
|
|
|
|
|
def register(nick, host):
|
|
print("Registering User...")
|
|
sendRaw("USER "+nick+" "+host+" "+nick+" "+nick+"\n")
|
|
|
|
|
|
def name(nick):
|
|
print("Setting Nickname to "+nick)
|
|
sendRaw("NICK "+nick+"\n")
|
|
|
|
|
|
def auth(nick, password):
|
|
print("Authenticating...")
|
|
sendRaw("PRIVMSG NickServ :IDENTIFY "+nick+" "+password+"\n")
|
|
|
|
|
|
def join(chan):
|
|
print("Joining channel "+chan)
|
|
try:
|
|
sendRaw("JOIN "+chan+"\n")
|
|
except Exception as err:
|
|
print("Failed! "+str(err))
|
|
|
|
|
|
def mode(nick):
|
|
print("Setting modes +B-x")
|
|
sendRaw("MODE "+nick+" +B-x\n")
|
|
|
|
|
|
def part(chan):
|
|
print("Leaving channel "+chan)
|
|
try:
|
|
sendRaw("PART "+chan+"\n")
|
|
except Exception as err:
|
|
print(err)
|
|
|
|
|
|
def say(chan, msg):
|
|
try:
|
|
sendRaw("PRIVMSG "+chan+" :"+msg+"\n")
|
|
print("OK")
|
|
except Exception as err:
|
|
print("Error: "+str(err))
|
|
|
|
|
|
def raw(msg):
|
|
try:
|
|
sendRaw(msg+"\n")
|
|
print("OK")
|
|
except Exception as err:
|
|
print("Error"+str(err))
|
|
|
|
|
|
def me(chan, msg):
|
|
try:
|
|
sendRaw("PRIVMSG "+chan+" :\u0001ACTION "+msg+"\u0001\n")
|
|
except Exception as err:
|
|
print("Error: "+str(err))
|
|
|
|
|
|
def getData():
|
|
try:
|
|
raw = irc.recv(4096)
|
|
except TimeoutError:
|
|
print("Connection timed out!")
|
|
sys.exit(0)
|
|
if not raw:
|
|
print("Connection lost!")
|
|
sys.exit(0)
|
|
try:
|
|
data = raw.decode("UTF-8")
|
|
except:
|
|
try:
|
|
data = raw.decode("latin-1")
|
|
except:
|
|
data = "Broken encoding"
|
|
return data
|
|
|
|
|
|
def getMessage():
|
|
data = getData()
|
|
rawMsg = data.strip("\r\n")
|
|
return rawMsg
|
|
|
|
|
|
def getRocket():
|
|
rocket, mission, delta = launch.next_launch()
|
|
rstring = "%sNext rocket: %s%s %s| %s%s %s| %s%s" % (b, y, rocket, b, y, mission, b, y, delta)
|
|
return rstring
|
|
|
|
|
|
def yon():
|
|
from random import choice
|
|
answer = choice(['y', 'n'])
|
|
return answer
|
|
|
|
|
|
def is_registered(username):
|
|
try:
|
|
sendRaw("WHOIS "+str(username)+"\n")
|
|
user_info = getMessage()
|
|
regex = rf"330 {str(re.escape(nick))} {str(re.escape(username))} \S+ :is logged in as"
|
|
matches = re.finditer(regex, user_info, re.MULTILINE)
|
|
for match in matches:
|
|
acc_name = match.group(0).split()[3]
|
|
return acc_name
|
|
except Exception as err:
|
|
print("Error getting user account! - "+str(err))
|
|
return None
|
|
|
|
|
|
def hour_min(td):
|
|
return td.seconds//3600, (td.seconds//60)%60
|
|
|
|
|
|
def give_rep(user, orig_user, giver, reason, channel):
|
|
print("Give rep action: target-user "+str(user)+" - username "+str(orig_user)+" - giver "+str(giver)+" - reason "+str(reason))
|
|
data = json.load(open("rep.json"))
|
|
date = datetime.now()
|
|
stamp = datetime.strftime(date, "%Y-%m-%d %H:%M:%S")
|
|
delay = timedelta(hours=4)
|
|
if giver in data["users"]:
|
|
last_give = datetime.strptime(data["users"][giver]["last_given"], "%Y-%m-%d %H:%M:%S")
|
|
delta = date - last_give
|
|
again = delay - delta
|
|
ah, am = hour_min(again)
|
|
if delta <= delay:
|
|
if ah != 0:
|
|
say(channel, "You can give rep again in "+str(ah)+" hours and "+str(am)+" minutes.")
|
|
return
|
|
else:
|
|
say(channel, "You can give rep again in "+str(am)+" minutes.")
|
|
return
|
|
else:
|
|
data["users"][giver]["last_given"] = stamp
|
|
else:
|
|
data["users"][giver] = {"rep": 0, "last_given": stamp, "reason": "None"}
|
|
if user in data["users"]:
|
|
data["users"][user]["rep"] += 1
|
|
data["users"][user]["reason"] = str(reason)
|
|
else:
|
|
data["users"][user] = {"rep": 1, "last_given": "1990-01-01 00:00:00", "reason": str(reason)}
|
|
say(channel, "Reputation of "+orig_user+": "+str(data["users"][user]["rep"]))
|
|
data["last_update"] = stamp
|
|
json.dump(data, open("rep.json", "w"))
|
|
|
|
|
|
def get_rep(user):
|
|
data = json.load(open("rep.json"))
|
|
if user in data["users"]:
|
|
rep = data["users"][user]["rep"]
|
|
reason = data["users"][user]["reason"]
|
|
else:
|
|
rep = 0
|
|
reason = "None"
|
|
return [str(rep), str(reason)]
|
|
|
|
|
|
def notice(user, msg):
|
|
sendRaw("NOTICE "+user+" :"+msg+"\n")
|
|
print("sent notice to "+user+" with message: "+msg)
|
|
|
|
|
|
def ping(msg):
|
|
sendRaw("PONG :"+msg+"\n")
|
|
|
|
|
|
def start(host, port, nick, password, chans):
|
|
connect(host, port)
|
|
sleep(2)
|
|
register(nick, host)
|
|
sleep(2)
|
|
name(nick)
|
|
sleep(6)
|
|
auth(nick, password)
|
|
sleep(2)
|
|
mode(nick)
|
|
sleep(2)
|
|
for chan in chans:
|
|
join(chan)
|
|
sleep(2)
|
|
|
|
|
|
def command_loop():
|
|
while True:
|
|
try:
|
|
data = getData()
|
|
ircmsg = data.strip("\n\r")
|
|
if ircmsg.find("PING :") != -1:
|
|
pingstring = ircmsg.strip("PING :")
|
|
ping(pingstring)
|
|
if ircmsg.find("ERROR :Closing link") != -1:
|
|
print("Error. Lost Connection. Giving up!")
|
|
os._exit(1)
|
|
break
|
|
if ircmsg.find(" PRIVMSG ") != -1:
|
|
ircnick = ircmsg.split("!")[0][1:]
|
|
channel = ircmsg.split(" PRIVMSG ", 1)[-1].split(" :", 1)[0]
|
|
msg = ircmsg.split(channel+" :", 1)[1]
|
|
|
|
if channel == nick:
|
|
print("direct message received")
|
|
if msg == "\x01VERSION\x01":
|
|
print("got ctcp version request")
|
|
notice(ircnick, "\x01VERSION HuanBot (fork of BertBot) "+version+"\x01")
|
|
elif msg.startswith("\x01PING"):
|
|
print("got ctcp ping request")
|
|
pingstring = msg.split()[1]
|
|
notice(ircnick, "\x01PING "+pingstring+"\x01")
|
|
continue
|
|
|
|
if msg == ".hello":
|
|
say(channel, "Hello "+ircnick)
|
|
|
|
elif msg == ".help":
|
|
print("sending help")
|
|
say(channel, "available commands: .nextrocket, .slap, .mate, .hello, .jn, .rep, .konfuzius, .fml, .eurusd, .usdeur, .nslookup")
|
|
|
|
elif msg == ".nextrocket":
|
|
try:
|
|
print("found Rocket command\nRequesting next rocketlaunch...")
|
|
response = getRocket()
|
|
say(channel, response)
|
|
except:
|
|
print("Error getting next rocketlaunch")
|
|
say(channel, "Error contacting LaunchLibrary API")
|
|
|
|
elif msg.startswith(".slap"):
|
|
try:
|
|
slapname = msg.split()[1]
|
|
print("slapping "+slapname)
|
|
say(channel, ircnick+" slaps "+slapname+" around a bit with a large trout")
|
|
except Exception as err:
|
|
print(err)
|
|
|
|
elif msg.startswith(".mate"):
|
|
try:
|
|
try:
|
|
user = msg.split()[1]
|
|
print("schenke mate an "+user+" aus")
|
|
me(channel, "reicht "+user+" eine eiskalte Mate. Prost du scheiss Hipster.")
|
|
except:
|
|
print("schenke mate an "+ircnick+" aus")
|
|
me(channel, "reicht "+ircnick+" eine eiskalte Mate. Prost du scheiss Hipster.")
|
|
except Exception as err:
|
|
print(err)
|
|
|
|
elif msg.startswith(".eurusd"):
|
|
try:
|
|
value = float(msg.split()[1])
|
|
rate = calc_currency("eur", value)
|
|
say(channel, "USD: {0:.2f}".format(rate))
|
|
except Exception as err:
|
|
say(channel, "could not get data")
|
|
print(err)
|
|
|
|
elif msg.startswith(".usdeur"):
|
|
try:
|
|
value = float(msg.split()[1])
|
|
rate = calc_currency("usd", value)
|
|
say(channel, "EUR: {0:.2f}".format(rate))
|
|
except Exception as err:
|
|
say(channel, "could not get data")
|
|
print(err)
|
|
|
|
elif msg.startswith(".jn"):
|
|
choose = yon()
|
|
try:
|
|
print("choose "+choose+" for "+ircnick)
|
|
if choose == "y":
|
|
say(channel, ircnick+": "+g+"Ja")
|
|
else:
|
|
say(channel, ircnick+": "+r+"Nein")
|
|
except Exception as err:
|
|
print(err)
|
|
|
|
elif msg.startswith(".rep"):
|
|
try:
|
|
user = msg.split(" ", 2)[1]
|
|
print("got rep message from "+str(ircnick)+" for "+str(user))
|
|
try:
|
|
reason = msg.split(" ", 2)[2]
|
|
print("with reason "+str(reason))
|
|
except:
|
|
reason = "None"
|
|
print("with no reason")
|
|
if user == ircnick:
|
|
say(channel, "You can't give rep to yourself. Selfish little prick!")
|
|
continue
|
|
try:
|
|
acc_name = is_registered(user)
|
|
give_acc = is_registered(ircnick)
|
|
print("found account name for "+str(user)+": "+str(acc_name))
|
|
if acc_name != None and give_acc != None:
|
|
give_rep(acc_name, user, give_acc, reason, channel)
|
|
elif give_acc == None:
|
|
say(channel, "You are not registered!")
|
|
continue
|
|
else:
|
|
say(channel, "invalid or not registered user")
|
|
continue
|
|
except Exception as err:
|
|
print("Error in giving rep! - "+str(err))
|
|
except Exception as err:
|
|
print("No rep user found! - "+str(err))
|
|
try:
|
|
acc_name = is_registered(ircnick)
|
|
if acc_name != None:
|
|
rep_result = get_rep(acc_name)
|
|
rep = rep_result[0]
|
|
reason = rep_result[1]
|
|
say(channel, "Your reputation: "+str(rep)+" - Last reason: "+str(reason))
|
|
else:
|
|
say(channel, "You are not registered")
|
|
continue
|
|
except Exception as err:
|
|
print("Error getting rep! - "+str(err))
|
|
|
|
elif msg.startswith(".konfuzius"):
|
|
try:
|
|
quote = konfuzius.random_quote()
|
|
say(channel, b+"Konfuzius sagt: "+c+quote)
|
|
except:
|
|
say(channel, "Error :(")
|
|
|
|
elif msg == ".quit":
|
|
if ircnick == "jkhsjdhjs":
|
|
say(channel, "Flying to mars...")
|
|
print("got quit command. exiting...")
|
|
part(channel)
|
|
safeexit()
|
|
else:
|
|
say(channel, "You are not my master!")
|
|
|
|
elif msg.startswith(".say"):
|
|
if ircnick == "jkhsjdhjs":
|
|
try:
|
|
sayit = msg.split(" ", 1)[1]
|
|
say(channel, str(sayit))
|
|
except:
|
|
say(channel, "What should I say?")
|
|
continue
|
|
else:
|
|
say(channel, "You are not my master!")
|
|
|
|
elif msg.startswith(".debug"):
|
|
if ircnick == "jkhsjdhjs":
|
|
try:
|
|
debugmsg = msg.split(" ", 1)[1]
|
|
raw(debugmsg)
|
|
except:
|
|
say(channel, "What should I say?")
|
|
continue
|
|
else:
|
|
say(channel, "You are not my master!")
|
|
|
|
elif msg == ".fml":
|
|
try:
|
|
fml_string = fml.get_fml(fml_url)
|
|
print("got fml command")
|
|
say(channel, c+fml_string+b+" FML.")
|
|
except Exception as err:
|
|
print("Error getting URL title "+str(err))
|
|
elif msg.startswith(".nslookup"):
|
|
try:
|
|
msg_parts = msg.split(" ")
|
|
try:
|
|
nsdomain = msg_parts[1]
|
|
except:
|
|
say(channel, r+"You must specify a domain!")
|
|
continue
|
|
nstype = msg_parts[2:]
|
|
if not nstype:
|
|
nstype = ["AAAA", "A"]
|
|
print("got nslookup command with domain: "+str(nsdomain)+" and type: "+str(nstype))
|
|
nsresult = nslookup(nsdomain, nstype)
|
|
nslines = set(nsresult.split("\n"))
|
|
for nsline in nslines:
|
|
say(channel, y+" "+str(nsline))
|
|
except Exception as err:
|
|
print("Error in nslookup - "+str(err))
|
|
#elif "i won't" in msg:
|
|
# try:
|
|
# say(channel, "blp")
|
|
# except Exception as err:
|
|
# print("could not blp - "+str(err))
|
|
|
|
except Exception as err:
|
|
print(err)
|
|
|
|
|
|
def fefe_check():
|
|
while True:
|
|
try:
|
|
fefe_result = rss.check()
|
|
if not fefe_result == None:
|
|
for chan in fefe_chans:
|
|
say(chan, b+"Fefe sagt: "+c+str(fefe_result))
|
|
except Exception as err:
|
|
print("Error in fefe module! - "+str(err))
|
|
sleep(300)
|
|
|
|
|
|
class command_thread(threading.Thread):
|
|
def __init__(self, threadID):
|
|
threading.Thread.__init__(self)
|
|
self.threadID = threadID
|
|
def run(self):
|
|
print("Starting Command Thread...")
|
|
command_loop()
|
|
|
|
class fefe_thread(threading.Thread):
|
|
def __init__(self, threadID):
|
|
threading.Thread.__init__(self)
|
|
self.threadID = threadID
|
|
def run(self):
|
|
print("Starting fefe thread...")
|
|
fefe_check()
|
|
|
|
def main():
|
|
try:
|
|
start(host, port, nick, password, set(join_chans + fefe_chans))
|
|
except Exception as err:
|
|
print("FAIL: "+str(err))
|
|
sys.exit(1)
|
|
thread_command = command_thread(1)
|
|
#thread_fefe = fefe_thread(2)
|
|
thread_command.start()
|
|
#sleep(2)
|
|
#thread_fefe.start()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|