def remind(text, nick, chan, db, conn, notice, async): """<1 minute, 30 seconds>: <do task> -- reminds you to <do task> in <1 minute, 30 seconds>""" count = len([x for x in reminder_cache if x[0] == conn.name and x[3] == nick.lower()]) if text == "clear": if count == 0: return "You have no reminders to delete." yield from delete_all(async, db, conn.name, nick) yield from load_cache(async, db) return "Deleted all ({}) reminders for {}!".format(count, nick) # split the input on the first ":" parts = text.split(":", 1) if len(parts) == 1: # user didn't add a message, send them help notice(remind.__doc__) return if count > 10: return "Sorry, you already have too many reminders queued (10), you will need to wait or " \ "clear your reminders to add any more." time_string = parts[0].strip() message = colors.strip_all(parts[1].strip()) # get the current time in both DateTime and Unix Epoch current_epoch = time.time() current_time = datetime.fromtimestamp(current_epoch) # parse the time input, return error if invalid seconds = time_parse(time_string) if not seconds: return "Invalid input." if seconds > 2764800 or seconds < 60: return "Sorry, remind input must be more then a minute, and less then one month." # work out the time to remind the user, and check if that time is in the past remind_time = datetime.fromtimestamp(current_epoch + seconds) if remind_time < current_time: return "I can't remind you in the past!" # finally, add the reminder and send a confirmation message yield from add_reminder(async, db, conn.name, nick, chan, message, remind_time, current_time) yield from load_cache(async, db) remind_text = format_time(seconds, count=2) output = "Alright, I'll remind you \"{}\" in $(b){}$(clear)!".format(message, remind_text) return colors.parse(output)
def bing(text, bot): """<query> - returns the first Bing search result for <query>""" api_key = bot.config.get("api_keys", {}).get("bing_azure") # handle NSFW show_nsfw = text.endswith(" nsfw") # remove "nsfw" from the input string after checking for it if show_nsfw: text = text[:-5].strip().lower() rating = NSFW_FILTER if show_nsfw else DEFAULT_FILTER if not api_key: return "Error: No Bing Azure API details." # why are these all differing formats and why does format have a $? ask microsoft params = { "Sources": bingify("web"), "Query": bingify(text), "Adult": bingify(rating), "$format": "json" } request = requests.get(API_URL, params=params, auth=(api_key, api_key)) # I'm not even going to pretend to know why results are in ['d']['results'][0] j = request.json()['d']['results'][0] if not j["Web"]: return "No results." result = j["Web"][0] # not entirely sure this even needs un-escaping, but it wont hurt to leave it in title = formatting.truncate(unescape(result["Title"]), 60) desc = formatting.truncate(unescape(result["Description"]), 150) url = unescape(result["Url"]) return colors.parse('{} -- $(b){}$(b): "{}"'.format(url, title, desc))
arguments = "" if factoid_id in factoid_cache: data = factoid_cache[factoid_id] # factoid pre-processors if data.startswith("<py>"): code = data[4:].strip() variables = 'input="""{}"""; nick="{}"; chan="{}"; bot_nick="{}";'.format(arguments.replace('"', '\\"'), event.nick, event.chan, event.conn.nick) result = yield from async(web.pyeval, variables + code) else: result = data # factoid post-processors result = colors.parse(result) if result.startswith("<act>"): result = result[5:].strip() action(result) elif result.startswith("<url>"): url = result[5:].strip() response = requests.get(url) if response.status_code != requests.codes.ok: message("Failed to fetch resource.") else: message(response.text) else: message(result)
def amazon(text, _parsed=False): """<query> -- Searches Amazon for query""" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, ' 'like Gecko) Chrome/41.0.2228.0 Safari/537.36', 'Referer': 'http://www.amazon.com/' } params = { 'url': 'search-alias', 'field-keywords': text.strip() } if _parsed: # input is from a link parser, we need a specific URL request = requests.get(SEARCH_URL.format(_parsed), params=params, headers=headers) else: request = requests.get(SEARCH_URL.format(REGION), params=params, headers=headers) soup = BeautifulSoup(request.text) results = soup.find('div', {'id': 'atfResults'}) if not results: if not _parsed: return "No results found." else: return results = results.find('ul', {'id': 's-results-list-atf'}).find_all('li', {'class': 's-result-item'}) item = results[0] asin = item['data-asin'] # here we use dirty html scraping to get everything we need title = formatting.truncate(item.find('h2', {'class': 's-access-title'}).text, 60) tags = [] # tags! if item.find('i', {'class': 'a-icon-prime'}): tags.append("$(b)Prime$(b)") if item.find('i', {'class': 'sx-bestseller-badge-primary'}): tags.append("$(b)Bestseller$(b)") if re.search(r"(Kostenlose Lieferung|Livraison gratuite|FREE Shipping|Envío GRATIS" r"|Spedizione gratuita)", item.text, re.I): tags.append("$(b)Free Shipping$(b)") price = item.find('span', {'class': ['s-price', 'a-color-price']}).text # use a whole lot of BS4 and regex to get the ratings try: pattern = re.compile(r'(product-reviews|#customerReviews)') rating = item.find('i', {'class': 'a-icon-star'}).find('span', {'class': 'a-icon-alt'}).text rating = re.search(r"([0-9]+(?:(?:\.|,)[0-9])?).*5", rating).group(1).replace(",", ".") num_ratings = item.find('a', {'href': pattern}).text.replace(".", ",") rating_str = "{}/5 stars ({} ratings)".format(rating, num_ratings) except AttributeError: rating_str = "No Ratings" # generate a short url if AFFILIATE_TAG: url = "http://www.amazon.com/dp/" + asin + "/?tag=" + AFFILIATE_TAG else: url = "http://www.amazon.com/dp/" + asin + "/" url = web.try_shorten(url) tag_str = " - " + ", ".join(tags) if tags else "" if not _parsed: return colors.parse("$(b){}$(b) ({}) - {}{} - {}".format(title, price, rating_str, tag_str, url)) else: return colors.parse("$(b){}$(b) ({}) - {}{}".format(title, price, rating_str, tag_str))
for reminder in reminder_cache: network, remind_time, added_time, user, message = reminder if remind_time <= current_time: if network not in bot.connections: # connection is invalid yield from add_reminder(async, db, network, remind_time, user) yield from load_cache(async, db) continue conn = bot.connections[network] if not conn.ready: return remind_text = colors.parse(time_since(added_time, count=2)) alert = colors.parse("{}, you have a reminder from $(b){}$(clear) ago!".format(user, remind_text)) conn.message(user, alert) conn.message(user, '"{}"'.format(message)) delta = (remind_time-added_time).seconds if delta > (30*60): late_time = time_since(remind_time, count=2) late = "(I'm sorry for delivering this message $(b){}$(clear) late," \ " it seems I was unable to deliver it on time)".format(late_time) conn.message(user, colors.parse(late)) yield from delete_reminder(async, db, network, remind_time, user) yield from load_cache(async, db)
def color_parse(text): return colors.parse(text)
def eightball(action): """<question> - asks the all knowing magic electronic eight ball <question>""" magic = random.choice(responses) message = colors.parse("shakes the magic 8 ball... {}".format(magic)) action(message)
def test_parse(): assert parse(test_input) == test_parse_output