def default_mask(trigger): welcome = formatting.color('Welcome to:', formatting.colors.PURPLE) chan = formatting.color(trigger.sender, formatting.colors.TEAL) topic_ = formatting.bold('Topic:') topic_ = formatting.color('| ' + topic_, formatting.colors.PURPLE) arg = formatting.color('{}', formatting.colors.GREEN) return '{} {} {} {}'.format(welcome, chan, topic_, arg)
def test_color(): text = 'Hello World' assert color(text) == text assert color(text, colors.PINK) == '\x0313' + text + '\x03' assert color(text, colors.PINK, colors.TEAL) == '\x0313,10' + text + '\x03' pytest.raises(ValueError, color, text, 100) pytest.raises(ValueError, color, text, 'INVALID')
def xkcdb(bot, trigger): qid = trigger.group(3) if qid: # specific quote lookup page = html.parse('http://www.xkcdb.com/%s' % qid).getroot() else: # random quote page = html.parse('http://www.xkcdb.com/random1').getroot() try: quoteblock = page.cssselect('p.quoteblock')[0] except IndexError: bot.say("XKCDB quote %snot found!" % ("#%s " % qid) if qid else "") return header = quoteblock.cssselect('span.quotehead')[0] quote = quoteblock.cssselect('span.quote')[0] for br in quote.xpath('*//br'): br.tail = '\n' + br.tail if br.tail else '\n' lines = quote.text_content().split('\n') qid = int(header.cssselect('.idlink')[0].text_content()[1:]) ratings = re.search('\(\+(?P<up>\d+)/\-(?P<down>\d+)\)', header.text_content()) up = formatting.color('+%s' % ratings.group('up'), 'green') down = formatting.color('-%s' % ratings.group('down'), 'red') url = 'http://www.xkcdb.com/%s' % qid bot.say("XKCDB quote #%s (%s/%s) - %s" % (qid, up, down, url)) if len(lines) <= 6: for line in lines: bot.say(line) else: for line in lines[:3]: bot.say(line) bot.say("[Quote truncated. Visit %s to read the rest.]" % url)
def get_data(bot, trigger, URL): URL = URL.split('#')[0] try: raw = fetch_api_endpoint(bot, URL) rawLang = fetch_api_endpoint(bot, URL + '/languages') except HTTPError: bot.say('[Github] API returned an error.') return NOLIMIT data = json.loads(raw) langData = list(json.loads(rawLang).items()) langData = sorted(langData, key=operator.itemgetter(1), reverse=True) if 'message' in data: return bot.say('[Github] %s' % data['message']) langColors = deque(['12', '08', '09', '13']) max = sum([pair[1] for pair in langData]) data['language'] = '' for (key, val) in langData[:3]: data['language'] = data['language'] + color(str("{0:.1f}".format(float(val) / max * 100)) + '% ' + key, langColors[0]) + ' ' langColors.rotate() if len(langData) > 3: remainder = sum([pair[1] for pair in langData[3:]]) data['language'] = data['language'] + color(str("{0:.1f}".format(float(remainder) / max * 100)) + '% Other', langColors[0]) + ' ' timezone = get_timezone(bot.db, bot.config, None, trigger.nick) if not timezone: timezone = 'UTC' data['pushed_at'] = format_time(bot.db, bot.config, timezone, trigger.nick, trigger.sender, from_utc(data['pushed_at'])) return data
def display(data, crypto, currency): price = data['data'][crypto.upper()]['quote'][currency.upper()]['price'] percent_change_1h = data['data'][crypto.upper()]['quote'][ currency.upper()]['percent_change_1h'] last_updated = data['data'][crypto.upper()]['quote'][ currency.upper()]['last_updated'] message = ('{crypto} ${price:g} ') if percent_change_1h >= 0: message += color('({percent_change_1h:.2f}%)', colors.GREEN) message += color(u'\u2b06', colors.GREEN) else: message += color('({percent_change_1h:.2f}%)', colors.RED) message += color(u'\u2b07', colors.RED) message += ' (Last Updated: {last_updated})' message = message.format( crypto=crypto.upper(), price=float(price), percent_change_1h=float(percent_change_1h), last_updated=arrow.get(last_updated).humanize(), ) print(message) return message
def get_data(bot, trigger, URL): URL = URL.split('#')[0] try: raw = fetch_api_endpoint(bot, URL) rawLang = fetch_api_endpoint(bot, URL + '/languages') except HTTPError: bot.say('[GitHub] API returned an error.') return NOLIMIT data = json.loads(raw) langData = list(json.loads(rawLang).items()) langData = sorted(langData, key=operator.itemgetter(1), reverse=True) if 'message' in data: return bot.say('[GitHub] %s' % data['message']) langColors = deque(['12', '08', '09', '13']) max = sum([pair[1] for pair in langData]) data['language'] = '' for (key, val) in langData[:3]: data['language'] = data['language'] + color(str("{0:.1f}".format(float(val) / max * 100)) + '% ' + key, langColors[0]) + ' ' langColors.rotate() if len(langData) > 3: remainder = sum([pair[1] for pair in langData[3:]]) data['language'] = data['language'] + color(str("{0:.1f}".format(float(remainder) / max * 100)) + '% Other', langColors[0]) + ' ' timezone = get_timezone(bot.db, bot.config, None, trigger.nick) if not timezone: timezone = 'UTC' data['pushed_at'] = format_time(bot.db, bot.config, timezone, trigger.nick, trigger.sender, from_utc(data['pushed_at'])) return data
def check_price(nick,ticker,default_price): checkprice = StockMarket() checkprice.open_db(file_Name) check = StockTrade() check.open_db(saved_stocks) try: curprice = checkprice.get_balance(ticker) checked = check.get_prices(ticker) except: checkprice.add_stock(ticker,default_price) curprice = checkprice.get_balance(ticker) checked = check.get_prices(ticker) ticker = color(bold(ticker + ":"),colors.RED) curprice = color(str(curprice),colors.RED) phrase = ('%s ɷ %s' %(ticker,curprice)) runs = 0 for x in (checked): if nick == checked[runs][0]: name = color(checked[runs][0],colors.RED) else: name = checked[runs][0][:3] owned = (bold(" |") + " %s %s @ %s " % (name.title(), checked[runs][2], checked[runs][1])) phrase += owned runs = runs + 1 return phrase
def redditor_info(bot, trigger, match, commanded=False): """Shows information about the given Redditor""" try: u = bot.memory['reddit_praw'].redditor(match) u.id # shortcut to check if the user exists or not except prawcore.exceptions.NotFound: if commanded: bot.reply('No such Redditor.') # Fail silently if it wasn't an explicit command. return plugin.NOLIMIT message = u.name is_cakeday = get_is_cakeday(u.created_utc) if is_cakeday: message = message + ' | ' + bold(color('Cake day', colors.LIGHT_PURPLE)) if commanded: message = message + ' | https://reddit.com/u/' + u.name if u.is_gold: message = message + ' | ' + bold(color('Gold', colors.YELLOW)) if u.is_employee: message = message + ' | ' + bold(color('Employee', colors.RED)) if u.is_mod: message = message + ' | ' + bold(color('Mod', colors.GREEN)) message = message + (' | Link: ' + str(u.link_karma) + ' | Comment: ' + str(u.comment_karma)) bot.say(message)
def album(link_id, bot): """ Handles information retrieval for non-gallery albums. The bot will output the title, the number of images and the number of views of the album. """ client = ImgurClient(bot.config.imgur.client_id) api_response = client.resource('album', link_id) album = api_response['data'] # print(album) is_nsfw = "{}".format( color(" [NSFW] ", colors.RED) if album. get('nsfw') else color(" [SFW] ", colors.GREEN)) if album['images_count'] == 1: # image(album['images'][0]['id'], bot) bot.say(f"\x02[imgur]\x02 - direct link: {album['images'][0]['link']}") return bot.say('\x02[imgur]\x02{3}{0} - {1} image{5} - ' \ '{2:,} view{6}{4}'.format(album.get('title') if album.get('title') else "untitled", str(album['images_count']), \ album['views'], is_nsfw, parse_date(album['datetime']), 's' if album['images_count'] > 1 else '', 's' if (album['views'] > 1 or album['views'] == 0) else '' ))
def getticket(bot, trigger): """Look up tickets in Jira and display their information""" if not hasattr(bot.config, 'jira'): bot.say("I don't seem to have a 'jira' section in my config!") return user = bot.config.jira.user password = bot.config.jira.password url = bot.config.jira.url if user is None or password is None or url is None: bot.say('You need to set user, password and url in the jira section of the config') return for issue in findall('[A-Z]+-[0-9]+', trigger): r = requests.get( os.path.join(url, 'rest/api/2/issue', issue), auth=(user, password)) if r.status_code != 200: return j = r.json() bot.say("({} {}) {} [ {} ] {} {}".format( j['fields']['issuetype']['name'], j['key'], j['fields']['summary'], color((j['fields']['assignee']['displayName'] if j['fields']['assignee'] else 'Unassigned'), 'BLUE'), bold(color(j['fields']['status']['name'], 'GREEN')), os.path.join(url, 'browse', j['key'])))
def announce_shift(bot, channel, rotation): """Anounces a shift and sets the topic to reflect that change""" debug(bot, 'announce_shift_complete: shifts - curr:{s1}'.format(s1=rotation)) hashline = formatting.color('###', formatting.colors.RED) lead = formatting.color( ' Shift Lead: {curr_nick}'.format(curr_nick=rotation['Shift Lead']), formatting.colors.RED) secondary = formatting.color( ' Shift Secondary: {curr_nick}'.format( curr_nick=rotation['Shift Secondary']), formatting.colors.RED) oncall = formatting.color( ' On-Call: {oncall_nick}'.format(oncall_nick=rotation['Oncall']), formatting.colors.RED) oncallWeeday = formatting.color( ' No oncall scheduled on weekdays, contact shift lead', formatting.colors.RED) if bot.db.get_channel_value(channel, 'announce'): print("Annoucing to channel " + str(channel)) bot.say(hashline, channel) bot.say(lead, channel) bot.say(secondary, channel) if rotation['Oncall']: bot.say(oncall, channel) else: bot.say(oncallWeeday, channel) else: print("Failed to get channel value")
def gelbooru(bot, trigger): """ .gelbooru <tags> -- Gets a random image, based on given tags from gelbooru.com """ global lastsearch global gelbooru_cache if trigger.group(2): search = trigger.group(2).strip().lower() else: search = '' if not search in lastsearch or len(gelbooru_cache) < 2: refresh_cache(bot, search) lastsearch = search if len(gelbooru_cache) == 0: bot.say('No results for search "{0}"'.format(trigger.group(2).strip())) return post_id, score, url, rating, tags = gelbooru_cache.pop() if 'e' in rating: rating = color('NSFW', colors.RED) elif 'q' in rating: rating = color('Questionable', colors.YELLOW) elif 's' in rating: rating = color('Safe', colors.GREEN) bot.say('[gelbooru] Score: {0} | Rating: {1} | http://gelbooru.com/index.php?page=post&s=view&id={2} | Tags: {3}' .format(score, rating, post_id, tags.strip()))
def test_plain_color(): text = 'some text' assert plain(color(text, colors.PINK)) == text assert plain(color(text, colors.PINK, colors.TEAL)) == text tpl = 'b %s a' expected = tpl % text assert plain(tpl % color(text, colors.PINK)) == expected assert plain(tpl % color(text, colors.PINK, colors.TEAL)) == expected
def rpost_info(bot, trigger, match=None): r = praw.Reddit( user_agent=USER_AGENT, client_id='6EiphT6SSQq7FQ', client_secret=None, ) match = match or trigger s = r.submission(id=match.group(2)) message = ('[REDDIT] {title} {link}{nsfw} | {points} points ({percent}) | ' '{comments} comments | Posted by {author} | ' 'Created at {created}') subreddit = s.subreddit.display_name if s.is_self: link = '(self.{})'.format(subreddit) else: link = '({}) to r/{}'.format(s.url, subreddit) if s.over_18: if subreddit.lower() in spoiler_subs: nsfw = bold(color(' [SPOILERS]', colors.RED)) else: nsfw = bold(color(' [NSFW]', colors.RED)) sfw = bot.db.get_channel_value(trigger.sender, 'sfw') if sfw: link = '(link hidden)' bot.write(['KICK', trigger.sender, trigger.nick, 'Linking to NSFW content in a SFW channel.']) else: nsfw = '' if s.author: author = s.author.name else: author = '[deleted]' tz = time.get_timezone(bot.db, bot.config, None, trigger.nick, trigger.sender) time_created = dt.datetime.utcfromtimestamp(s.created_utc) created = time.format_time(bot.db, bot.config, tz, trigger.nick, trigger.sender, time_created) if s.score > 0: point_color = colors.GREEN else: point_color = colors.RED percent = color(unicode(s.upvote_ratio * 100) + '%', point_color) title = unescape(s.title) message = message.format( title=title, link=link, nsfw=nsfw, points=s.score, percent=percent, comments=s.num_comments, author=author, created=created) bot.say(message)
def query_jira(jira_id): response = requests.get(jboss_org_rest + jira_id) response = response.json() if "fields" in response: return "[{0}] {1} - {2}".format( jira_id, response["fields"]["summary"], color(jboss_org_case + jira_id, colors.GREY)) color(text, colors.PINK) else: return "Sorry but I couldn't fetch the URL"
def rpost_info(bot, trigger, match=None): r = praw.Reddit(user_agent=USER_AGENT) match = match or trigger s = r.get_submission(submission_id=match.group(1)) message = ('[REDDIT] {title} {link}{nsfw} | {points} points ({percent}) | ' '{comments} comments | Posted by {author} | ' 'Created at {created}') if s.is_self: link = '(self.{})'.format(s.subreddit.display_name) else: link = '({}) to r/{}'.format(s.url, s.subreddit.display_name) if s.over_18: nsfw = bold(color(' [NSFW]', colors.RED)) sfw = bot.db.get_channel_value(trigger.sender, 'sfw') if sfw: link = '(link hidden)' bot.write([ 'KICK', trigger.sender, trigger.nick, 'Linking to NSFW content in a SFW channel.' ]) else: nsfw = '' if s.author: author = s.author.name else: author = '[deleted]' tz = time.get_timezone(bot.db, bot.config, None, trigger.nick, trigger.sender) time_created = dt.datetime.utcfromtimestamp(s.created_utc) created = time.format_time(bot.db, bot.config, tz, trigger.nick, trigger.sender, time_created) if s.score > 0: point_color = colors.GREEN else: point_color = colors.RED percent = color(str(s.upvote_ratio * 100) + '%', point_color) title = unescape(s.title) message = message.format(title=title, link=link, nsfw=nsfw, points=s.score, percent=percent, comments=s.num_comments, author=author, created=created) bot.say(message)
def getClientSentiment(data, bot, ticker, name): r = requests.get(ig_url + '/clientsentiment/' + ticker, headers=data) pctLong = r.json()['longPositionPercentage'] pctShrt = r.json()['shortPositionPercentage'] out = 'IG ' + name + ' sentiment: ' out += formatting.color(str(pctLong) + "%", formatting.colors.GREEN) out += " / " out += formatting.color(str(pctShrt) + "%", formatting.colors.RED) output(bot, out) return
def key_info(bot, trigger): if not trigger.is_privmsg: bot.reply("Opening query for configuration.") bot.msg(trigger.nick, "Please note that the API Token can be used as a " + color("password", "red") + " and you should never give it to anyone you don't trust!") bot.msg(trigger.nick, "Be aware that BAD THINGS can happen, and your API Token might be made public.") bot.msg(trigger.nick, "IN NO EVENT SHALL THE OPERATORS OF THIS BOT BE LIABLE FOR ANY CLAIM, DAMAGES OR " + "OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN" + "CONNECTION WITH THE BOT OR THE USE OR OTHER DEALINGS IN THE BOT.") bot.msg(trigger.nick, "" + color(bold("YOU HAVE BEEN WARNED!"), "red")) bot.msg(trigger.nick, "If you ARE SURE want this bot to save your API Token, add it with " + "'.hero key IHAVEBEENWARNED <API Token>'")
def stock(bot, trigger): """Get the current price for a given stock.""" # If the user types .stock with no arguments, let them know proper usage if not trigger.group(2): return else: # Get symbol symbol = trigger.group(2) # Do regex checking on symbol to ensure it's valid if not re.match( '^([a-zA-Z0-9]{1,10}:[a-zA-Z0-9]{1,10}|[a-zA-Z0-9]{1,10})$', symbol): bot.say('Invalid Symbol') return # Get data from API try: data = get_price(bot, symbol) except Exception as e: return bot.say(str(e)) message = ('{symbol} ${close:g} ') # Change is None, usually on IPOs if not data['change']: message = message.format( symbol=symbol.upper(), close=float(data['close']), ) # Otherwise, check change versus previous day else: if data['change'] >= 0: message += color('{change:g} ({percentchange:.2f}%)', colors.GREEN) message += color(u'\u2b06', colors.GREEN) else: message += color('{change:g} ({percentchange:.2f}%)', colors.RED) message += color(u'\u2b07', colors.RED) message = message.format( symbol=symbol.upper(), close=float(data['close']), change=float(data['change']), percentchange=float(data['percentchange']), ) # Print results to channel return bot.say(message)
def redditor_info(bot, trigger, match=None): """Shows information about the given Redditor""" commanded = re.match(bot.config.core.prefix + 'redditor', trigger) r = praw.Reddit( user_agent=USER_AGENT, client_id='6EiphT6SSQq7FQ', client_secret=None, ) match = match or trigger try: # praw <4.0 style u = r.get_redditor(match.group(2)) except AttributeError: # praw >=4.0 style u = r.redditor(match.group(2)) except Exception: # TODO: Be specific if commanded: bot.say('No such Redditor.') return NOLIMIT else: return # Fail silently if it wasn't an explicit command. message = '[REDDITOR] ' + u.name now = dt.datetime.utcnow() cakeday_start = dt.datetime.utcfromtimestamp(u.created_utc) cakeday_start = cakeday_start.replace(year=now.year) day = dt.timedelta(days=1) year_div_by_400 = now.year % 400 == 0 year_div_by_100 = now.year % 100 == 0 year_div_by_4 = now.year % 4 == 0 is_leap = year_div_by_400 or ((not year_div_by_100) and year_div_by_4) if (not is_leap) and ((cakeday_start.month, cakeday_start.day) == (2, 29)): # If cake day is 2/29 and it's not a leap year, cake day is 1/3. # Cake day begins at exact account creation time. is_cakeday = cakeday_start + day <= now <= cakeday_start + (2 * day) else: is_cakeday = cakeday_start <= now <= cakeday_start + day if is_cakeday: message = message + ' | ' + bold(color('Cake day', colors.LIGHT_PURPLE)) if commanded: message = message + ' | https://reddit.com/u/' + u.name if u.is_gold: message = message + ' | ' + bold(color('Gold', colors.YELLOW)) if u.is_mod: message = message + ' | ' + bold(color('Mod', colors.GREEN)) message = message + (' | Link: ' + str(u.link_karma) + ' | Comment: ' + str(u.comment_karma)) bot.say(message)
def _say_result(bot, trigger, id_, include_link=True): for n in range(num_retries + 1): try: result = bot.memory['youtube_api_client'].videos().list( id=id_, part='snippet,contentDetails,statistics', ).execute().get('items') except ConnectionError: if n >= num_retries: bot.say('Maximum retries exceeded fetching YouTube video {},' ' please try again later.'.format(id_)) return sleep(random() * 2**n) continue break if not result: return result = result[0] message = ('[You' + color('Tube', colors.WHITE, colors.RED) + '] ' '{title} | Uploader: {uploader} | Uploaded: {uploaded} | ' 'Length: {length} | Views: {views:,} | Comments: {comments}') snippet = result['snippet'] details = result['contentDetails'] statistics = result['statistics'] duration = _parse_duration(details['duration']) uploaded = _parse_published_at(bot, trigger, snippet['publishedAt']) comments = statistics.get('commentCount', '-') if comments != '-': comments = '{:,}'.format(int(comments)) message = message.format( title=snippet['title'], uploader=snippet['channelTitle'], length=duration, uploaded=uploaded, views=int(statistics['viewCount']), comments=comments, ) if 'likeCount' in statistics: likes = int(statistics['likeCount']) message += ' | ' + color('{:,}+'.format(likes), colors.GREEN) if 'dislikeCount' in statistics: dislikes = int(statistics['dislikeCount']) message += ' | ' + color('{:,}-'.format(dislikes), colors.RED) if include_link: message = message + ' | Link: https://youtu.be/' + id_ bot.say(message)
def getQuote(data, bot, ticker): # Fetch data r = requests.get(ig_url + '/markets/' + ticker, headers=data) if debug: print r.json() # Extract bid/offer ig_bid = float(r.json()['snapshot']['bid']) ig_offer = float(r.json()['snapshot']['offer']) ig_mid = float((ig_offer+ig_bid)/2) if debug: print ig_mid # Extract percentChange ig_change = float(r.json()['snapshot']['percentageChange']) if debug: print ig_change # Extract netChange ig_netchange = float(r.json()['snapshot']['netChange']) if debug: print ig_netchange # Format percentChange if ig_change < 0: ig_change_color = formatting.color(str(ig_change) + "%", formatting.colors.RED) elif ig_change > 0: ig_change_color = formatting.color('+' + str(ig_change) + "%", formatting.colors.GREEN) else: ig_change_color = '+' + str(ig_change) + '%' # Format netChange if ig_netchange < 0: ig_netchange_color = formatting.color(str(ig_netchange), formatting.colors.RED) elif ig_netchange > 0: ig_netchange_color = formatting.color('+' + str(ig_netchange), formatting.colors.GREEN) else: ig_netchange_color = '+' + str(ig_netchange) # Extract name name = r.json()['instrument']['name'] # Get expiry expiry = r.json()['instrument']['expiry'] if expiry == '-': out = 'IG ' + name + ': ' else: out = 'IG ' + name + ' ' + expiry + ': ' out += str(ig_mid) out += " (" + ig_change_color + " / " + ig_netchange_color + ")" output(bot, out) return
def formatPercentage(percentage): pf = '{0:.2f}%'.format(percentage) if percentage > 0: pf = '+' + pf if formatting: if percentage < 0: pf = formatting.color(pf, formatting.colors.RED) elif percentage > 0: pf = formatting.color(pf, formatting.colors.GREEN) pf = '(' + pf + ')' return pf
def format_result(result): fixed = { 'title': result['title'] or 'Unknown title', 'episode': result['episode'] or "", 'station': result['station'] or 'Unknown station' } for k in fixed: if fixed[k]: fixed[k] = formatting.color(fixed[k], 'red') fixed['station'] = fixed['station'].replace('I think something messed up when you tried to copy that', 'Ultra! A&G+') if fixed['episode']: fixed['episode'] = " episode %s" % formatting.color(fixed['episode'], 'red') fixed['countdown'] = format_countdown(datetime.fromtimestamp(result['unixtime']) - datetime.today()) return fixed
def formatPercentage(percentage): pf = "{0:.2f}%".format(percentage) if percentage > 0: pf = "+" + pf if formatting: if percentage < 0: pf = formatting.color(pf, formatting.colors.RED) elif percentage > 0: pf = formatting.color(pf, formatting.colors.GREEN) pf = "(" + pf + ")" return pf
def now_playing(bot, trigger): global network db_key = 'lastfm_username' if trigger.group(2): args = trigger.group(2).split(' ') if args[0] in ADD_STRINGS: if len(args) == 1: bot.reply('please provide a username. (.np -s <url>)') else: username = args[1].strip() user_exists = False try: network.get_user(username).get_id() user_exists = True except pylast.WSError: pass if user_exists: bot.db.set_nick_value(trigger.nick, db_key, username) bot.reply('last.fm username set.') else: bot.reply('no such last.fm user. Are you trying to trick me? :^)') return username = bot.db.get_nick_value(trigger.nick, db_key) if not username: bot.reply('you have no last.fm username set. Please set one with .np -s <username>') else: user = network.get_user(username) current_track = user.get_now_playing() if not current_track: bot.say('{0} is not listening to anything right now.'.format(trigger.nick)) else: trackinfo = '{0} - {1}'.format(current_track.get_artist().get_name(), current_track.get_title()) bot.say('{0} is now playing {1} | {2}' .format(trigger.nick, bold(trackinfo), color(current_track.get_url(), colors.BLUE)))
def get_decorated_name(team: Team, string: str) -> str: if team is Team.red: irc_color = irc_format.colors.RED else: irc_color = irc_format.colors.LIGHT_BLUE decorated_name = irc_format.bold(irc_format.color(string, irc_color)) return decorated_name
def generateAcro(self, bot, trigger): self.currentAcro = [] self.countAcros = 1 self.submittedAcros = {} self.voteCount = 0 self.letters = [] if random.randint(1, 100) <= bot.db.get_plugin_value( 'acro', 'custom_chance', 10): customAcros = bot.db.get_plugin_value('acro', 'custom_acros', ['ACRO', 'GAME']) customAcro = random.choice(customAcros).lower() for letter in customAcro: self.currentAcro.append(letter) else: letterPool = bot.db.get_plugin_value('acro', 'letters') for char in letterPool: self.letters.append(char) if (random.randint(0, 5)) == 0: max_length = 6 else: max_length = 4 for _ in range(random.randint(3, max_length)): randomLetter = random.choice(self.letters) self.letters.remove(randomLetter) self.currentAcro.append(randomLetter) self.currentAcroString = bold( color(''.join(self.currentAcro).upper(), colors.ORANGE)) return bot.say(f"Acro for this round: {self.currentAcroString}")
def ytsearch(bot, trigger): """ .youtube <query> - Search YouTube """ if not trigger.group(2): return uri = 'https://www.googleapis.com/youtube/v3/search?part=snippet&type=video&q=' + trigger.group(2) raw = web.get('{0}&key={1}'.format(uri, bot.config.google.public_key)) vid = json.loads(raw)['items'][0]['id']['videoId'] uri = 'https://www.googleapis.com/youtube/v3/videos?id=' + vid + '&part=contentDetails,snippet,statistics' video_info = ytget(bot, trigger, uri) if video_info is None: return title = video_info['snippet']['title'] uploader = video_info['snippet']['channelTitle'] duration = video_info['contentDetails']['duration'] views = video_info['statistics']['viewCount'] likes = video_info['statistics']['likeCount'] dislikes = video_info['statistics']['dislikeCount'] message = '[YT Search] {0} | https://youtu.be/{1} | Duration: {2} | Views: {3} | Uploader: {4} | {5} | {6}'.format( bold(title), video_info['id'], duration, views, uploader, color(likes, colors.GREEN), color(dislikes, colors.RED)) bot.say(message)
def _vimeo_say_result(bot, trigger, id_, include_link=True): """ Parse and say result """ url = "http://vimeo.com/api/v2/video/{vid}.json".format(vid=id_) try: response = requests.get(url) LOGGER.info(response.url) response = response.json() except: LOGGER.error("something went wrong fetching {}".format(url)) return data = response[0] reply = {} vimeo_tag = color("vimeo", "cyan") reply_string = bold("[{}] ".format(vimeo_tag)) reply['title'] = bold(data['title']) reply['duration'] = _parse_duration(data['duration']) reply['channel'] = "Channel: {}".format(data['user_name']) reply['views'] = "{:,} views".format(data['stats_number_of_plays']) reply['uploaded'] = "Uploaded {}".format( _parse_published_at_relative(bot, trigger, data['upload_date'])) reply_string += " | ".join(reply.values()) bot.say(reply_string)
def rainbow_cmd(bot, trigger): """Make text colored. Options are "rainbow", "usa", "commie", and "spooky".""" text = formatting.plain(trigger.group(2) or '') scheme = trigger.group(1).lower() if not text: try: msg = SCHEME_ERRORS[scheme] except KeyError: msg = "How did you do that?!" bot.reply(msg) return try: colors = COLOR_SCHEMES[scheme] except KeyError: # not possible to reach this at time of writing, but who knows? # mistakes happen when updating stuff that needs to be changed in # parallel bot.reply( "I don't know what color sequence to use for '{}'!".format(scheme)) return color_cycle = itertools.cycle(colors) bot.say(''.join(char if unicodedata.category(char) == 'Zs' else formatting.color(char, next(color_cycle)) for char in text), max_messages=4)
def handle_quiz(bot, trigger): if not bot.memory['quiz']: return quiz = bot.memory['quiz'] if quiz.question.attempt(trigger.args[1]) and not quiz.question.answered: quiz.question.answered = True bot.say(color('Correct! The answer was {}'.format(quiz.question.answer), colors.GREEN)) quiz.award_user(trigger.nick, quiz.question.value if bot.config.quiz.win_method == 'score' else 1) score = bot.memory['quiz'].get_scores()[trigger.nick] bot.say('{} has {} point{}!'.format(trigger.nick, score, 's' * (score > 1))) if bot.config.quiz.win_method == 'points': win_value = bot.config.quiz.points_to_win else: win_value = bot.config.quiz.score_to_win if score >= win_value: bot.say('{} is the winner!'.format(trigger.nick)) qscores(bot) db = SopelDB(bot.config) db_users = bot.config.quiz.db_users if not db_users or quiz.starter in db_users: wins = (db.get_nick_value(trigger.nick, 'quiz_wins') or 0) + 1 db.set_nick_value(trigger.nick, 'quiz_wins', wins) bot.say('{} has won {} time{}'.format(trigger.nick, wins, 's' * (wins > 1))) bot.memory['quiz'] = None return next_q(bot)
def send_message(bot, channel, message): uuid = message["uuid"] if uuid == "system": name = "*" colors = (Common.action_color, None) else: user = requests.get(bot.config.habitica.api_url + "members/" + uuid, headers=Common.auth) if user.status_code == 200: name = Common.name_prefix + user.json()["profile"]["name"] + Common.name_suffix colors = get_name_colors(user.json()) else: name = Common.name_prefix + message["user"] + Common.name_suffix colors = Common.default_colors text = parse_code_tags(bot, message["text"]) bot.msg( channel, color(name, colors[0], colors[1]) + " " + text, max_messages=bot.config.habitica.max_lines ) # manual rate limiting, otherwise multi-line messages might be broken up due to bot's scheduling sleep(len(text) / 400.0)
def checkiday(bot, trigger): r = requests.get('https://www.checkiday.com/rss.php?tz=Europe/London') days = re.findall(r'<title>(.*?)</title>', r.text)[1:] colors = cycle(random.sample([2, 3, 4, 6, 7, 14, 15], 7)) cdays = [color(i, j) + u'\x0f' for i, j in zip(days, colors)] out = 'Today is {}'.format(', '.join(cdays)) bot.say(out, max_messages=10)
def get_decorated_team_name(team: Team) -> str: team_name = '{color} team'.format(color=team.color.capitalize()) if team is Team.red: irc_color = irc_format.colors.RED else: irc_color = irc_format.colors.LIGHT_BLUE decorated_name = irc_format.bold(irc_format.color(team_name, irc_color)) return decorated_name
def url_handler(bot: SopelWrapper, trigger: Trigger): """Checks for malicious URLs.""" mode = bot.db.get_channel_value( trigger.sender, "safety", bot.settings.safety.default_mode, ) if mode == "off": return local_only = "local" in mode or bot.settings.safety.vt_api_key is None strict = "strict" in mode for url in tools.web.search_urls(trigger): safe_url = safeify_url(url) positives = 0 # Number of engines saying it's malicious total = 0 # Number of total engines try: hostname = urlparse(url).hostname.lower() except ValueError: pass # Invalid address else: if any(regex.search(hostname) for regex in known_good): continue # explicitly trusted if hostname in bot.memory[SAFETY_CACHE_LOCAL_KEY]: LOGGER.debug("[local] domain in blocklist: %r", hostname) positives += 1 total += 1 result = virustotal_lookup(bot, url, local_only=local_only) if result: positives += result["positives"] total += result["total"] if positives >= 1: # Possibly malicious URL detected! LOGGER.info( "Possibly malicious link (%s/%s) posted in %s by %s: %r", positives, total, trigger.sender, trigger.nick, safe_url, ) bot.say( "{} {} of {} engine{} flagged a link {} posted as malicious". format( bold(color("WARNING:", colors.RED)), positives, total, "" if total == 1 else "s", bold(trigger.nick), )) if strict: bot.kick(trigger.nick, trigger.sender, "Posted a malicious link")
def nodeinfo(bot, trigger): search_queries = [n for n in trigger.args[1].split(' ')[1:] if len(n) > 0] if len(search_queries) is 0: bot.msg(trigger.sender, "Usage: .nodeinfo [nodename]") for node in search_queries[:2]: possible_nodes = find_node(bot, node) if possible_nodes is None: bot.msg(trigger.sender, "No Data yet") break elif len(possible_nodes) is 0: bot.msg(trigger.sender, "No node with Name {}".format(node)) elif len(possible_nodes) is 1: node = possible_nodes[0] online = node['flags']['online'] time = datetime.strptime(node['lastseen'], '%Y-%m-%dT%H:%M:%S%z') nodename = bold(color(node['hostname'], colors.RED)) if online: nodename = bold(color(node['hostname'], colors.GREEN)) timezone = time.tzinfo time = datetime.now() - timedelta(seconds=node['statistics']['uptime']) time = time.replace(tzinfo=timezone) addr = node['network'].get('addresses', None) if not addr: addr = 'N/A' else: addr = "http://[{}]".format(sorted(addr)[0]) bot.msg(trigger.sender, "{}: {} - {} - {}({})".format(nodename, format_time(time), node['model'], node['software']['firmware']['release'], node['software']['firmware']['base'])) if online: bot.msg(trigger.sender, "Load: {} - Memory: {} - Filesystem: {} - {}".format( color_percentage(int(round(node['statistics'].get('loadavg', 0) * 100))), color_percentage(round(node['statistics'].get('memory_usage', 0) * 100, 2)), color_percentage(round(node['statistics'].get('rootfs_usage', 0) * 100, 2)), addr)) elif len(possible_nodes) > 1: max_full_hostnames = 3 msg_string = ", ".join(map(lambda x: x['hostname'], possible_nodes[:max_full_hostnames])) if(len(possible_nodes) > max_full_hostnames): msg_string = msg_string + " and {} more".format(len(possible_nodes)-max_full_hostnames) bot.msg(trigger.sender, "More than one node containing '{}': {}".format(node, msg_string))
def gelbooru_url(bot, trigger): soup = get_soup('http://gelbooru.com/index.php?page=dapi&s=post&q=index&id={0}'.format(trigger.group(1))) posts = soup.find_all('post') post = posts[0] post_id, score, url, rating, tags = (post.get('id'), post.get('score'), post.get('file_url'), post.get('rating'), post.get('tags')) if 'e' in rating: rating = color('NSFW', colors.RED) elif 'q' in rating: rating = color('Questionable', colors.YELLOW) elif 's' in rating: rating = color('Safe', colors.GREEN) bot.say('[gelbooru] Score: {0} | Rating: {1} | Tags: {2}'.format(score, rating, tags.strip()))
def show_status(bot, trigger): api_user = bot.db.get_nick_value(trigger.nick, 'habitica_api_user') api_key = bot.db.get_nick_value(trigger.nick, 'habitica_api_key') if api_user is None: bot.reply("I do not know you, sorry. Please use '.hero add'.") return else: if api_key is None: user = requests.get(bot.config.habitica.api_url + "members/" + api_user, headers=Common.auth) else: headers = {"x-api-key": api_key, "x-api-user": api_user} user = requests.get(bot.config.habitica.api_url + "user", headers=headers) if user.status_code != 200: bot.say("No connection to Habitica. Please try again later.") return hp = str(round(user.json()["stats"]["hp"], 2)) mp = str(int(user.json()["stats"]["mp"])) gp = str(round(user.json()["stats"]["gp"], 2)) xp = str(int(user.json()["stats"]["exp"])) name = user.json()["profile"]["name"] name_colors = get_name_colors(user.json()) if api_key is not None: max_hp = user.json()["stats"]["maxHealth"] max_mp = user.json()["stats"]["maxMP"] to_next_level = user.json()["stats"]["toNextLevel"] hp = hp + "/" + str(max_hp) mp = mp + "/" + str(max_mp) xp = xp + "/" + str(to_next_level) seperator = " | " bot.say("Status for " + color(Common.name_prefix + name + Common.name_suffix, name_colors[0], name_colors[1]) + " " + color(bold(u"♥ ") + hp + " HP", Common.hp_color) + seperator + color(bold(u"⚡ ") + mp + " MP", Common.mp_color) + seperator + color(bold(u"⭐ ") + xp + " XP", Common.xp_color) + seperator + color(bold(u"⛁ ") + gp + " Gold", Common.gp_color) )
def decorate_word(word: str, card_type: CardType) -> str: text_color = card_type_color(card_type) if card_type == CardType.assassin: bg_color = irc_format.colors.BLACK else: bg_color = None decorated_word = irc_format.color(word, text_color, bg_color) if word == REVEALED_CARD_TOKEN: decorated_word = irc_format.bold(decorated_word) return decorated_word
def rainbow(bot, trigger): text = trigger.group(2) if not text: text = 'rainbow' rainbow = [4, 7, 8, 3, 12, 2, 6] out = '' for c in text: out += color(c, rainbow[0]) rainbow = rotate(rainbow, 1) bot.say(out)
def format_rescue(rescue): cr = color("(CR)", colors.RED) if rescue.codeRed else '' id = "" if show_ids: id = "@" + (rescue.id if rescue.id is not None else "none") return "[{boardindex}{id}]{client}{cr}".format( boardindex=rescue.boardindex, id=id, client=getattr(rescue, attr), cr=cr )
def _say_result(bot, trigger, id_, include_link=True): result = API.videos().list( id=id_, part='snippet,contentDetails,statistics', ).execute().get('items') if not result: return result = result[0] message = ( '[You' + color('Tube', colors.WHITE, colors.RED) + '] ' '{title} | Uploader: {uploader} | Uploaded: {uploaded} | ' 'Length: {length} | Views: {views:,} | Comments: {comments}' ) snippet = result['snippet'] details = result['contentDetails'] statistics = result['statistics'] duration = _parse_duration(details['duration']) uploaded = _parse_published_at(bot, trigger, snippet['publishedAt']) comments = statistics.get('commentCount', '-') if comments != '-': comments = '{:,}'.format(int(comments)) message = message.format( title=snippet['title'], uploader=snippet['channelTitle'], length=duration, uploaded=uploaded, views=int(statistics['viewCount']), comments=comments, ) if 'likeCount' in statistics: likes = int(statistics['likeCount']) message += ' | ' + color('{:,}+'.format(likes), colors.GREEN) if 'dislikeCount' in statistics: dislikes = int(statistics['dislikeCount']) message += ' | ' + color('{:,}-'.format(dislikes), colors.RED) if include_link: message = message + ' | Link: https://youtu.be/' + id_ bot.say(message)
def get_post(self): for submission in r.get_subreddit(self.subreddit).get_hot(limit=25): if str(submission.over_18) == 'True': nsfwtag = str("[" + bold(color('NSFW', colors.RED))+ "] ") else: nsfwtag = '' fullthingred = (str(nsfwtag) + str('[' + str(submission.score) + '] ' + (submission.title)) + " - " + str(submission.url + " (" + self.subreddit + ")")) self.posts.append('%s /// %s' % (fullthingred, submission.permalink)) self.chosen_post = random.choice(self.posts) self.chosen_post = self.chosen_post.split('///') self.post_title = (self.chosen_post[0]) self.post_comments = (self.chosen_post[1])
def redditor_info(bot, trigger, match, commanded=False): """Shows information about the given Redditor""" try: u = bot.memory['reddit_praw'].redditor(match) message = '[REDDITOR] ' + u.name now = dt.datetime.utcnow() cakeday_start = dt.datetime.utcfromtimestamp(u.created_utc) cakeday_start = cakeday_start.replace(year=now.year) day = dt.timedelta(days=1) year_div_by_400 = now.year % 400 == 0 year_div_by_100 = now.year % 100 == 0 year_div_by_4 = now.year % 4 == 0 is_leap = year_div_by_400 or ((not year_div_by_100) and year_div_by_4) if (not is_leap) and ((cakeday_start.month, cakeday_start.day) == (2, 29)): # If cake day is 2/29 and it's not a leap year, cake day is 3/1. # Cake day begins at exact account creation time. is_cakeday = cakeday_start + day <= now <= cakeday_start + (2 * day) else: is_cakeday = cakeday_start <= now <= cakeday_start + day if is_cakeday: message = message + ' | ' + bold( color('Cake day', colors.LIGHT_PURPLE)) if commanded: message = message + ' | https://reddit.com/u/' + u.name if u.is_gold: message = message + ' | ' + bold(color('Gold', colors.YELLOW)) if u.is_mod: message = message + ' | ' + bold(color('Mod', colors.GREEN)) message = message + (' | Link: ' + str(u.link_karma) + ' | Comment: ' + str(u.comment_karma)) bot.say(message) except prawcore.exceptions.NotFound: if commanded: bot.say('No such Redditor.') # Fail silently if it wasn't an explicit command. return NOLIMIT
def getDifference(data, bot, ticker): # Fetch data for Sverige30 r = requests.get(ig_url + '/markets/' + ticker, headers=data) # Extract bid/offer ig_bid = float(r.json()['snapshot']['bid']) ig_offer = float(r.json()['snapshot']['offer']) ig_mid = float((ig_offer+ig_bid)/2) # Get latest close from Yahoo Finance r = requests.get('http://download.finance.yahoo.com/d/quotes.csv?s=^OMX&f=l1') omx_close = float(r.text[:7]) # Calculate results difference = ig_mid - omx_close difference_pct = (ig_mid - omx_close) / omx_close * 100 if debug: print difference_pct # Print difference out = "OMXS30 at " + str(omx_close) + ". " out += "IG at " + str(ig_mid) + " (" if difference_pct >= 0: out += formatting.color('+' + str(difference_pct)[:4] + '%', formatting.colors.GREEN) else: out += formatting.color(str(difference_pct)[:5] + '%', formatting.colors.RED) out += ' / ' if difference >= 0: out += formatting.color('+' + str(difference)[:4] + 'p', formatting.colors.GREEN) else: out += formatting.color(str(difference)[:5] + 'p', formatting.colors.RED) out += ')' output(bot, out) return
def _say_result(bot, id_, include_link): result = API.videos().list( id=id_, part='snippet,contentDetails,statistics', ).execute().get('items') if not result: return result = result[0] message = ( '[YouTube] {title} | Uploader: {uploader} | Duration: {duration} | ' 'Views: {views} | {likes} | {dislikes}' ) snippet = result['snippet'] details = result['contentDetails'] splitdur = ISO8601_PERIOD_REGEX.match(details['duration']) dur = [] for k, v in splitdur.groupdict().items(): if v is not None: dur.append(v.lower()) duration = ' '.join(dur) for k in result['statistics']: result['statistics'][k] = '{:,}'.format(int(result['statistics'][k])) message = message.format( title=bold(snippet['title']), uploader=snippet['channelTitle'], duration=duration, views=result['statistics']['viewCount'], likes=color(result['statistics']['likeCount'], colors.GREEN), dislikes=color(result['statistics']['dislikeCount'], colors.RED), ) if include_link: message += ' | ' + color('https://youtu.be/{0}' .format(id_), colors.BLUE) bot.say(message)
def query_jira(jira_id): url = jboss_org_rest + jira_id response = requests.get(url, headers=headers, verify=False) response = response.json() if "fields" in response: return "[{0}] {1} - {2}".format( jira_id, response["fields"]["summary"], color( jboss_org_case.replace(jboss_org_base_url, jboss_org_base_url_dns) + jira_id, colors.GREY)) else: return "Sorry but I couldn't fetch the URL"
def ud_search(bot, trigger): query = trigger.group(2).strip() url = 'http://api.urbandictionary.com/v0/define?term=%s' % (query.encode('utf-8')) #bot.say(url) try: response = web.get_urllib_object(url, 20) except UnicodeError: bot.say('[UrbanDictionary] ENGLISH, DO YOU SPEAK IT?') return else: data = json.loads(response.read()) #bot.say(str(data)) try: definition = data['list'][0]['definition'].replace('\n', ' ') except KeyError: bot.say('[UrbanDictionary] Something went wrong bruh') except IndexError: bot.say('[UrbanDictionary] No results, do you even spell bruh?') else: thumbsup = color(str(data['list'][0]['thumbs_up']) + '+', u'03') thumbsdown = color(str(data['list'][0]['thumbs_down']) + '-', u'04') permalink = data['list'][0]['permalink'] length = len(thumbsup) + len(thumbsdown) + len(permalink) + 35 ellipsies = '' if (len(definition) + length) > 445: ellipsies = '...' udoutput = "[UrbanDictionary] %s; %.*s%s | %s >> %s %s" % (query, 445 - length, definition, ellipsies, permalink, thumbsup, thumbsdown) if "spam spam" not in udoutput: if not trigger.sender.is_nick() and bot.privileges[trigger.sender][trigger.nick] < VOICE: bot.notice(udoutput, recipient=trigger.nick) else: bot.say(udoutput) else: if not trigger.sender.is_nick() and bot.privileges[trigger.sender][trigger.nick] < VOICE: bot.notice('[UrbanDictionary] Negative ghostrider', recipient=trigger.nick) else: bot.say('[UrbanDictionary] Negative ghostrider')
def ytinfo(bot, trigger, found_match=None): """ Get information about the given youtube video """ match = found_match or trigger uri = 'https://www.googleapis.com/youtube/v3/videos?id={0}&part=contentDetails,snippet,statistics'.format( match.group(2)) video_info = ytget(bot, trigger, uri) if video_info is None: return title = video_info['snippet']['title'] uploader = video_info['snippet']['channelTitle'] duration = video_info['contentDetails']['duration'] views = video_info['statistics']['viewCount'] likes = video_info['statistics']['likeCount'] dislikes = video_info['statistics']['dislikeCount'] message = '[YouTube] {0} | Duration: {1} | Views: {2} | Uploader: {3} | {4} | {5}'.format( bold(title), duration, views, uploader, color(likes, colors.GREEN), color(dislikes, colors.RED)) bot.say(message)
def status(bot, trigger): blacklist = bot.config.steamstatus.blacklist json = get_info(bot) result = [] for name, details in json['services'].items(): if name not in blacklist and name in service_translations: name = service_translations[name] status = details['status'] title = details['title'] if status == 'good': status = formatting.color(title, "GREEN") else: status = formatting.color(title, "RED") i = "{0:<30} {1:>30}".format(name, status) result.append(i) result.sort() for line in result: bot.say(line)
def add_player(self, player): if len(self.players) > 1: self.bot.say('There is already an active game') return if self.players[1] == player: self.bot.say('You\'re already playing...') return self.players[2] = player self.bot.say('Game started between {} and {}'.format(*self.players.values())) self.print_board() self.bot.say(color('{}\'s go!'.format(self.players[1]), self.colours[1])) self.bot.say('(.connect4 COLUMN_NUMBER to play)')
def image(link_id, bot): """ Handles information retrieval for non-gallery images. The bot will output the title, the type (image/gif) and the number of views of the selected image. """ client = ImgurClient(bot.config.imgur.client_id) api_response = client.resource('image', link_id) img = api_response['data'] # print(img) if img['title']: title = img['title'] if not img['title'] and img['description']: title = img['description'] if not img['title'] and not img['description']: title = 'untitled' # pprint.pprint(img) is_nsfw = "{}".format( color(" [NSFW] ", colors.RED) if img. get('nsfw') else color(" [SFW] ", colors.GREEN)) if img['animated']: return bot.say('\x02[imgur]\x02{2}{0} - a gif with {1:,} view{5}{3}{4}'.format(title, \ img['views'], is_nsfw, parse_date(img['datetime']), parse_size(img['width'], img['height'], img['size'], img['type']), 's' if (img['views'] > 1 or img['views'] == 0) else '', )) else: return bot.say('\x02[imgur]\x02{2}{0} - {1:,} view{5}{3}{4}'.format(title, \ img['views'], is_nsfw, parse_date(img['datetime']), parse_size(img['width'], img['height'], img['size'], img['type']), 's' if (img['views'] > 1 or img['views'] == 0) else '', ))
def start(self, bot, trigger): if len(self.games) > 0: bot.say("I'm already hosting an acro game!") return bot.notice( f"New acro game started by {trigger.nick}! Have fun and good luck!", trigger.sender) time.sleep(1) self.games[trigger.sender] = AcroGame(trigger) game = self.games[trigger.sender] instructions = bold(color(f"/msg {bot.nick} <answer>", colors.GREEN)) # game loop while (game.active is True): game.gameMode = 'SUBMITTING' bot.say(f"Points needed to win this game: {game.scoreNeeded}") bot.say( f"Submit an acro by messaging me. {instructions} is how you do it!" ) time.sleep(2) bot.say("You have 60 seconds to come up with your best acro! GO!") game.generateAcro(bot, trigger) time.sleep(45) bot.say( bold(color("HURRY THE F**K UP! 15 SECONDS LEFT!", colors.RED))) time.sleep(15) game.gameMode = 'PREVOTE' if game.displayAcros(bot) == False: continue game.gameMode = 'SCORING' if game.displayVotes(bot) == False: continue time.sleep(8) del self.games[trigger.sender]
def displayAcros(self, bot): if len(self.submittedAcros) < 3: self.badRounds += 1 if self.badRounds > 2: bot.say( "We need at least 3 players to play acro. Stopping the game now." ) self.active = False return False else: bot.say( "We need at least 3 players to play acro. Restarting the round..." ) return False self.badRounds = 0 self.voterLog = [] bot.say("Ok, Acro submission time is over. Its time to VOTE:") for username, info in self.submittedAcros.items(): acroID = bold(color(str(info['acroID']), colors.RED)) acro = color(' ' + info['acro'] + ' ', colors.ORANGE, colors.BLACK) bot.say(f"[{acroID}] {acro}") time.sleep(2) vote_instructions = bold(color(f"/msg {bot.nick} #", colors.GREEN)) bot.say( f"Ok, you have 30 seconds to vote for your favorite acro! Type {vote_instructions} to vote now!" ) self.gameMode = 'VOTING' voteEndTime = time.time() + 30 while (self.gameMode == 'VOTING'): if self.voteCount == len( self.submittedAcros) or time.time() > voteEndTime: self.gameMode = 'NONE' bot.say("Voting is over!")