def xkcd(m): """Get an xkcd comic based on given arguments.""" if len(m.line) == 1: url = "http://c.xkcd.com/random/comic/" html = get_url(m, url) message = xkcd_direct(html) if message is None: m.bot.logger.error("Couldn't get random xkcd comic.") message = "Sorry, I'm broken. Tell GorillaWarfare to fix me." elif len(m.line) == 2 and m.line[1].isdigit(): url = "http://xkcd.com/{0}/".format(m.line[1]) html = get_url(m, url) if html is None: m.bot.private_message(m.location, "There is no xkcd #{0}.".format(m.line[1])) return message = xkcd_direct(html, url) if message is None: m.bot.logger.error("Couldn't get xkcd comic #{0}.".format(m.line[1])) message = "Sorry, I'm broken. Tell GorillaWarfare to fix me." else: query = " ".join(m.line[1:]) url = 'https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=site:xkcd.com%20{0}'\ .format(quote(query)) html = get_url(m, url) message = xkcd_google(html) m.bot.private_message(m.location, message)
def reddit(m, url): """Retrieve information about the Reddit link.""" # I'm sorry reddit_regex = re.compile( r'reddit\.com/(?:u(?:ser)?/(?P<user>.+?)(?:\Z|#|/)|r/(?P<sub>.+?)' r'(?:/?\Z|/comments/(?P<id>.+?)(?:/?\Z|/(?P<title>.+?)' r'(?:/?\Z|/(?P<cid>.+?)(?:/|#|\Z)))))') match = re.search(reddit_regex, url) if match: m.bot.logger.info( "Retrieving information from the Reddit API for {}.".format(url)) if match.group("user"): api_url = "http://www.reddit.com/user/{}/about.json" user = match.group("user") resp = get_url(m, api_url.format(user)) blob = json.loads(resp)["data"] return "User {name}: {link_karma} link karma, {comment_karma} comment " \ "karma.".format(**blob) else: api_url = "http://www.reddit.com/api/info.json?id={}" sub, id, cid = match.group("sub"), match.group("id"), match.group( "cid") if cid: resp = get_url(m, api_url.format("t1_" + cid)) blob = json.loads(resp)["data"]["children"][0]["data"] parent_resp = get_url(m, api_url.format("t3_" + id)) parent_blob = json.loads( parent_resp)["data"]["children"][0]["data"] parent_blob["nsfw"] = " \x0304[NSFW]\x03" if parent_blob[ "over_18"] else "" return "Comment by {user} on \"{title}\"{nsfw} in /r/{sub}. {up}↑.".format( user=blob["author"], title=parent_blob["title"], nsfw=parent_blob["nsfw"], sub=blob["subreddit"], up=blob["ups"]) elif id: resp = get_url(m, api_url.format("t3_" + id)) blob = json.loads(resp)["data"]["children"][0]["data"] blob["nsfw"] = "\x0304[NSFW]\x03" if blob["over_18"] else "" return "\"{title}\" in /r/{subreddit}. {ups}↑. {nsfw}".format( **blob) else: api_url = "http://www.reddit.com/r/{}/about.json" resp = get_url(m, api_url.format(sub)) blob = json.loads(resp)["data"] blob["nsfw"] = "\x0304[NSFW]\x03" if blob["over18"] else "" return "/r/{display_name}. {title}. {subscribers} subscribers." \ " {nsfw}".format(**blob) return generic(m, url)
def get_weather(m, loc, api_key): """Make the API call to get the weather.""" if loc: m.bot.logger.info("Finding weather for {}.".format(loc["name"])) forecast_api = "https://api.forecast.io/forecast/{0}/{1},{2}?exclude=flags" resp = get_url(m, forecast_api.format(api_key, loc["lat"], loc["long"])) return json.loads(resp)
def spotify(m): """Retrieve information about a Spotify URI.""" #- !spotify URI #- #- ```irc #- < GorillaWarfare> !spotify spotify:track:6NmXV4o6bmp704aPGyTVVG #- < GorillaBot> "Bøn Fra Helvete (Live)" by Kaizers Orchestra #- ``` #- #- Provide information about the Spotify URI. Accepts Spotify- and HTTP-style URIs. #- #- #### Settings #- * `auto` - All Spotify URIs in the chat will be parsed, regardless of whether they're #- prefaced with `!spotify`. spotify_uris = re.findall(SPOTIFY_URI_REGEX, m.body) for spotify_uri in spotify_uris: media_type, identifier = spotify_uri req = get_url(m, ENDPOINT.format(media_type, identifier)) if req: blob = json.loads(req) if media_type == "track" or media_type == "album": m.bot.private_message( m.location, '"{0}" by {1}'.format(blob["name"], blob["artists"][0]["name"])) else: m.bot.private_message(m.location, blob["name"])
def spotify(m): """Retrieve information about a Spotify URI.""" #- !spotify URI #- #- ```irc #- < GorillaWarfare> !spotify spotify:track:6NmXV4o6bmp704aPGyTVVG #- < GorillaBot> "Bøn Fra Helvete (Live)" by Kaizers Orchestra #- ``` #- #- Provide information about the Spotify URI. Accepts Spotify- and HTTP-style URIs. #- #- #### Settings #- * `auto` - All Spotify URIs in the chat will be parsed, regardless of whether they're #- prefaced with `!spotify`. spotify_uris = re.findall(SPOTIFY_URI_REGEX, m.body) for spotify_uri in spotify_uris: media_type, identifier = spotify_uri req = get_url(m, ENDPOINT.format(media_type, identifier)) if req: blob = json.loads(req) if media_type == "track" or media_type == "album": m.bot.private_message(m.location, '"{0}" by {1}'.format(blob["name"], blob["artists"][0]["name"])) else: m.bot.private_message(m.location, blob["name"])
def reddit(m, url): """Retrieve information about the Reddit link.""" # I'm sorry reddit_regex = re.compile(r'reddit\.com/(?:u(?:ser)?/(?P<user>.+?)(?:\Z|#|/)|r/(?P<sub>.+?)' r'(?:/?\Z|/comments/(?P<id>.+?)(?:/?\Z|/(?P<title>.+?)' r'(?:/?\Z|/(?P<cid>.+?)(?:/|#|\Z)))))') match = re.search(reddit_regex, url) if match: m.bot.logger.info("Retrieving information from the Reddit API for {}.".format(url)) if match.group("user"): api_url = "http://www.reddit.com/user/{}/about.json" user = match.group("user") resp = get_url(m, api_url.format(user)) blob = json.loads(resp)["data"] return "User {name}: {link_karma} link karma, {comment_karma} comment " \ "karma.".format(**blob) else: api_url = "http://www.reddit.com/api/info.json?id={}" sub, id, cid = match.group("sub"), match.group("id"), match.group("cid") if cid: resp = get_url(m, api_url.format("t1_" + cid)) blob = json.loads(resp)["data"]["children"][0]["data"] parent_resp = get_url(m, api_url.format("t3_" + id)) parent_blob = json.loads(parent_resp)["data"]["children"][0]["data"] parent_blob["nsfw"] = " \x0304[NSFW]\x03" if parent_blob["over_18"] else "" return "Comment by {user} on \"{title}\"{nsfw} in /r/{sub}. {up}↑.".format( user = blob["author"], title = parent_blob["title"], nsfw = parent_blob["nsfw"], sub = blob["subreddit"], up = blob["ups"] ) elif id: resp = get_url(m, api_url.format("t3_" + id)) blob = json.loads(resp)["data"]["children"][0]["data"] blob["nsfw"] = "\x0304[NSFW]\x03" if blob["over_18"] else "" return "\"{title}\" in /r/{subreddit}. {ups}↑. {nsfw}".format(**blob) else: api_url = "http://www.reddit.com/r/{}/about.json" resp = get_url(m, api_url.format(sub)) blob = json.loads(resp)["data"] blob["nsfw"] = "\x0304[NSFW]\x03" if blob["over18"] else "" return "/r/{display_name}. {title}. {subscribers} subscribers." \ " {nsfw}".format(**blob) return generic(m, url)
def xkcd(m): """Get an xkcd comic based on given arguments.""" #- !xkcd [number|query] #- #- ```irc #- < GorillaWarfare> !xkcd batman acne #- < GorillaBot> xkcd: Complexion: http://xkcd.com/700/ #- < GorillaWarfare> !xkcd 700 #- < GorillaBot> xkcd: Complexion: http://xkcd.com/700/ #- < GorillaWarfare> !xkcd #- < GorillaBot> xkcd: Telescope Names: http://xkcd.com/1294/ #- ``` #- #- Without any arguments, this provides a random xkcd comic. When a number is supplied, #- it tries to return the xkcd comic with that given number. When a query string is supplied, #- it tries to return the xkcd comic that most closely matches that query. if len(m.line) == 1: url = "https://c.xkcd.com/random/comic/" html = get_url(m, url) message = xkcd_direct(html) if message is None: m.bot.logger.error("Couldn't get random xkcd comic.") message = "Sorry, I'm broken. Tell GorillaWarfare to fix me." elif len(m.line) == 2 and m.line[1].isdigit(): url = "http://xkcd.com/{0}/".format(m.line[1]) html = get_url(m, url) if html is None: m.bot.private_message(m.location, "There is no xkcd #{0}.".format(m.line[1])) return message = xkcd_direct(html, url) if message is None: m.bot.logger.error("Couldn't get xkcd comic #{0}.".format( m.line[1])) message = "Sorry, I'm broken. Tell GorillaWarfare to fix me." else: query = " ".join(m.line[1:]) url = 'https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=site:xkcd.com%20{' \ '0}'.format(quote(query)) html = get_url(m, url) message = xkcd_google(html) m.bot.private_message(m.location, message)
def xkcd(m): """Get an xkcd comic based on given arguments.""" #- !xkcd [number|query] #- #- ```irc #- < GorillaWarfare> !xkcd batman acne #- < GorillaBot> xkcd: Complexion: http://xkcd.com/700/ #- < GorillaWarfare> !xkcd 700 #- < GorillaBot> xkcd: Complexion: http://xkcd.com/700/ #- < GorillaWarfare> !xkcd #- < GorillaBot> xkcd: Telescope Names: http://xkcd.com/1294/ #- ``` #- #- Without any arguments, this provides a random xkcd comic. When a number is supplied, #- it tries to return the xkcd comic with that given number. When a query string is supplied, #- it tries to return the xkcd comic that most closely matches that query. if len(m.line) == 1: url = "http://c.xkcd.com/random/comic/" html = get_url(m, url) message = xkcd_direct(html) if message is None: m.bot.logger.error("Couldn't get random xkcd comic.") message = "Sorry, I'm broken. Tell GorillaWarfare to fix me." elif len(m.line) == 2 and m.line[1].isdigit(): url = "http://xkcd.com/{0}/".format(m.line[1]) html = get_url(m, url) if html is None: m.bot.private_message(m.location, "There is no xkcd #{0}.".format(m.line[1])) return message = xkcd_direct(html, url) if message is None: m.bot.logger.error("Couldn't get xkcd comic #{0}.".format(m.line[1])) message = "Sorry, I'm broken. Tell GorillaWarfare to fix me." else: query = " ".join(m.line[1:]) url = 'https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=site:xkcd.com%20{' \ '0}'.format(quote(query)) html = get_url(m, url) message = xkcd_google(html) m.bot.private_message(m.location, message)
def generic(m, url): """Retrieve the title of the webpage.""" m.bot.logger.info("Retrieving link for {}.".format(url)) html = get_url(m, url, True) if html: title_regex = re.compile(r'<title>(.+?)</title>', re.DOTALL) match = re.search(title_regex, html) if match: return match.group(1) else: m.bot.logger.info("No title element found.") return None
def youtube(m, url): """Retrieve information about the YouTube video.""" api_key = m.bot.configuration["youtube"] if api_key: match = re.search(r'youtu(?:be.com/watch\?v=|\.be/)(.+?)(?:\?|&|\Z)', url) if match: video_id = match.group(1) m.bot.logger.info( "Retrieving information from the YouTube API for {}.".format( url)) api_url = "https://www.googleapis.com/youtube/v3/videos?id={id}" \ "&key={key}&part=snippet,contentDetails,statistics" resp = get_url(m, api_url.format(id=video_id, key=api_key)) if resp: # Load JSON blob = json.loads(resp)["items"][0] # Parse uploaded time this was originally # raw_time = raw_time = datetime.strptime(blob["snippet"]["publishedAt"], "%Y-%m-%dT%H:%M:%S.%fZ") pretty_time = raw_time.strftime("%b %d, %Y") # Parse video duration dur_match = re.match(r'PT(?:(\d+)H)?(?:(\d+)M)?(\d+)S', blob["contentDetails"]["duration"]) if dur_match: hr, min, sec = dur_match.groups() if hr: pretty_dur = ":".join([ hr, "00" if min is None else min.zfill(2), sec.zfill(2) ]) else: pretty_dur = ":".join([ "00" if min is None else min.zfill(2), sec.zfill(2) ]) else: pretty_dur = "" # Format and return message return "\"{title}\" ({duration}). Uploaded {date}. {views} views. {likes} likes, " \ "{dislikes} dislikes.".format(title=blob["snippet"]["title"], duration=pretty_dur, date=raw_time, # this was originally pretty_time! I changed it to raw! views=blob["statistics"]["viewCount"], likes=blob["statistics"]["likeCount"], dislikes=blob["statistics"]["dislikeCount"]) # If there's no API key stored, or the URL is poorly formatted, fall back to generic linking return generic(m, url)
def get_location(m, line): """Get the latitude, longitude, and well-formatted name of the given location.""" google_api = "http://maps.googleapis.com/maps/api/geocode/json?address={}" loc = {} loc["name"] = " ".join(line) resp = get_url(m, google_api.format("+".join(line))) blob = json.loads(resp) if not blob["results"]: m.bot.private_message(m.location, "Could not find weather information for {}." .format(" ".join(line))) else: loc["lat"] = blob['results'][0]['geometry']['location']['lat'] loc["long"] = blob['results'][0]['geometry']['location']['lng'] loc["addr"] = blob['results'][0]['formatted_address'] return loc
def bash_specific(m, number): """Get a specific quote from bash.org.""" resp = get_url(m, "http://bash.org?" + number) soup = BeautifulSoup(resp) raw = soup.find(class_="qt") if raw: meta = soup.find(class_="quote") lines = raw.get_text().splitlines() if len(lines) > 5 and not m.is_pm: m.bot.private_message(m.location, "This quote is too long to post publicly, " "but you can view it at http://bash.org?" "{}.".format(number)) else: format_quote(m, lines, meta, number) else: m.bot.private_message(m.location, "Could not find bash quote.")
def get_location(m, line): """Get the latitude, longitude, and well-formatted name of the given location.""" google_api = "http://maps.googleapis.com/maps/api/geocode/json?address={}" loc = {} loc["name"] = " ".join(line) resp = get_url(m, google_api.format("+".join(line))) blob = json.loads(resp) if not blob["results"]: m.bot.private_message( m.location, "Could not find weather information for {}.".format( " ".join(line))) else: loc["lat"] = blob['results'][0]['geometry']['location']['lat'] loc["long"] = blob['results'][0]['geometry']['location']['lng'] loc["addr"] = blob['results'][0]['formatted_address'] return loc
def spotify(m): """Retrieve information about a Spotify URI.""" spotify_uris = re.findall(SPOTIFY_URI_REGEX, m.body) for spotify_uri in spotify_uris: try: type, id = _parse_spotify_uri(spotify_uri) except ValueError: m.bot.logger.error("Invalid Spotify URI: " + spotify_uri) else: req = get_url(m, ENDPOINT.format(type, id)) if req: blob = json.loads(req) if type == "track" or type == "album": m.bot.private_message(m.location, '"{0}" by {1}' .format(blob["name"], blob["artists"][0]["name"])) else: m.bot.private_message(m.location, blob["name"])
def bash_rand(m): """Get a random quote from bash.org""" resp = get_url(m, "http://bash.org?random1") soup = BeautifulSoup(resp, features="html.parser") raw = soup.find(class_="qt") if raw: meta = soup.find(class_="quote") while True: if not raw: bash_rand(m) return lines = raw.get_text().splitlines() if len(lines) <= 5: break raw = raw.find_next(class_="qt") meta = soup.find_next(class_="quote") format_quote(m, lines, meta) else: m.bot.private_message(m.location, "Could not find bash quote.")
def bash_rand(m): """Get a random quote from bash.org""" resp = get_url(m, "http://bash.org?random1") soup = BeautifulSoup(resp) raw = soup.find(class_="qt") if raw: meta = soup.find(class_="quote") while True: if not raw: bash_rand(m) return lines = raw.get_text().splitlines() if len(lines) <= 5: break raw = raw.find_next(class_="qt") meta = soup.find_next(class_="quote") format_quote(m, lines, meta) else: m.bot.private_message(m.location, "Could not find bash quote.")
def youtube(m, url): """Retrieve information about the YouTube video.""" api_key = m.bot.get_config('youtube') if api_key: match = re.search(r'youtu(?:be.com/watch\?v=|\.be/)(.+?)(?:\?|&|\Z)', url) if match: video_id = match.group(1) m.bot.logger.info("Retrieving information from the YouTube API for {}.". format(url)) api_url = "https://www.googleapis.com/youtube/v3/videos?id={id}" \ "&key={key}&part=snippet,contentDetails,statistics" resp = get_url(m, api_url.format(id = video_id, key = api_key)) if resp: # Load JSON blob = json.loads(resp)["items"][0] # Parse uploaded time raw_time = datetime.strptime(blob["snippet"]["publishedAt"], "%Y-%m-%dT%H:%M:%S.%fZ") pretty_time = raw_time.strftime("%b %d, %Y") # Parse video duration dur_match = re.match(r'PT(?:(\d+)H)?(?:(\d+)M)?(\d+)S', blob["contentDetails"]["duration"]) hr, min, sec = dur_match.groups() if hr: pretty_dur = ":".join([hr, "00" if min is None else min.zfill(2), sec.zfill(2)]) else: pretty_dur = ":".join(["00" if min is None else min.zfill(2), sec.zfill(2)]) # Format and return message return "\"{title}\" ({duration}). Uploaded {date}. {views} views. {likes} likes, " \ "{dislikes} dislikes.".format( title = blob["snippet"]["title"], duration = pretty_dur, date = pretty_time, views = blob["statistics"]["viewCount"], likes = blob["statistics"]["likeCount"], dislikes = blob["statistics"]["dislikeCount"] ) # If there's no API key stored, or the URL is poorly formatted, fall back to generic linking return generic(m, url)