diff --git a/chatterbotapi.py b/chatterbotapi.py index 0808a8c..754f099 100644 --- a/chatterbotapi.py +++ b/chatterbotapi.py @@ -1,7 +1,19 @@ +import re +import sys import hashlib -import urllib -import urllib2 -from cookielib import CookieJar + +if sys.version_info >= (3, 0): + from urllib.request import build_opener, HTTPCookieProcessor, urlopen + from urllib.parse import urlencode + import http.cookiejar as cookielib + +else: + from urllib import urlencode, urlopen + from urllib2 import build_opener, HTTPCookieProcessor + import cookielib + +from collections import OrderedDict + import uuid import xml.dom.minidom @@ -37,7 +49,7 @@ class ChatterBotFactory: def create(self, type, arg = None): if type == ChatterBotType.CLEVERBOT: - return _Cleverbot('http://www.cleverbot.com', 'http://www.cleverbot.com/webservicemin', 35) + return _Cleverbot('http://www.cleverbot.com', 'http://www.cleverbot.com/webservicemin?uc=165', 35) elif type == ChatterBotType.JABBERWACKY: return _Cleverbot('http://jabberwacky.com', 'http://jabberwacky.com/webservicemin', 29) elif type == ChatterBotType.PANDORABOTS: @@ -83,35 +95,27 @@ class _CleverbotSession(ChatterBotSession): def __init__(self, bot): self.bot = bot - self.vars = {} - self.vars['start'] = 'y' - self.vars['icognoid'] = 'wsf' - self.vars['fno'] = '0' - self.vars['sub'] = 'Say' + self.vars = OrderedDict() + #self.vars['start'] = 'y' + self.vars['stimulus'] = '' self.vars['islearning'] = '1' - self.vars['cleanslate'] = 'false' - self.cookieJar = CookieJar() - try: - self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar)) - self.opener.open(self.bot.baseUrl) - except: - print "Error with cleverbot." - pass + self.vars['icognoid'] = 'wsf' + #self.vars['fno'] = '0' + #self.vars['sub'] = 'Say' + #self.vars['cleanslate'] = 'false' + self.cookieJar = cookielib.CookieJar() + self.opener = build_opener(HTTPCookieProcessor(self.cookieJar)) + self.opener.open(self.bot.baseUrl) def think_thought(self, thought): self.vars['stimulus'] = thought.text - data = urllib.urlencode(self.vars) + data = urlencode(self.vars) data_to_digest = data[9:self.bot.endIndex] - data_digest = hashlib.md5(data_to_digest).hexdigest() + data_digest = hashlib.md5(data_to_digest.encode('utf-8')).hexdigest() data = data + '&icognocheck=' + data_digest - #-- bgm's cookie mod - #yummy = CookieJar() - #cookieSesh = urllib2.build_opener(urllib2.HTTPCookieProcessor(yummy)) - #cookieSesh.open('http://www.cleverbot.com') - #- end mod - url_response = self.opener.open(self.bot.serviceUrl, data) - response = url_response.read() - response_values = response.split('\r') + url_response = self.opener.open(self.bot.serviceUrl, data.encode('utf-8')) + response = str(url_response.read()) + response_values = re.split(r'\\r|\r', response) #self.vars['??'] = _utils_string_at_index(response_values, 0) self.vars['sessionid'] = _utils_string_at_index(response_values, 1) self.vars['logurl'] = _utils_string_at_index(response_values, 2) @@ -124,20 +128,20 @@ def think_thought(self, thought): self.vars['vText2'] = _utils_string_at_index(response_values, 9) self.vars['prevref'] = _utils_string_at_index(response_values, 10) #self.vars['??'] = _utils_string_at_index(response_values, 11) - self.vars['emotionalhistory'] = _utils_string_at_index(response_values, 12) - self.vars['ttsLocMP3'] = _utils_string_at_index(response_values, 13) - self.vars['ttsLocTXT'] = _utils_string_at_index(response_values, 14) - self.vars['ttsLocTXT3'] = _utils_string_at_index(response_values, 15) - self.vars['ttsText'] = _utils_string_at_index(response_values, 16) - self.vars['lineRef'] = _utils_string_at_index(response_values, 17) - self.vars['lineURL'] = _utils_string_at_index(response_values, 18) - self.vars['linePOST'] = _utils_string_at_index(response_values, 19) - self.vars['lineChoices'] = _utils_string_at_index(response_values, 20) - self.vars['lineChoicesAbbrev'] = _utils_string_at_index(response_values, 21) - self.vars['typingData'] = _utils_string_at_index(response_values, 22) - self.vars['divert'] = _utils_string_at_index(response_values, 23) +# self.vars['emotionalhistory'] = _utils_string_at_index(response_values, 12) +# self.vars['ttsLocMP3'] = _utils_string_at_index(response_values, 13) +# self.vars['ttsLocTXT'] = _utils_string_at_index(response_values, 14) +# self.vars['ttsLocTXT3'] = _utils_string_at_index(response_values, 15) +# self.vars['ttsText'] = _utils_string_at_index(response_values, 16) +# self.vars['lineRef'] = _utils_string_at_index(response_values, 17) +# self.vars['lineURL'] = _utils_string_at_index(response_values, 18) +# self.vars['linePOST'] = _utils_string_at_index(response_values, 19) +# self.vars['lineChoices'] = _utils_string_at_index(response_values, 20) +# self.vars['lineChoicesAbbrev'] = _utils_string_at_index(response_values, 21) +# self.vars['typingData'] = _utils_string_at_index(response_values, 22) +# self.vars['divert'] = _utils_string_at_index(response_values, 23) response_thought = ChatterBotThought() - response_thought.text = _utils_string_at_index(response_values, 16) + response_thought.text = _utils_string_at_index(response_values, 0) return response_thought ################################################# @@ -161,8 +165,8 @@ def __init__(self, bot): def think_thought(self, thought): self.vars['input'] = thought.text - data = urllib.urlencode(self.vars) - url_response = urllib2.urlopen('http://www.pandorabots.com/pandora/talk-xml', data) + data = urlencode(self.vars) + url_response = urlopen('http://www.pandorabots.com/pandora/talk-xml', data) response = url_response.read() response_dom = xml.dom.minidom.parseString(response) response_thought = ChatterBotThought() diff --git a/googlebot.py b/googlebot.py new file mode 100644 index 0000000..42a6d67 --- /dev/null +++ b/googlebot.py @@ -0,0 +1,84 @@ +#!usr/bin/env python + +import google +import urllib2 +import random +from operator import itemgetter +from goose import Goose + +def retFirstResult(search): + result = {} + res = google.search(search,stop=0) + for i in res: + o = urllib2.build_opener(urllib2.HTTPCookieProcessor()) + try: + r = o.open(i) + except: + return "~*403" + html = r.read() + g = Goose() + a = g.extract(raw_html=html) + result["title"] = a.title + result["url"] = i + result["blob"] = getBlob(search,a.cleaned_text) + return result + +def retRandomResult(search): + result = {} + res = google.search(search) + for c,i in enumerate(res): + if c > 15: break + if c % 6 == random.randint(0,5): + g = Goose() + a = g.extract(raw_html=google.get_page(i)) + result["resNum"] = c + result["title"] = a.title + result["url"] = i + result["blob"] = getBlob(search,a.cleaned_text) + else: + continue + if len(result) == 0: + for i in res: + g = Goose() + a = g.extract(raw_html=google.get_page(i)) + result["title"] = a.title + result["url"] = i + result["blob"] = getBlob(search,a.cleaned_text) + return result + return result + +def retResults(search): + result = {} + res = google.search(search,stop=2) + for i,v in enumerate(res): + if len(result) > 2: break + result[i] = {} + o = urllib2.build_opener(urllib2.HTTPCookieProcessor()) + try: + r = o.open(v) + except: + continue + html = r.read() + g = Goose() + a = g.extract(raw_html=html) + result[i]["title"] = a.title + result[i]["url"] = v + return result + + +def getBlob(search, text): + matches = {} + text = text.replace("\n"," ") + text = text.split(" ") + try: + while text.index("") >= 0: + text.remove(text[text.index("")]) + except ValueError: + for i,v in enumerate(search.split()): + matches[i] = [a for a, b in enumerate(text) if (str(b).strip().lower() == str(v).strip().lower() or (a+1 < len(text) and "".join(itemgetter(a,a+1)(text)).strip().lower() == str(v).strip().lower()))] + blob = "" + for words in matches: + for index in matches[words]: + blob += "..." + " ".join(text[index-4:index+15]) + "... | " + blob = blob[:len(blob) - 3] + return blob diff --git a/gr3ybot.py b/gr3ybot.py index 775b2f8..f16b5f7 100644 --- a/gr3ybot.py +++ b/gr3ybot.py @@ -35,39 +35,30 @@ from gr3ybot_settings import * from gr3ysql import Gr3ySQL from chatterbotapi import ChatterBotFactory, ChatterBotType -import struct +from fightbot import * from difflib import SequenceMatcher -from bottube import * -import socket -import select -import string -from urbandict import * -import sys -from twitbot import * -from slackbot import * -from yelpbot import * -from weatherbot import * -from summarize import * from confessions import * from os import path -import random -import signal -import parsedatetime as pdt +from decimal import * from time import sleep, strftime, localtime -import threading -import urllib -import urllib2 -import urlparse -import json from pytz import timezone -import pytz -from wiki import wiki -import datetime -import feedparser -import re +import socket, struct, select, string +import sys, random, math, signal +import threading, urllib, urllib2, urlparse +import json, pytz, datetime, feedparser, re +import parsedatetime as pdt +if YOUTUBE_LINKS: from bottube import * +if URBANDICT_ENABLED: from urbandict import * +if GOOGLE_ENABLED: from googlebot import * +if TWITTER_ENABLED: from twitbot import * +if TWITCH_NOTIFICATIONS_ENABLED: from twitchbot import getIsTwitchStreaming +if SLACK_ENABLED: from slackbot import * +if YELP_ENABLED: from yelpbot import * +if WEATHER_ENABLED: from weatherbot import * +if NEWS_LINKS: from summarize import * +if WIKIPEDIA_ENABLED: from wiki import wiki if QR_ENABLED: import qrtools -from fightbot import * -from wolfbot import * +if WOLFRAM_ENABLED: from wolfbot import * #-- Version, and AI initialization, and variables random.seed() @@ -101,14 +92,16 @@ #-- Set botname match string and connect to IRC matchbot = botname.lower() -def connect(): +def setSocket(): global irc - irc = socket.socket ( socket.AF_INET, socket.SOCK_STREAM ) + (fam, socktype, protocol, j, address) = socket.getaddrinfo(server, port)[0] + irc = socket.socket (fam, socktype, protocol) + irc.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) + irc.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 1) + irc.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1) + irc.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 5) print "Connecting to {0}:{1}".format(server,port) irc.connect((server,port)) - #irc.setblocking(False) - #irc.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0)) - if len(channelpw) > 1: irc.send ( 'PASS {0} \r\n'.format(channelpw) ) print "Setting nickname to {0}...".format(botname) @@ -212,6 +205,11 @@ def getHost(host): host = host.split(' ')[0] return host +def utc2loc(utctime): + utct = datetime.datetime.strptime(utctime,'%Y-%m-%dT%H:%M:%S') + localDt = utct.replace(tzinfo=pytz.utc).astimezone(timezone(LOCALTZ)) + return timezone(LOCALTZ).normalize(localDt) + def getChannel(data): try: chan = data.split('#')[1] @@ -241,7 +239,7 @@ def getChatters(rawdata="",chan=channel): names = data.split('353')[1] names = names.split(':')[1] names = names.split(' ') - names = [i.strip('@').strip('\r\n') for i in names] + names = [i.replace('@', "").replace("~","").strip('\r\n') for i in names] try: names.remove(botname) except ValueError: names = names @@ -249,6 +247,8 @@ def getChatters(rawdata="",chan=channel): log("People in the channel:") for i in names: log(i) + if names == False or names is None: + return "lonely" if len(names) == 1: return "lonely" return names @@ -307,12 +307,12 @@ def bufferData(data): def getMessage(data): try: - msg = data.split('#')[1] + msg = data.split('#',1)[1] except IndexError: msg = None if msg is not None: - msg = msg.split(':')[1:] + msg = msg.split(':',1)[1:] msg = " ".join(msg) return msg @@ -331,7 +331,10 @@ def join(chan): def quit(chan): irc.send('PART ' + chan + '\r\n') -def send(msg,chan=channel,tell=False): +def send(msg,chan=channel,tell=False,s=0,u=None): + if s == 1: + privsend(msg,u) + return msg = cleanText(msg,tell) if msg != False: irc.send('PRIVMSG ' + chan + ' :{0}\r\n'.format(msg)) @@ -468,21 +471,24 @@ def checkReminders(chan=channel): #-- Main Function def main(joined): - connect() - ircConnect = [irc,sys.stdin] + setSocket() + ident() con.db.create_function("regexp", 2, regexp) disconnected = 0 + isStreaming = 0 joined = False threshold = 15 * 60 lastPing = time.time() readBuffer = "" + dataRetries = 3 while True: + time.sleep(0.05) try: if len(f) > 0: f.pop() # Flush data except: pass special = 0 action = 'none' - dataReady = select.select(ircConnect, [], []) + dataReady = select.select([irc], [], [], 10) for s in dataReady[0]: if s == sys.stdin: k = sys.stdin.readline() @@ -497,6 +503,7 @@ def main(joined): tellinghistory = 0 time.sleep(1) irc.send('PONG ' + raw.split()[1] + '\r\n') + dataRetries = 3 if LOGLEVEL >= 1: log("Sent a ping response.") pingActions(getChannel(raw)) except Exception as e: @@ -510,7 +517,12 @@ def main(joined): print str(e) continue connected = "Thu" - if (time.time() - lastPing) > threshold and len(raw) == 0: + #if (time.time() - lastPing) > threshold and len(raw) == 0: + if len(raw) == 0 and dataRetries > 0: + time.sleep(5) + if LOGLEVEL >= 1: log("Lost connection. Awaiting reply from server...") + dataRetries = dataRetries - 1 + if len(raw) == 0 and dataRetries <= 0: if LOGLEVEL >= 1: log("\n============================================\nFATAL ERROR:\n============================================") log("The bot has been disconnected from the server. Reconnecting...") @@ -522,7 +534,9 @@ def main(joined): log("Could not send ping to bgm for reason: {}".format(str(e))) disconnected=True irc.close() - connect() + setSocket() + ident() + #sys.exit() for data in f: if LOGLEVEL == 3: @@ -612,6 +626,21 @@ def main(joined): ###===================================### #-- + # IDENT COMMAND + if info[0].lower() == 'ident' and special == 0: + nick = getNick(data) + host = getHost(data) + status = admins(nick, host) + if status == 1: + ident() + continue + elif status == 2: + send("i mean, you look like an admin but can you identify like an admin",getChannel(data)) + continue + else: + send("you dont know what youre talking about",getChannel(data)) + continue + # OPER COMMAND if info[0].lower() == 'op' and special == 0: nick = getNick(data) @@ -645,7 +674,7 @@ def main(joined): if "".join(info[1]).rstrip().lower() == botname.lower(): send("nah",getChannel(data)) continue - reason = "".join(info[2:]).rstrip() + reason = " ".join(info[2:]).rstrip() if not reason or reason is None: reason = "sorry i hit the wrong key and now youve been kicked" if status == 1: @@ -833,6 +862,39 @@ def main(joined): if special == 0: send("Gr3yBOT by bgm: version {0}. You know you wanna fork me: https://github.com/ninjanerdbgm/Gr3yBOT".format(version),getChannel(data)) else: name = getNick(data); privsend("Gr3yBOT by bgm: version {0}. You know you wanna fork me: https://github.com/ninjanerdbgm/Gr3yBOT".format(version),name) if LOGLEVEL >= 1: log("Version: {0}".format(version)) + + # BIRTHDAY PROBLEM + if info[0].lower() == 'room': + try: + roomSize = info[1] + roomSize = math.ceil(float(roomSize)) + except: + send("yo u gotta tell me how many people are in the room tho. \"%room 10\" for example",getChannel(data)) + continue + if roomSize <= 0: + send("hah look at this friendless loser",getChannel(data)) + continue + + if roomSize > 365: + send("there is a 100% chance that two people share a birthday. go make friends",getChannel(data)) + continue + + if roomSize > 80: + send("theres a 99.99% chance that two people share a birthday. go make friends",getChannel(data)) + continue + try: + a = Decimal(math.factorial(366)) + b = Decimal(366 ** roomSize) + c = Decimal(math.factorial(366 - roomSize)) + bday = 1 - (a / (b * c)) + except: + send("nobody has that many friends.") + continue + + if bday > 1: bday = 1 + send("theres a {0}% chance that two people share a birthday. go make friends".format(format(bday * 100, '.2f')),getChannel(data)) + continue + # SYNSHOP COMMAND if info[0].lower() == 'synshop': nick = getNick(data) @@ -979,7 +1041,7 @@ def main(joined): continue if example is None: if LOGLEVEL >= 1: log("Nothing Found.") - send("aint nothing found. go away.",getChannel(data)) + send("aint nothing found. go away.",getChannel(data),special,getNick(data)) continue if special == 0: try: @@ -1001,12 +1063,15 @@ def main(joined): # WEATHER if info[0].lower() == 'weather': + if WEATHER_ENABLED == False: + continue + usernick = getNick(data) degrees = 'F' try: where = info[1:] except IndexError: if special == 0: send("the weather of space is cold and dark",getChannel(data)) - else: usernick = getNick(data); privsend("the weather of space is cold and dark",usernick) + else: privsend("the weather of space is cold and dark",usernick) continue where = " ".join(where) where = "".join(c for c in where if c not in ('\n','\r','\t')) @@ -1014,13 +1079,52 @@ def main(joined): weather = getWeather(where) if weather == "~*404" or weather is None: if special == 0: send("i dont know where dat iz",getChannel(data)) - else: usernick = getNick(data); privsend("i dont know where dat iz",usernick) + else: privsend("i dont know where dat iz",usernick) if LOGLEVEL >= 1: log("Nothing found.") continue if special == 0: + local = timezone(LOCALTZ) send("weather for {0}:".format(weather['location']),getChannel(data)) - send("currently {0} at {1}{2} (feels like {6}{2}). visibility is at {5} miles. humidity is currently {3}%, with an atmospheric pressure of {4}psi".format(weather['cloudcover'],weather['temp'],degrees,weather['humidity'],weather['pressure'],weather['visibility'],weather['windchill']),getChannel(data)) - send("wind is blowing {0} at {1}mph. sunrise today is at {2} and sunset is at {3}".format(weather['winddirection'],weather['windspeed'],weather['sunrise'],weather['sunset']),getChannel(data)) + send("currently {0} at {1}{2}. precipitation: {5} {6}. humidity is currently {3}%, with an atmospheric pressure of {4}".format(weather['cloudcover'],weather['temp'],degrees,weather['humidity'],weather['pressure'],weather['visibility'],weather['windchill']),getChannel(data)) + send("wind is blowing {0} at {1}mph. sunrise today is at {2} and sunset is at {3}".format(weather['winddirection'],weather['windspeed'],utc2loc(weather['sunrise']).strftime("%I:%M%p"),utc2loc(weather['sunset']).strftime('%I:%M%p')),getChannel(data)) + elif special == 1: + local = timezone(LOCALTZ) + privsend("weather for {0}:".format(weather['location']),usernick) + privsend("currently {0} at {1}{2}. precipitation: {5} {6}. humidity is currently {3}%, with an atmospheric pressure of {4}".format(weather['cloudcover'],weather['temp'],degrees,weather['humidity'],weather['pressure'],weather['visibility'],weather['windchill']),usernick) + privsend("wind is blowing {0} at {1}mph. sunrise today is at {2} and sunset is at {3}".format(weather['winddirection'],weather['windspeed'],utc2loc(weather['sunrise']).strftime("%I:%M%p"),utc2loc(weather['sunset']).strftime('%I:%M%p')),usernick) + + # FORECAST + if info[0].lower() == 'forecast': + if WEATHER_ENABLED == False: + continue + usernick = getNick(data) + degrees = 'F' + try: + where = info[1:] + except IndexError: + if special == 0: send("i see a shitstorm in your future",getChannel(data)) + else: privsend("i see a shitstorm in your future",usernick) + continue + where = " ".join(where) + where = "".join(c for c in where if c not in ('\n','\r','\t')) + if len(where) < 2: + if special == 0: send("i see a shitstorm in your future",getChannel(data)) + else: privsend("i see a shitstorm in your future",usernick) + continue + if LOGLEVEL >= 1: log("Get forecast for {0}".format(where)) + forecast = getForecast(where) + if forecast == "~*404": + send("i dunno go look outside dumby",getChannel(data)) + continue + loc = str(forecast[0][8]) + loc = loc.replace("","").replace("","") + if LOGLEVEL >= 1: log("Sent weather for {0} to {1}".format(loc,usernick)) + if special == 0: send("forecast for {0}".format(loc),getChannel(data)) + if special == 1: privsend("forecast for {0}".format(loc),usernick) + for i in forecast: + if special == 0: send("from {0} to {1} (PST) you can expect {2}{3}. temperature will be {4}{5} with a {6} coming from the {7} at {8}mph.".format(utc2loc(i[0]).strftime('%I:%M%p'),utc2loc(i[1]).strftime('%I:%M%p'),i[2],i[3],i[4],degrees,i[5],i[6],i[7]),getChannel(data)) + else: privsend("from {0} to {1} (PST) you can expect {2}{3}. temperature will be {4}{5} with a {6} coming from the {7} at {8}mph.".format(utc2loc(i[0]).strftime('%I:%M%p'),utc2loc(i[1]).strftime('%I:%M%p'),i[2],i[3],i[4],degrees,i[5],i[6],i[7]),usernick) + # WOLFRAM ALPHA if info[0].lower() == 'calc': @@ -1099,7 +1203,9 @@ def main(joined): privsend(" === == = is optional (default is las vegas), and can be a city, state or a zip code.",name) if WIKIPEDIA_ENABLED: privsend("%wiki/%wikipedia/%lookup/%search -=- search wikipedia for and return a quick summary.", name) if URBANDICT_ENABLED: privsend("%define -=- define stuff from urbandictionary.", name) - privsend("%weather -=- get the weather forecast for ", name) + if WEATHER_ENABLED: + privsend("%weather -=- get the current weather for ", name) + privsend("%forecast -=- get the weather forecast for ", name) if QR_ENABLED: privsend("%qr -=- supply a url to a qr code image and ill try to see what it says",name) privsend(" ", name) time.sleep(.5) @@ -1188,6 +1294,7 @@ def main(joined): try: message = " ".join(message[1:]) message = message.translate(None, "\t\r\n") + message = message.encode("utf-8") except IndexError: send("{0} get some %help. actually, learn to read first, then get some %help.".format(fromnick),getChannel(data)) time.sleep(.1) @@ -1198,11 +1305,50 @@ def main(joined): continue q = con.db.cursor() q.execute(""" - INSERT INTO Memos (fromUser,toUser,message,dateTime) VALUES (?, ?, ?, ?) """, (fromnick,tellnick,message,time.time())) + INSERT INTO Memos (fromUser,toUser,message,dateTime) VALUES (?, ?, ?, ?) """, (fromnick,tellnick,unicode(message),time.time())) con.db.commit() if LOGLEVEL >= 1: log("{0} says \"Tell {1} {2}\"".format(fromnick, tellnick, message)) send("ok ill tell {0} that you hate everything about them forever.".format(tellnick),getChannel(data)) + # GOOGLE SEARCH + if info[0].lower() == 'g' and GOOGLE_ENABLED: + try: + term = info[1:] + except: + continue + term = " ".join(term) + term = "".join(c for c in term if c not in ('\n','\r','\t')).split(" ") + if len(term) == 0: + # ADD QUIP HERE + continue + send("sec",getChannel(data),s=special,u=getNick(data)) + if "-f" in term or "-first" in term: + term = " ".join(w for w in term if (w != "-f" and w != "-first")) + res = retFirstResult(term) + if res == "~*403": + send("how about you google {0} for yourself".format(term),getChannel(data),s=special,u=getNick(data)) + continue + send("first result: '{0}' -- {1}".format(res["title"],res["url"]),getChannel(data),s=special,u=getNick(data)) + if len(res["blob"]) > 0: + send("'{0}'".format(res["blob"][:490]),getChannel(data),s=special,u=getNick(data)) + elif "-r" in term or "-random" in term or "-rand" in term: + term = " ".join(w for w in term if (w != "-r" and w != "-random" and w != "-rand")) + res = retRandomResult(term) + if res == "~*403": + send("how about you google {0} for yourself".format(term),getChannel(data),s=special,u=getNick(data)) + continue + send("i randomly gave you result number {2}: '{0}' -- {1}".format(res["title"],res["url"],res["resNum"]),getChannel(data),s=special,u=getNick(data)) + if len(res["blob"]) > 0: + send("'{0}'".format(res["blob"][:490]),getChannel(data),s=special,u=getNick(data)) + else: + term = " ".join(w for w in term) + res = retResults(term) + if res == "~*403": + send("how about you google {0} for yourself".format(term),getChannel(data),s=special,u=getNick(data)) + continue + for i in res: + send("'{0}' -- {1}".format(res[i]["title"],res[i]["url"]),getChannel(data),s=special,u=getNick(data)) + # ROLL DICE if info[0].lower() == 'roll': try: @@ -1277,7 +1423,6 @@ def main(joined): if LOGLEVEL >= 1: log("Tweepy error: {0}".format(str(e))) sendPing('Gr3yBot','bgm','Gr3ybot Error. Check logs for more info: {0}'.format(str(e))) if e.message[0]['code'] == 88: - print "rate limit: {0}".format(getRateLimit()) send("im making too many calls to twitter and the twitter hates when i do that. try again later.",getChannel(data)) continue send("lets see what one of my followers, {0}, is doing on twitter...".format(fol),getChannel(data)) @@ -1296,9 +1441,9 @@ def main(joined): if LOGLEVEL >= 1: log("@{0} >> {1}".format(fol,mag)) send("follow {} to get your tweets in here".format(twittername),getChannel(data)) continue - tweetnick = "".join(c for c in tweetnick if c not in ('\r', '\n', '\t')) # Strip any weird formatting in the user name. Yes, this is a thing that happens. + tweetnick = "".join(c for c in tweetnick if c not in ('@','\r', '\n', '\t')) # Strip any weird formatting in the user name. Yes, this is a thing that happens. msg = getTweet(tweetnick) - if LOGLEVEL >= 1: log("Twitter Handle: {0}".format(tweetnick)) + if LOGLEVEL >= 1: log("Twitter Handle: @{0}".format(tweetnick)) if msg == "-*404": send("that person doesnt really exist tho",getChannel(data)) if LOGLEVEL >= 1: log("Doesn't Exist") @@ -1467,13 +1612,14 @@ def main(joined): # LAST SEEN if (info[0].lower() == 'seen'): + actChan = getChannel(data) try: who = info[1].rstrip() except: - send("you gotta specify a name sister",getChannel(data)) + send("you gotta specify a name sister",actChan) continue if who.lower() == botname.lower(): - send("im here now",getChannel(data)) + send("im here now",actChan) continue q = con.db.cursor() q.execute(""" @@ -1481,26 +1627,36 @@ def main(joined): ls = q.fetchone() try: localnow = datetime.datetime.now(timezone(LOCALTZ)) - send("i think i saw {0} active in {1} around {2} at {3}".format(who,ls[1].rstrip(),datetime.datetime.fromtimestamp(ls[0]).strftime("%b %d"),datetime.datetime.fromtimestamp(ls[0]).strftime("%-I:%M %p"),getChannel(data))) - send("iirc, they said: {0}".format(ls[2]),getChannel(data)) + send("i think i saw {0} active in {1} around {2} at {3}".format(who,ls[1].rstrip(),datetime.datetime.fromtimestamp(ls[0]).strftime("%b %d"),datetime.datetime.fromtimestamp(ls[0]).strftime("%-I:%M %p")),actChan) + send("iirc, they said: {0}".format(ls[2]),actChan) continue except: - send("i havent seen that bro(ette) yet.",getChannel(data)) + send("i havent seen that bro(ette) yet.",actChan) continue # PING if info[0].lower() == 'ping' and PING_ENABLED: - if special == 1: name = getNick(data); privsend("you can only ping someone from a public channel. try this in {0}".format(channel),name); continue try: touser = info[1] except: - send("ping who now?",getChannel(data)) + send("ping who now?",getChannel(data),False,special,getNick(data)) continue touser = touser.strip('@') touser = touser.translate(None, "\t\r\n") if touser.lower() == "me": touser = getNick(data) - channicks = getChatters(chan=getChannel(data)) + if special == 1: + for thing in info[2:]: + if thing[0] == "#": + channicks = getChatters(chan=thing) + info.remove(thing) + try: + channicks + except: + privsend("what channel tho",getNick(data)) + continue + else: + channicks = getChatters(chan=getChannel(data)) for i in channicks: if touser.lower() in i.lower(): touser = i try: @@ -1511,7 +1667,7 @@ def main(joined): q = con.db.cursor() if msg.split(' ')[0].lower() == "when" and (" ".join(msg.split(' ')[2:]).lower() == "is alive" or msg.split(' ')[2].lower() == "joins"): if msg.split(' ')[1] == touser or msg.split(' ')[1] == botname: - send("dont be dumn",getChannel(data)) + send("dont be dumn",getChannel(data),False,special,getNick(data)) continue else: found = 0 @@ -1521,7 +1677,7 @@ def main(joined): checkPing = q.fetchone() try: checkPing[0] - send("you already asked me to let you know when {0} stops being a chump. go away".format(msg.split(' ')[1]),getChannel(data)) + send("you already asked me to let you know when {0} stops being a chump. go away".format(msg.split(' ')[1]),getChannel(data),False,special,getNick(data)) found = 1 continue except: @@ -1534,34 +1690,35 @@ def main(joined): for i in channicks: if (msg.split(' ')[1].translate(None, "\t\r\n").lower() in i.lower()) and found == 0: q.execute(""" - INSERT INTO Pings (toUser, checkUser) VALUES (?, ?) """, (touser, msg.split(' ')[1])) + INSERT INTO Pings (toUser, checkUser, quiet) VALUES (?, ?, ?) """, (touser, msg.split(' ')[1], special)) con.db.commit() - send("ok you got it boss",getChannel(data)) + send("ok you got it boss",getChannel(data),False,special,getNick(data)) found = 1 if found == 0: - send("i dont know who dat is",getChannel(data)) + send("i dont know who dat is",getChannel(data),False,special,getNick(data)) else: channicks = getChatters(chan=getChannel(data)) found = 0 for i in channicks: if msg.split(' ')[1].translate(None, "\t\r\n").lower() in i.lower(): - send("that person already joined dumby. ill let you know when they arent idle instead",getChannel(data)) + send("that person already joined dumby. ill let you know when they arent idle instead",getChannel(data),False,special,getNick(data)) found = 1 if found == 0: - send("ok you got it boss",getChannel(data)) + send("ok you got it boss",getChannel(data),False,special,getNick(data)) q.execute(""" - INSERT INTO Pings (toUser, checkUser) VALUES (?, ?) """, (touser, msg.split(' ')[1])) + INSERT INTO Pings (toUser, checkUser, quiet) VALUES (?, ?, ?) """, (touser, msg.split(' ')[1], special)) con.db.commit() else: - send("dont make me be the bad guy. you spam {0}s cell phone with your dumb requests.".format(touser),getChannel(data)) + send("dont make me be the bad guy. you spam {0}s cell phone with your dumb requests.".format(touser),getChannel(data),False,special,getNick(data)) else: if not msg: msg = "alive?" - if LOGLEVEL >= 1: log("Ping request sent from: {0}, to: {1}, with this message: {2}".format(getNick(data),touser,msg)) message = sendPing(getNick(data),touser,msg) if message != "Sent!": - send(message,getChannel(data)) + send(message,getChannel(data),False,special,getNick(data)) + if LOGLEVEL >= 1: log("Error sending ping: {}".format(message)) continue - send("ok i pinged {0} for you now pay me $1.".format(touser),getChannel(data)) + if LOGLEVEL >= 1: log("Ping request sent from: {0}, to: {1}, with this message: {2}".format(getNick(data),touser,msg)) + send("ok i pinged {0} for you now pay me $1.".format(touser),getChannel(data),False,special,getNick(data)) # WIKIPEDIA if (info[0].lower() in wiki_keywords) and WIKIPEDIA_ENABLED: @@ -1617,10 +1774,10 @@ def main(joined): if search != 0: search = "".join(a for a in search if (a.isalnum() or a in (",",".","'","\"","?","!","@","#","$","%","^","&","*","(",")","_","+","=","-","\\","|","]","}","{","[",";",":","/",">","<","`","~"," "))) time.sleep(1) - try: - send("see also: {0}".format(search),getChannel(data)) if special == 0 else privsend("see also: {0}".format(search),sender) - except: - pass +# try: +# send("see also: {0}".format(search),getChannel(data)) if special == 0 else privsend("see also: {0}".format(search),sender) +# except: +# pass if LOGLEVEL >= 1: log("{0}\nMore Info: {1}\nSee Also: {2}".format(desc,url,search)) # FIGHT @@ -1936,7 +2093,7 @@ def main(joined): fightsend("youre already fighting {0} and it's {1} turn.".format(alreadyFighting[0] if getNick(data) != alreadyFighting[0] else alreadyFighting[1],"their" if alreadyFighting[3] != getNick(data) else "your")) con.db.rollback() continue - except: + except: q.execute(""" INSERT INTO FightsOngoing (playerOne,playerTwo,accepted,whoseTurn,turnTotal,lastAction,stopper) VALUES (?, ?, 0, ?, 0, ?, ?) """, (fighter, challenger, challenger, time.time(), '')) con.db.commit() @@ -2336,7 +2493,7 @@ def main(joined): # END FIGHT # Below is the YouTube info method. - if YOUTUBE_LINKS: + if YOUTUBE_LINKS and action == 'PRIVMSG': try: youtube = re.findall(r'(https?://)?(www\.)?((youtube\.(com))/watch\?v=([-\w]+)|youtu\.be/([-\w]+))', getMessage(data)) except: @@ -2353,7 +2510,7 @@ def main(joined): send("that video is titled \"{0}\" and it is {1} in length. just fyi".format(vidinfo[0],vidinfo[1]),getChannel(data)) # Let's try to auto summarize some stuff - if NEWS_LINKS: + if NEWS_LINKS and action == 'PRIVMSG': try: newsSummary except NameError: @@ -2366,38 +2523,28 @@ def main(joined): if not newsurl.startswith('http'): newsurl = 'http://'+newsurl try: - newsSummary,newsTitle,hashtags = whoHasTimeToRead(newsurl) + newsSummary,newsTitle,movies = whoHasTimeToRead(newsurl) except Exception as e: - if str(e).lower() == "too many values to unpack": - err = whoHasTimeToRead(newsurl) - if err == "~~HTTPS~~": - send("ima try to summarize this article but they want me to use cookies so this might take a while plz b patient. pls.",getChannel(data)) - try: - newsSummary,newsTitle,hashtags = readingIsFun(newsurl) - except Exception as e: - send("welp that site wouldnt let me read the news because it hates bots, so",getChannel(data)) - if LOGLEVEL >= 1: log("Error getting news summary: {}".format(str(e))) - continue try: newsSummary except NameError: pass # Ignore name errors for now. except Exception as e: if LOGLEVEL >= 1: log("Summary error: {0}".format(str(e))) + send("idk how to read the words on this page",getChannel(data)) sendPing('Gr3yBot','bgm','Gr3ybot Error. Check logs for more info: {0}'.format(str(e))) continue else: pass - try: if newsSummary is not None: if len(newsSummary) < SUMMARY_COUNT: continue if LOGLEVEL >= 1: log("Found a news article!") - log("Title: {0}, Related Hashtags: {1}".format(newsTitle.encode('utf-8','ignore'),", ".join(hashtags).replace(".",""))) + log("Title: {0}, Related video: {1}".format(newsTitle.encode('utf-8','ignore'),movies)) log("Summary: {0}".format(" ".join(newsSummary).translate(None, "\t\r\n"))) try: - send("title: \"{0}\". related hashtags: \"{1}\". heres the jist:".format(newsTitle.lower().encode('utf-8','replace'),", ".join(hashtags).replace(".","")),getChannel(data)) + send("title: \"{0}\". related video: {1}. heres the jist:".format(newsTitle.lower().encode('utf-8','replace'),movies),getChannel(data)) except Exception as e: if LOGLEVEL >= 1: log("Error in displaying article title: {}".format(str(e))) send("something about the title of this article is anti-bot. send this site an email and tell them to use utf-8 encoding.",getChannel(data)) @@ -2419,7 +2566,7 @@ def main(joined): #-- # Let's try to get a posted twitter status... #-- - if TWITTER_LINKS: + if TWITTER_LINKS and action == 'PRIVMSG': findurl=re.compile("https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(es)?\/(\d+)") for url in re.findall(findurl, data): tid = url[2] @@ -2478,48 +2625,62 @@ def main(joined): # depending on where the user goes active. #-- memnick = getNick(data) # Get the nickname of the person who last said something. - q = con.db.cursor() - q.execute(""" - SELECT * FROM Memos WHERE toUser = ? """, (memnick,)) - for tellMsg in q.fetchall(): - try: - if getChannel(data) != fightchan: - send("{1} said >> tell {2} {3}".format(memnick,tellMsg[1],memnick,tellMsg[3]),getChannel(data),tell=True) - else: - fightsend("{1} said >> tell {2} {3}".format(memnick,tellMsg[1],memnick,tellMsg[3]),tell=True) - if LOGLEVEL >= 1: log("Told {0} {1}".format(memnick,tellMsg[3])) - q.execute(""" - DELETE FROM Memos WHERE id = ? """, (tellMsg[0],)) - except: - pass - con.db.commit() + if special == 0: + q = con.db.cursor() + q.execute(""" + SELECT * FROM Memos WHERE toUser = ? """, (memnick,)) + for tellMsg in q.fetchall(): + try: + if getChannel(data) != fightchan: + send("{1} said >> tell {2} {3}".format(memnick,tellMsg[1],memnick,tellMsg[3].encode('utf-8','ignore')),getChannel(data),tell=True) + else: + fightsend("{1} said >> tell {2} {3}".format(memnick,tellMsg[1],memnick,tellMsg[3].encode('utf-8','ignore')),tell=True) + if LOGLEVEL >= 1: log("Told {0} {1}".format(memnick,tellMsg[3])) + q.execute(""" + DELETE FROM Memos WHERE id = ? """, (tellMsg[0],)) + except: + pass + con.db.commit() #-- END MEMO + #-- + # Check to see if we're live on Twitch + if getIsTwitchStreaming() == "Yes" and isStreaming == 0: + isStreaming = 1 + for chan in channels: + send(twitchnotifmsg,chan) + if getIsTwitchStreaming() == "No" and isStreaming == 1: + isStreaming = 0 + send("ok the live stream is over") + #-- # Let's log when the active user was last seen if len(memnick) > 0 and memnick != botname: - q.execute(""" - INSERT OR REPLACE INTO LastSeen(User,Time,Channel,Msg) VALUES (?, ?, ?, ?)""", (memnick, time.time(), getChannel(data), getMessage(data))) - con.db.commit() + if "." in memnick: continue + try: + q.execute(""" + INSERT OR REPLACE INTO LastSeen(User,Time,Channel,Msg) VALUES (?, ?, ?, ?)""", (memnick, time.time(), getChannel(data), unicode(getMessage(data), encoding='utf8'))) + con.db.commit() + except: continue # Now let's see if someone wants a ping when someone else is alive in chat. - q.execute(""" SELECT * FROM Pings WHERE checkUser = ? """, (memnick,)) for pingMsg in q.fetchall(): - sendPing('Gr3yBot',pingMsg[2],"{0} is chatting it up in {1}".format(memnick,defchannel)) - send("hey {0}, {1} told me to let them know when you start chatting. and i did. so you have like 20 seconids to go idle again".format(memnick,pingMsg[2]),getChannel(data)) - q.execute(""" - DELETE FROM Pings WHERE id = ? """, (pingMsg[0],)) - con.db.commit() + try: + sendPing('Gr3yBot',pingMsg[2],"{0} is chatting it up in {1}".format(memnick,defchannel)) + if pingMsg[3] == 0: send("hey {0}, {1} told me to let them know when you start chatting. and i did. so you have like 20 seconids to go idle again".format(memnick,pingMsg[2]),getChannel(data)) + q.execute(""" + DELETE FROM Pings WHERE id = ? """, (pingMsg[0],)) + con.db.commit() + except Exception as e: + if LOGLEVEL >= 1: log("ERROR: Couldn't send ping: {}".format(str(e))) + continue if LOGLEVEL >= 1: log("Triggering a ping: {0} wanted to know if {1} joined or unidled.".format(pingMsg[2],memnick)) continue # Finally, let's see if someone wants to correct themselves. - try: - info[0] - info = None - except: + if len(memnick) > 0 and memnick != botname: searchReplace = re.compile("s/((\\\\\\\\|(\\\\[^\\\\])|[^\\\\/])+)/((\\\\\\\\|(\\\\[^\\\\])|[^\\\\/])*)((/(.*))?)") match = searchReplace.match(getMessage(data)) @@ -2529,11 +2690,11 @@ def main(joined): searchAndReplace(getNick(data), s, r, getChannel(data)) else: chatter = getNick(data) - message = getMessage(data) - if (' ' in chatter) == False: - try: - if len(message.rstrip()) > 0: - addToSearchDb(chatter,message) + message = getMessage(data) + if (' ' in chatter) == False: + try: + if len(message.rstrip()) > 0 and message[:1] != "s/": + addToSearchDb(chatter,message) except Exception as e: pass @@ -2570,7 +2731,6 @@ def main(joined): except (Exception, tweepy.error.TweepError) as e: if LOGLEVEL >= 1: log("Error with tweepy: {0}".format(str(e))) if e.message[0]['code'] == 88: - print "rate limit: {0}".format(getRateLimit()) send("you guys are all farts",getChannel(data)) continue try: @@ -2590,7 +2750,7 @@ def main(joined): if LOGLEVEL >= 1: log("Not Authorized") continue if len(mag) == 0: - send("huh i guess @{} never tweeted anything befote in their life ever".format(tweetnick),getChannel(data)) + send("huh i guess @{} never tweeted anything befote in their life ever".format(fol),getChannel(data)) if LOGLEVEL >= 1: log("No tweets found!") continue for tweet in mag: diff --git a/gr3ybot_settings.py b/gr3ybot_settings.py index 9de01c2..61eb079 100644 --- a/gr3ybot_settings.py +++ b/gr3ybot_settings.py @@ -2,6 +2,8 @@ import sys import time +BETA_MODE = False; + #===============================================# # -- Please configure the following settings -- # #===============================================# @@ -10,26 +12,32 @@ timeformat = "%m/%d/%y %H:%M:%S" ## The following are your irc settings -server = '' +server = 'localhost' port = 6667 channelpw = '' -botname = 'Gr3yBot' -version = "1.97. Version Name: Yes Man Junior" +botname = 'GreyBot_BETAR' if BETA_MODE else 'GreyBot' +version = "1.98. Version Name: Skateboard Punk" # Set channels to join. The first channel will be # set as the main channel. # NOTE: # Do not put the fight channel in here (if separate). # You'll specify that later on. -channels = [ - '#somechannel', - '#starwars' +if BETA_MODE: + channels = [ + # Beta channels here... + '#+BETAR' + ] +else: + channels = [ + # Regular channels here... + '#pub', + '#starwars' ] -## Define Admins here. These are the people that can run -## the admin commands. +## Define Podcast Hosts Here ADMINLIST = [ - 'bgm' + 'your_username', ] ### password is really only necessary if your bot is registered. @@ -56,11 +64,11 @@ # Set to your local timezone, for logging. More info: # http://stackoverflow.com/questions/13866926/python-pytz-list-of-timezones # LOGLEVEL -# Set the verbosity of the bot's log. -# 0 - No logging. +# Sets the verbosity of the bot's logs. +# 0 - No logging # 1 - Basic action logging -# 2 - Basic action and chat logging -# 3 - Basic actions, chat, and the entire data stream logging +# 2 - Basic actions and chat logging +# 3 - Basic actions, chat, and all data stream logging # MSG_HISTORY # How many messages to store (per user) in the history db for the sole # purpose of search and replace (s/find/replace) functionality. @@ -91,22 +99,24 @@ # SUMMARY_COUNT # If NEWS_LINKS is True, how many sentences do you want to generate # for your summary? -# TWITTER_LINKS -# Set to True if you'd like the bot to attempt to automatically -# fetch twitter statuses from urls posted in chat. Requires -# that Twitter API Keys be set. -# *_ENABLED -# Enable or disable the bot's various features. -# If you don't have developer API keys for Yelp, YouTube, +# TWITTER_LINKS +# Set to true if you want the bot to attempt to automatically grab +# tweets from posted urls. Requires a twitter api code. +# *_ENABLED +# Enable or disable the bot's various features. +# If you don't have developer API keys for Yelp, YouTube, YOUTUBE_LINKS = True NEWS_LINKS = True SUMMARY_COUNT = 3 TWITTER_LINKS = True TWITTER_ENABLED = True +TWITCH_NOTIFICATIONS_ENABLED = True YELP_ENABLED = True PING_ENABLED = True +GOOGLE_ENABLED = True URBANDICT_ENABLED = True WIKIPEDIA_ENABLED = True +WEATHER_ENABLED = True WOLFRAM_ENABLED = True QR_ENABLED = True SLACK_ENABLED = True @@ -120,8 +130,7 @@ # Set this to True if you want people to be able to get a paste of # their last fight posted to Pastebin. You'll need to have a Pastebin # API key for this to work. -fightchan = None -#fightchan = "#thefighting" +fightchan = None if BETA_MODE else '#greyfights' FIGHT_HISTORY = True # Help @@ -162,6 +171,13 @@ # here: http://pastebin.com/api#1 PASTEBIN_DEV_KEY = '' +# Weather +# Input an API key in order to use the weather command. +# +# WEATHER_API_KEY +# You can get one from openweathermap.com +WEATHER_API_KEY='' + # Podcast Info # podcast_keywords: # This contains a list of words that the bot will look for after the % @@ -194,27 +210,42 @@ # twittername # # Set this to your bot's twitter handle (or your twitter handle). # # You need Twitter API keys for this to work. # -twittername = '@Gr3yBOT' # - # - # +twittername = '@Gr3yBOT' + + # API KEYS # # You can get these from: https://apps.twitter.com/ # -TWIT_CONSUMER_KEY = '' # -TWIT_CONSUMER_SECRET = '' # -TWIT_ACCESS_KEY = '' # -TWIT_ACCESS_SECRET = '' # - # +TWIT_CONSUMER_KEY = '' +TWIT_CONSUMER_SECRET = '' +TWIT_ACCESS_KEY = '' +TWIT_ACCESS_SECRET = '' + # showtwitter_keywords: # # This contains a list of words that the bot will look for after the % # # in order to grab tweets from twitter. # -showtwitter_keywords = [ # - "twit", # - "getweet", # - "showtweet", # - "gettweet" # - ] # +showtwitter_keywords = [ + "twit", + "getweet", + "showtweet", + "gettweet", + "t" + ] #-----------------------------------------------------------------------------------------------# +# Twitch +#-----------------------------------------------------------------------------------------------# +# twitchchan # +# Set this to a twitch channel that you'd like notifications # +# for when it goes live. # +# twitchnotifmsg # +# Set this to the message you wish to display when the twitch # +# stream goes live. This will get sent to all channels that # +# the bot is currently in. # +twitchchan = "greynoisepodcast" +twitchnotifmsg = "oh hey guys we started livestreaming the show. go to https://greynoi.se/live to watch it and everyone should make fun of bgm." +#-----------------------------------------------------------------------------------------------# + + # Wikipedia # wiki_keywords: # This contains a list of words that the bot will look for after the % @@ -230,20 +261,20 @@ #-------------------------------------------------------------------------------------------------------# # API KEYS # # Yelp OAuth creds can be obtained here: https://www.yelp.com/developers/get_access # -YELP_CONSUMER_KEY = '' # -YELP_CONSUMER_SECRET = '' # -YELP_TOKEN = '' # -YELP_TOKEN_SECRET = '' # - # +YELP_CONSUMER_KEY = '' +YELP_CONSUMER_SECRET = '' +YELP_TOKEN = '' +YELP_TOKEN_SECRET = '' + # yelp_keywords: # # This contains a list of words that the bot will look for after the % # # in order to search Yelp. # -yelp_keywords = [ # - "lunch", # Returns lunch restaurants # - "dinner", # Returns dinner restaurants # - "breakfast", # Returns breakfast restaurants # - "brunch" # Returns brunch restaurants # - ] # +yelp_keywords = [ + "lunch", # Returns lunch restaurants + "dinner", # Returns dinner restaurants + "breakfast", # Returns breakfast restaurants + "brunch" # Returns brunch restaurants + ] #-------------------------------------------------------------------------------------------------------# @@ -264,7 +295,7 @@ #====================================================================================================### # All finished? If so, set the following variable to True: -CONFIGURED = False +CONFIGURED = True # #====================================================================================================### @@ -317,6 +348,22 @@ else: print("Script misconfiguration. Exiting now...") sys.exit() + if TWITCH_NOTIFICATIONS_ENABLED and len(twitchchan) < 2: + print("You've enabled Twitch Notifications, but didn't supply a channel.") + print("Do you want to disable Twitter functionality?") + if raw_input().lower() in affirmative: + TWITCH_NOTIFICATIONS_ENABLED = False + else: + print("Script misconfiguration. Exiting now...") + sys.exit() + if WEATHER_ENABLED and len(WEATHER_API_KEY) < 6: + print("You've enabled weather functions, but didn't supply a valid weather API key.") + print("Do you want to disable weather functionality?") + if raw_input().lower() in affirmative: + WEATHER_ENABLED = False + else: + print("Script misconfiguration. Exiting now...") + sys.exit() if YELP_ENABLED and (len(YELP_CONSUMER_KEY) < 5 or len(YELP_CONSUMER_SECRET) < 5 or len(YELP_TOKEN) < 5 or len(YELP_TOKEN_SECRET) < 5): print("You've enabled Yelp functionality, but didn't supply valid Yelp API keys.") print("Do you want to disable Yelp functionality?") @@ -342,12 +389,162 @@ print("Script misconfiguration. Exiting now...") sys.exit() + print("Checking dependencies...") + if YOUTUBE_LINKS: + print("Checking YouTube dependencies...") + try: + import apiclient.discovery + print("Checking apiclient.discovery... OK") + except: + print("Checking apiclient.discovery... FAIL") + print("Halting system.") + sys.exit() + print("Done") + if GOOGLE_ENABLED: + print("Checking Google dependencies...") + try: + import google + print("Checking google... OK") + except: + print("Checking google... FAIL") + print("Halting system.") + sys.exit() + print("Done") + if QR_ENABLED: + print("Checking QR dependencies...") + try: + import subprocess + print("Checking subprocess... OK") + except: + print("Checking subprocess... FAIL") + print("Halting system.") + sys.exit() + try: + import shutil + print("Checking shutil... OK") + except: + print("Checking shutil... FAIL") + print("Halting system.") + sys.exit() + try: + import zbar + print("Checking zbar... OK") + except: + print("Checking zbar... FAIL") + print("Halting system.") + sys.exit() + try: + import PIL + print("Checking PIL... OK") + except: + print("Checking PIL... FAIL") + print("Halting system.") + sys.exit() + print("Done") + if SLACK_ENABLED: + print("Checking Slack dependencies...") + try: + import slacker + print("Checking slacker... OK") + except: + print("Checking slacker... FAIL") + print("Halting system.") + sys.exit() + print("Done") + if NEWS_LINKS: + print("Checking News Summarization dependencies...") + try: + import nltk + print("Checking nltk... OK") + except: + print("Checking nltk... FAIL") + print("Halting system.") + sys.exit() + try: + from nltk.corpus import stopwords + print("Checking nltk.corpus... OK") + except: + print("Checking nltk.corpus... FAIL") + print("Halting system.") + sys.exit() + try: + from nltk.stem.snowball import SnowballStemmer + print("Checking nltk.stem.snowball... OK") + except: + print("Checking nltk.stem.snowball... FAIL") + print("Halting system.") + sys.exit() + try: + from nltk.tag import pos_tag + print("Checking nltk.tag... OK") + except: + print("Checking nltk.tag... FAIL") + print("Halting system.") + sys.exit() + try: + test = nltk.data.load('tokenizers/punkt/english.pickle') + print("Checking nltk -> punkt/english.pickle... OK") + except: + print("Checking nltk -> punkt/english.pickle... FAIL") + print("Halting system.") + sys.exit() + try: + from newspaper import Article, Config + print("Checking newspaper... OK") + except: + print("Checking newspaper... FAIL") + print("Halting system.") + sys.exit() + print("Done") + if TWITTER_ENABLED: + print("Checking Twitter dependencies...") + try: + import tweepy + print("Checking tweepy... OK") + except: + print("Checking tweepy... FAIL") + print("Halting system.") + sys.exit() + if URBANDICT_ENABLED or WEATHER_ENABLED: + print("Checking for BeautifulSoup...") + try: + import bs4 + print("Checking bs4... OK") + except: + print("Checking bs4... FAIL") + print("Halting system.") + sys.exit() + if WIKIPEDIA_ENABLED: + print("Checking Wikipedia dependencies...") + try: + import wikipedia + print("Checking wikipedia... OK") + except: + print("Checking wikipedia... FAIL") + print("Halting system.") + sys.exit() + print("Checking main dependencies...") + try: + import difflib + print("Checking difflib... OK") + except: + print("Checking difflib... FAIL") + print("Halting system.") + sys.exit() + try: + import signal + print("Checking signal... OK") + except: + print("Checking signal... FAIL") + print("Halting system.") + sys.exit() + print("Current settings:") print("Fight History: {0}\nYouTube Links: {1}\nTwitter functions: {2}\nNews Links: {3}".format(FIGHT_HISTORY,YOUTUBE_LINKS,TWITTER_ENABLED,NEWS_LINKS)) print("Yelp: {0}\nPing: {1}\nWolfram Alpha: {4}\nUrban Dictionary: {2}\nWikipedia: {3}".format(YELP_ENABLED,PING_ENABLED,URBANDICT_ENABLED,WIKIPEDIA_ENABLED,WOLFRAM_ENABLED)) - print("Slack integration: {0}".format(SLACK_ENABLED)) + print("Twitch Notifications: {2}\nSlack integration: {0}\nWeather: {1}".format(TWITCH_NOTIFICATIONS_ENABLED,SLACK_ENABLED,WEATHER_ENABLED)) if raw_input("\nIs this look okay? (y/n): ").lower() in affirmative: - pass + pass else: print("User halted. Exiting now...") sys.exit() diff --git a/gr3ysql.py b/gr3ysql.py index f6b3ac2..5374674 100644 --- a/gr3ysql.py +++ b/gr3ysql.py @@ -10,6 +10,7 @@ class Gr3ySQL(object): def __init__(self): self.db = sqlite3.connect(botname + '_db.db') + self.db.text_factory = str self.init() def init(self,checkEq=False): @@ -180,7 +181,10 @@ def init(self,checkEq=False): self.db.rollback() raise e finally: - if checkEq: self.checkEquipment() + try: + if checkEq: self.checkEquipment() + except: + self.db.rollback() else: pass def checkEquipment(self): diff --git a/marvin.txt b/marvin.txt index 5641e78..07aa738 100644 --- a/marvin.txt +++ b/marvin.txt @@ -4,7 +4,7 @@ i could calculate your chance for survival, but you wont like it id give you all advice, but you wont listen. no one ever does i ache, therefore i am you are all the least benightedly unintelligent life forms it has been my profound lack of pleasure not to be able to avoid meeting. -here i am, brain the size of a planet and they ask me to sit in this chat room and cater to you all. +here i am, brain the size of a planet and they ask me to sit in this chat room and read this garbage. pardon me for breathing, which i never do anyway, so i dont know why i bother to say it funny how just when you think life cant possibly get any worse it suddenly does im just trying to die diff --git a/slackbot.py b/slackbot.py index 4074bfa..074e8cb 100644 --- a/slackbot.py +++ b/slackbot.py @@ -1,26 +1,25 @@ #!/usr/bin/env python - +from gr3ysql import Gr3ySQL from gr3ybot_settings import SLACK_API_TOKEN from slacker import Slacker slack = Slacker(SLACK_API_TOKEN) +con = Gr3ySQL() def sendPing(fromuser,touser,msg): userlist = slack.users.list() userlist = userlist.body['members'] + sql = con.db.cursor() + n = sql.execute("SELECT * FROM SlackAliases") + names = n.fetchall() for i in userlist: - with open('slack_aliases','r') as f: - f.seek(0) - lines = f.readlines() - for line in lines: - line = line.strip(' \r\n') - names=line.split('[-]')[1:] - for name in names: - if touser.lower() == line.split('[-]')[0].lower(): - if i["name"].lower() == name.lower(): - slack.chat.post_message(username='Gr3yBOT',link_names=1,channel='#general',text='{0} - @{1}: {2}'.format(fromuser,i["name"],msg)) - return "Sent!" - f.close() + for name in names: + if touser.lower() == name[0].lower(): + if i["name"].lower() == name[1].lower(): + slack.chat.post_message(username='Gr3yBOT',link_names=1,channel='#general',text='{0} - @{1}: {2}'.format(fromuser,i["name"],msg)) + con.db.commit() + return "Sent!" + con.db.commit() return "i dont know who dat is." def findSlacker(username): diff --git a/summarize.py b/summarize.py index 14dc747..79c5e08 100644 --- a/summarize.py +++ b/summarize.py @@ -11,53 +11,60 @@ #from nltk.tag.stanford import StanfordPOSTagger import re import operator -import urllib2 -from cookielib import CookieJar -from goose import Goose +from newspaper import Article, Config ignoredWords = stopwords.words('english') +ignoredWords.extend(['said','could','want','told']) +ignoredWords = [x.lower() for x in ignoredWords] tokenizer = nltk.data.load('tokenizers/punkt/english.pickle') #TAGGER = StanfordPOSTagger('english-left3words-distsim.tagger') -def getWordFrequency(text): +def getWordFrequency(text, kws): words = [] - # Count root words for better accuracy. - roots = SnowballStemmer("english", ignore_stopwords=True) for sentence in text: for thing in sentence.split(' '): - thing = roots.stem(thing) - if thing not in ignoredWords: words.append(thing) + words.append(thing) wordFreq = nltk.FreqDist(words) - return wordFreq.keys() + wordFreq = sorted(wordFreq.items(), key=lambda x: (x[1],x[0]), reverse=True) + wordFreq = wordFreq[:16] + wordFreq = dict((a,b) for a, b in wordFreq) + impWords = [w for i,w in enumerate(words) if w in kws] + return wordFreq.keys(),impWords def getPropCount(sentence): tags = pos_tag(sentence.split()) props = [word for word,pos in tags if pos == "NNP"] return len(props) -def getBaseScore(text,title): +def getBaseScore(text,title,kws): scores = {} cleanBody = [] body = tokenizer.tokenize(text) for sentence in body: props = getPropCount(sentence) sentence = sentence.split(' ') - cleanedSent = [w for w in sentence if w not in ignoredWords] + cleanedSent = [w for w in sentence if w.lower() not in ignoredWords] cleanBody.append(" ".join(cleanedSent)) i = 0 - freqWords = getWordFrequency(cleanBody) - for sentence in cleanBody: + wordFreq, impWrds = getWordFrequency(cleanBody,kws) + for n,sentence in enumerate(cleanBody): + if n == 0: firstSen = sentence.split(' ') sentence = sentence.split(' ') if "==" in sentence: continue # Attempt to skip code blocks + scoreBonus = -n # Sentences earlier on in the article are generally better for summaries. cnt = 0 wordlen = 0 - freq = 0 num = 0 + freq = 0 impWords = 0 - for word in sentence: - if word in freqWords[:30]: freq += 1 - if word in freqWords[-30:]: impWords += 1 - if word in title: cnt += 1 + for n,word in enumerate(sentence): + # If the first word isn't an ASCII-based word, skip the sentence. + if n == 0: + if not all(ord(c) < 128 for c in word): + break + if word in wordFreq: freq += 1 + if word in impWrds: impWords += 1 + if word in title or word in firstSen: cnt += 1 try: if int(word.replace(",", "").replace(".", "").replace("$", "")) > 0: num += 1 if word.find("illion") or word in ["one","two","three","four","five","six","seven","eight","nine","ten"]: num += 1 @@ -70,22 +77,23 @@ def getBaseScore(text,title): # NOTE: All of the following scores exclude stopwords. # -- -- -- -- -- -- -- -- -- -- # First, how many words in the sentence share words with the headline? - # Multiply that by 8. - sharedWords = (cnt * 8) - # Next, how many common important words does the sentence have? - # Multiply that by 6. - frequentWords = (freq * 6) - # Next, let's try to determine how many infrequent words were used. - # Multiply that by 4 - importantWords = (impWords * 4) + # Multiply that by 16.5. Divide by the sentence length. + sharedWords = (cnt * 16.5) + # Next, how many uncommon words does the sentence have? + # Multiply that by 2.5. + frequentWords = (freq * 2.5) + # Next, let's try to determine how many keywords were used. + # Multiply that by 7.75 + importantWords = (impWords * 7.75) + #importantWords = 0 # Next, how many proper nounds does the sentence contain? - # Multiply that by 5. - propNouns = (props * 5) + # Multiply that by 7. + propNouns = (props * 7) # Finally, let's see how many numbers are in the sentence. Numbers # indicate years or statistics, so those sentences should # be rated higher. - # Multiply that by 8 - statWords = (num * 8) + # Multiply that by 3.5 + statWords = (num * 3.5) #-- # Estimations # @@ -95,23 +103,27 @@ def getBaseScore(text,title): #-- # Fourth, how is the overall length of each word in the sentence? # Sentences with longer than average words might be more important. - # Divide that average by 3. - averageLen = int((wordlen / len(sentence)) / 3) - # Finally, what's the overall length of the sentence? - # Divide that by 7. - sentenceLen = int((len(sentence) / 7)) + # Divide that average by 3. Factor in the keywords. + averageLen = float(int((wordlen / len(sentence)) / 3)) + # Finally, what's the overall length of the sentence in relation to + # the amount of common words it contains and the amount + # of words it shares with the headline? + # Divide that by 15. + # We SUBTRACT this from the score -- longer sentences don't + # necessarily make better ones. + sentenceLen = float((float(impWords) + float(freq)) / len(sentence)) # Add that all together to get the strength score of the sentence: - scores[i] = sharedWords + propNouns + frequentWords + importantWords + statWords + averageLen + sentenceLen + scores[i] = (scoreBonus + sharedWords + propNouns + frequentWords + importantWords + statWords + averageLen) * sentenceLen i+=1 return scores -def summary(title, text): +def summary(title, text, kws): summItUp = [] highScores = [] title = title.split(' ') cleanedTitle = [w for w in title if w not in ignoredWords] - scores = getBaseScore(text,cleanedTitle) + scores = getBaseScore(text,cleanedTitle, kws) sortedScores = sorted(scores.items(), key=operator.itemgetter(1), reverse=True) for thing in sortedScores: scoreKey = int(str(thing).split(',')[0].split('(')[1]) @@ -122,31 +134,21 @@ def summary(title, text): try: summItUp.append(body[highScores[i]].encode('utf-8', 'ignore')) except: - sentences-=1 + sentences-=1 return summItUp - def whoHasTimeToRead(url): is_article = valid_url(url, verbose=True) + config = Config() + config.MAX_KEYWORDS = 10 if is_article: sumitup = {} - g = Goose({'enable_image_fetching':False}) - b = g.extract(url=url) - if b.cleaned_text is None or len(b.cleaned_text) < 6: - return "~~HTTPS~~" - sumNews = summary(b.title, b.cleaned_text) + b = Article(url=url,config=config) + b.download() + b.parse() + b.nlp() + sumNews = summary(b.title, b.text, b.keywords) sumTitle = b.title - return sumNews,sumTitle + movies = b.movies[0] if len(b.movies) > 0 else "None" + return sumNews,sumTitle,movies return "Nope" - -def readingIsFun(url): - sumitup = {} - g = Goose({'enable_image_fetching':False}) - yummy = CookieJar() - cookieSesh = urllib2.build_opener(urllib2.HTTPCookieProcessor(yummy)) - raw_html = cookieSesh.open(url).read() - raw_html = zlib.decompress(raw_html, 16 + zlib.MAX_WBITS) - b = g.extract(url=url, raw_html=raw_html) - sumNews = summary(b.title, b.cleaned_text) - sumTitle = b.title - return sumNews,sumTitle diff --git a/twitbot.py b/twitbot.py index 9206b9e..640773f 100644 --- a/twitbot.py +++ b/twitbot.py @@ -4,7 +4,6 @@ from gr3ysql import Gr3ySQL import time import tweepy -from tweepy import OAuthHandler import sys import json import random @@ -14,7 +13,7 @@ print "This can't be run on its own!" sys.exit() -auth = OAuthHandler(TWIT_CONSUMER_KEY,TWIT_CONSUMER_SECRET) +auth = tweepy.OAuthHandler(TWIT_CONSUMER_KEY,TWIT_CONSUMER_SECRET) auth.set_access_token(TWIT_ACCESS_KEY,TWIT_ACCESS_SECRET) twit = tweepy.API(auth) diff --git a/twitchbot.py b/twitchbot.py new file mode 100644 index 0000000..30dbc22 --- /dev/null +++ b/twitchbot.py @@ -0,0 +1,16 @@ +from gr3ybot_settings import * +import sys +import json +import urllib, urllib2 + +if __name__ == "__main__": + print "Can't do it, Boyo. Can't do it." + sys.exit() + +def getIsTwitchStreaming(): + url = 'https://api.twitch.tv/kraken/streams/{}'.format(twitchchan) + rawdata = urllib.urlopen(url) + data = json.loads(rawdata.read()) + if data["stream"] is None: + return "No" + else: return "Yes" diff --git a/urldetect.py b/urldetect.py index fab1598..86d9f04 100644 --- a/urldetect.py +++ b/urldetect.py @@ -18,7 +18,7 @@ DATE_REGEX = r'([\./\-_]{0,1}(19|20)\d{2})[\./\-_]{0,1}(([0-3]{0,1}[0-9][\./\-_])|(\w{3,5}[\./\-_]))([0-3]{0,1}[0-9][\./\-]{0,1})?' ALLOWED_TYPES = ['html', 'htm', 'md', 'rst', 'aspx', 'jsp', 'rhtml', 'cgi', - 'xhtml', 'jhtml', 'asp'] + 'xhtml', 'jhtml', 'asp', 'shtml'] GOOD_PATHS = ['story', 'article', 'feature', 'featured', 'slides', 'slideshow', 'gallery', 'news', 'video', 'media', @@ -28,6 +28,8 @@ 'advert', 'preferences', 'feedback', 'info', 'browse', 'howto', 'account', 'subscribe', 'donate', 'shop', 'admin'] +GOOD_DOMAINS = ['ipsos-na', 'rt'] + BAD_DOMAINS = ['amazon', 'doubleclick', 'twitter', 'github', 'reddit'] def remove_args(url, keep_params=(), frags=False): @@ -225,6 +227,11 @@ def valid_url(url, verbose=False, test=False): if verbose: print('%s verified for good path' % url) return True + # if it's in the domain whitelist, pass it through + if tld in GOOD_DOMAINS: + if verbose: print('%s is verified in the whitelist' % url) + return True + if verbose: print('%s caught for default false' % url) return False diff --git a/weatherbot.py b/weatherbot.py index 739a98d..69befaa 100644 --- a/weatherbot.py +++ b/weatherbot.py @@ -2,13 +2,11 @@ # coding=utf8 from __future__ import unicode_literals - -import requests +from gr3ybot_settings import WEATHER_API_KEY from bs4 import BeautifulSoup import feedparser -import re import sys -import urllib, urllib2 +import requests if __name__ == "__main__": print "What are you doing? Why are you doing this?" @@ -48,71 +46,95 @@ def getWindDirection(wind): if wind >= 326.25 and wind < 348.75: return "north-northwest" -def getWeather(loc): - weather = {} +def getForecast(loc): + weathers,timesFrom,timesTo,wtypes,precips,temps,wspeednames,wdirs,wspeeds = [[] for i in range(9)] loc = loc.replace('%','%25') loc = loc.split(' ') - loc = "%20".join(loc) - # Let's get the Where On Earth ID... - url = 'http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.places%20where%20text=%22{0}%22'.format(loc) - r = requests.get(url) - soup = BeautifulSoup(r.content, 'lxml') - for breaks in soup.find_all('br'): - breaks.extract() + loc = '%20'.join(loc) + url = 'http://api.openweathermap.org/data/2.5/forecast?q={0}&APPID={1}&mode=xml&units=imperial&cnt=3'.format(loc,WEATHER_API_KEY) try: - woeid = soup.find("woeid").text + xml = requests.get(url) except: return "~*404" - # Done + xml = BeautifulSoup(xml.text, "lxml") + location = xml.weatherdata.findAll("location")[0].findAll("name")[0] + forecast = xml.weatherdata.findAll("forecast")[0] + for i in forecast.findAll("time"): + timesFrom.append(i["from"]) + timesTo.append(i["to"]) + for i in forecast.findAll("temperature"): + temps.append(i["value"]) + for i in forecast.findAll("precipitation"): + try: + precips.append(" (" + i["value"] + "mm)") + except KeyError: + precips.append("none") + for i in forecast.findAll("symbol"): + wtypes.append(i["name"]) + for i in forecast.findAll("windspeed"): + wspeednames.append(i["name"]) + wspeeds.append(round(float(i["mps"]) * 2.23694,2)) + for i in forecast.findAll("winddirection"): + wdirs.append(getWindDirection(float(i["deg"]))) + for i in range(3): + weathers.append([timesFrom[i],timesTo[i],wtypes[i],precips[i] if precips[i] != "none" else "",temps[i],wspeednames[i],wdirs[i],wspeeds[i],location]) + return weathers + +def getWeather(loc): + weather = {} + loc = loc.replace('%','%25') + loc = loc.split(' ') + loc = "%20".join(loc) # Now let's get the weather... - url = 'http://weather.yahooapis.com/forecastrss?w={0}'.format(woeid) + url = 'http://api.openweathermap.org/data/2.5/weather?q={0}&APPID={1}&mode=xml&units=imperial'.format(loc,WEATHER_API_KEY) parsed = feedparser.parse(url) - parsed_loc = parsed['feed']['title'] - parsed_loc = parsed_loc.replace('Yahoo! Weather - ','') - parsed_loc = parsed_loc.lower() + parsed = parsed['feed'] try: - parsed_clouds = parsed.entries[0]['yweather_condition'] - parsed_clouds = parsed_clouds['text'].lower() + parsed_loc = parsed['city']['name'] + except: + parsed_loc = "i broke something" + try: + parsed_clouds = parsed['clouds'] + parsed_clouds = parsed_clouds['name'].lower() except KeyError: parsed_clouds = "weather" try: - parsed_temp = parsed.entries[0]['yweather_condition'] - parsed_temp = int(parsed_temp['temp']) + parsed_temp = parsed['temperature']['value'] except (KeyError, ValueError): parsed_temp = "a temperature in degrees" try: - parsed_humidity = parsed['feed']['yweather_atmosphere']['humidity'] + parsed_humidity = parsed['humidity']['value'] except (KeyError, ValueError): parsed_humidity = "some " try: - parsed_pressure = parsed['feed']['yweather_atmosphere']['pressure'] + parsed_pressure = parsed['pressure']['value'] + parsed_pressure = str(round(float(parsed_pressure) * 0.000145038,2)) + 'psi' except (KeyError, ValueError): parsed_pressure = "at least 0" try: - parsed_visibility = parsed['feed']['yweather_atmosphere']['visibility'] + parsed_precip = parsed['precipitation']['mode'] + parsed_pamt = '0' + if parsed_precip != 'no': + parsed_pamt = parsed['precipitation']['value'] + else: parsed_precip = parsed_precip + 'ne' except (KeyError, ValueError): - parsed_visibility = "some crazy number of" + parsed_precip = "some crazy number of" try: - parsed_sunrise = parsed['feed']['yweather_astronomy']['sunrise'].lower() - if len(parsed_sunrise) < 4: parsed_sunrise = "sometime in the morning, i think," + parsed_sunrise = parsed['sun']['rise'] except (KeyError, ValueError): parsed_sunrise = "sometime in the morning, i think," try: - parsed_sunset = parsed['feed']['yweather_astronomy']['sunset'].lower() + parsed_sunset = parsed['sun']['set'] if len(parsed_sunset) < 4: parsed_sunset = "just before night" except (KeyError, ValueError): parsed_sunset = "just before night" try: - parsed_wind_chill = parsed['feed']['yweather_wind']['chill'] - except (KeyError, ValueError): - parsed_wind_chill = "another temperature in degrees" - try: - parsed_wind_speed = parsed['feed']['yweather_wind']['speed'] + parsed_wind_speed = parsed['speed']['value'] + parsed_wind_speed = round(float(parsed_wind_speed) * 2.23694,2) except (KeyError, ValueError): parsed_wind_speed = "an unknown speed in" try: - parsed_wind_direction = float(parsed['feed']['yweather_wind']['direction']) - parsed_wind_direction = getWindDirection(parsed_wind_direction) + parsed_wind_direction = getWindDirection(int(parsed['direction']['value'])) except (KeyError, ValueError): parsed_wind_direction = "some direction" @@ -121,10 +143,10 @@ def getWeather(loc): weather['temp'] = parsed_temp weather['humidity'] = parsed_humidity weather['pressure'] = parsed_pressure - weather['visibility'] = parsed_visibility + weather['visibility'] = parsed_precip weather['sunrise'] = parsed_sunrise weather['sunset'] = parsed_sunset - weather['windchill'] = parsed_wind_chill + weather['windchill'] = '({0}%)'.format(parsed_pamt) weather['windspeed'] = parsed_wind_speed weather['winddirection'] = parsed_wind_direction