async def end_giveaway(self, giveaway): registered = self.in_progress[giveaway.server.id] del self.in_progress[giveaway.server.id] if len(registered) == 0: await self.send_message( giveaway.server.default_channel, 'No one registered for the giveaway 😢\nNo one wins' ) else: winner = choice(list(registered)) await self.send_message( giveaway.server.default_channel, '{} You are the giveaway winner!\n' 'I will whisper you your prize shortly' .format(winner.mention) ) await self.send_message( winner, 'You won the giveaway of {} on `{}`\n' 'Here is your prize:\n' '{}' .format( giveaway.user.mention, giveaway.server.name, f.code_block(giveaway.content) ) )
async def twitter_three_legged_action(self, tweet, channel, user, action, description): oauth_user = self.get_user_oauth(user) if oauth_user is None: await self.inform_user_about_connections(user) return user_api = self.get_user_api(oauth_user) try: action(user_api, tweet) except Exception as e: await self.send_message( user, 'I couldn\'t {} `{}`\'s tweet for you\n' 'Twitter said:\n{}' .format( description, tweet['user']['screen_name'], f.code_block(str(e.response_data)) ) ) else: await self.send_message( channel, '{} I {} `{}`\'s tweet for you 👍' .format( user.mention, PAST_FORMS[description], tweet['user']['screen_name'] ), delete_after = 5 )
async def plugin_help(self, message, plugin_name): plugin_name = plugin_name.lower() if plugin_name not in self.enabled_plugins_names: return plugin = self.get_plugin(plugin_name) def hooks_description(hooks): if hooks: hook_descriptions = (hook.__doc__.strip() for hook in hooks if hook.__doc__) return '/* {} */'.format(' | '.join(hook_descriptions)) return '' raw_components = [ '{}{}'.format(validator.parser.name, hooks_description(validator.hooks)) for validator, _ in plugin.actions ] components = sorted( re.sub(' +', ' ', re.sub(r'[(,)]', '', name)).split(' ') for name in raw_components) lines = [' '.join(comp) for comp in components] help_message = f.code_block(lines, language='css') await self.send_message(message.channel, '{} `{}` plugin commands:\n\n{}'.format( message.author.mention, plugin_name, help_message), delete_after=30)
async def stats_games(self, message, user_id): member = message.server.get_member(str(user_id)) if member is None: return # Flush current tracking self.update_game(member.id, member.game) games = self.top_user_games(user_id) top = [(game.name, game.duration) for game in games[:10]] if games: since = min(map(lambda g: g.created_at, games)) since_days = int((time() - since.timestamp()) / (3600 * 24)) response = ( '{} has played **{}** different games in the last **{}** days ' 'for a total of **{}** seconds\ntop 10:\n{}').format( f.mention(user_id), len(games), since_days, sum(map(lambda g: g.duration, games)), f.code_block(f.format_sql_rows(top))) else: response = '{} has not played any games yet'.format( f.mention(user_id)) await self.send_message(message.channel, response, delete_after=25)
async def stats_games(self, message, user_id): member = message.server.get_member(str(user_id)) if member is None: return # Flush current tracking self.update_game(member.id, member.game) games = self.top_user_games(user_id) top = [(game.name, game.duration) for game in games[:10]] if games: since = min(map(lambda g: g.created_at, games)) since_days = int((time() - since.timestamp()) / (3600 * 24)) response = ( '{} has played **{}** different games in the last **{}** days ' 'for a total of **{}** seconds\ntop 10:\n{}' ).format( f.mention(user_id), len(games), since_days, sum(map(lambda g: g.duration, games)), f.code_block(f.format_sql_rows(top)) ) else: response = '{} has not played any games yet'.format(f.mention(user_id)) await self.send_message( message.channel, response, delete_after = 25 )
async def plugin_help(self, message, plugin_name): plugin_name = plugin_name.lower() if plugin_name not in self.enabled_plugins_names: return plugin = self.get_plugin(plugin_name) raw_components = [ '{}{}'.format( validator.parser.name, ' /* master only */' if validator.pre_hook == master_only else '') for validator, _ in plugin.actions ] components = sorted( re.sub(' +', ' ', re.sub(r'[(,)]', '', name)).split(' ') for name in raw_components) lines = [' '.join(comp) for comp in components] help_message = f.code_block(lines, language='css') await self.send_message(message.channel, '{} `{}` plugin commands:\n\n{}'.format( message.author.mention, plugin_name, help_message), delete_after=30)
async def stats_games_top(self, message, count=10): data = self.top_games(message.server, count) if data: await self.send_message( message.channel, 'Most **{}** games played on this server\n{}'.format( len(data), f.code_block(f.format_sql_rows(data))), delete_after=25)
async def general_help(self, message): help_message = f.code_block( ['!help {}'.format(name) for name in self.enabled_plugins_names], language='css' # Kinda look ok ) await self.send_message(message.channel, '{}\n{}'.format(message.author.mention, help_message), delete_after=30)
async def stats_games_top(self, message, count=10): data = self.top_games(message.server, count) if data: await self.send_message( message.channel, 'Most **{}** games played on this server\n{}' .format(len(data), f.code_block(f.format_sql_rows(data))), delete_after = 25 )
async def eval_env_list(self, message): environments = [ env.name for env in self.get_environments(message.author.id) if env.author_id ] await self.send_message( message.channel, '{} You have `{}` saved environments\n{}'.format( message.author.mention, len(environments), f.code_block(environments)))
async def channels(self, message): channels = [ (channel.name, channel.id) for channel in message.server.channels ] await self.send_message( message.channel, f.code_block(f.format_sql_rows(channels)), delete_after = 30 )
async def roll_dice_command(self, message, dice): grouped_dice = group_dice(dice) enforce_dnd_invariants(grouped_dice) results = map(roll_die, grouped_dice) response = ('{} 🎲 rolling your dice\n' '{}'.format(message.author.mention, f.code_block('\n'.join(results)))) await self.send_message(message.channel, response, delete_after=30)
async def twitch_top_channels(self, message, count=10): streams = await self.api.top_channels(count) info = [(stream.channel.display_name, '🕹 {}'.format(stream.game), '👀 {:,}'.format(stream.viewers), stream.channel.status) for stream in streams] await self.send_message(message.channel, 'Top {} games on Twitch right now\n{}'.format( len(streams), f.code_block(f.pad_rows(info, ' | '))), delete_after=15)
async def twitch_top_games(self, message, count=10): top_games = await self.api.top_games(count) info = [(top_game.game.name, '📺 {:,}'.format(top_game.channels), '👀 {:,}'.format(top_game.viewers)) for top_game in top_games] await self.send_message(message.channel, 'Top {} games on Twitch right now\n{}'.format( len(top_games), f.code_block(f.pad_rows(info, ' | '))), delete_after=15)
async def logs_find(self, message, user_id, what, count=10): with self.transaction() as trans: trans.execute( q.find_logs, dict(author_id=user_id, str='%%{}%%'.format(what), limit=count)) results = trans.fetchall() messages = [r[0] for r in results] await self.send_message(message.channel, 'Found **{}** messages\n{}'.format( len(results), f.code_block(messages)), delete_after=30)
async def eval_env_map(self, message): environments = self.get_environments(message.author.id) padding = max(map(lambda env: len(env.language), environments), default=0) mapping = [ '{:{}} ➡ {}'.format(env.language, padding, env.name) for env in environments ] await self.send_message( message.channel, '{} Here is your eval mapping\n{}'.format(message.author.mention, f.code_block(mapping)))
async def monitored(self, message): with self.transaction() as trans: trans.execute(q.get_monitored) monitored = [MonitoredChannel(*row) for row in trans.fetchall()] user_futures = (self.get_user_by_id(channel.user_id) for channel in monitored if str(channel.server_id) == message.server.id) users = await asyncio.gather(*user_futures) await self.send_message( message.channel, 'I\'m currently monitoring the following channels:\n{}'.format( f.code_block(user['screen_name'] for user in users)))
async def general_help(self, message): help_message = f.code_block( [ '!help {}'.format(name) for name in self.enabled_plugins_names ], language='css' # Kinda look ok ) await self.send_message( message.channel, '{}\n{}'.format(message.author.mention, help_message), delete_after=30 )
async def deleted_messages(self, message, user_id, count=5): with self.transaction() as trans: trans.execute(q.last_deleted_logs, dict(author_id=user_id, limit=count)) results = trans.fetchall() messages = [ '{}{}'.format(row[0], ' '.join(row[1])) for row in results ] await self.send_message( message.channel, 'last **{}** deleted messages from <@{}>:\n{}'.format( len(results), user_id, f.code_block(messages)), delete_after=30)
async def monitored(self, message): with self.transaction() as trans: trans.execute(q.get_monitored) monitored = [MonitoredChannel(*row) for row in trans.fetchall()] channels = [ channel.name for channel in monitored if str(channel.server_id) == message.server.id ] await self.send_message( message.channel, 'I\'m currently monitoring the following channels:\n{}'.format( f.code_block(channels)), delete_after=15)
async def eval_env_list(self, message): environments = [ env.name for env in self.get_environments(message.author.id) if env.author_id ] await self.send_message( message.channel, '{} You have `{}` saved environments\n{}' .format( message.author.mention, len(environments), f.code_block(environments) ) )
async def sql_exec(self, message, snippet): if snippet.language.lower() != 'sql': return try: with self.transaction() as trans: trans.execute(snippet.code) rows = trans.fetchall() self.debug(rows) if rows: text = f.code_block(f.format_sql_rows(rows)) else: text = 'Request executed successfully\n`no output`' await self.send_message(message.channel, text) except Exception as e: await self.send_message(message.channel, '```\n{}\n```'.format(e))
async def logs_find(self, message, user_id, what, count=10): with self.transaction() as trans: trans.execute(q.find_logs, dict( author_id = user_id, str = '%%{}%%'.format(what), limit = count )) results = trans.fetchall() messages = [r[0] for r in results] await self.send_message( message.channel, 'Found **{}** messages\n{}' .format(len(results), f.code_block(messages)), delete_after = 30 )
async def twitch_top_games(self, message, count=10): top_games = await self.api.top_games(count) info = [ (top_game.game.name, '📺 {:,}'.format(top_game.channels), '👀 {:,}'.format(top_game.viewers)) for top_game in top_games ] await self.send_message( message.channel, 'Top {} games on Twitch right now\n{}' .format(len(top_games), f.code_block(f.pad_rows(info, ' | '))), delete_after=15 )
async def monitored(self, message): with self.transaction() as trans: trans.execute(q.get_monitored) monitored = [MonitoredChannel(*row) for row in trans.fetchall()] channels = [ channel.name for channel in monitored if str(channel.server_id) == message.server.id ] await self.send_message( message.channel, 'I\'m currently monitoring the following channels:\n{}' .format(f.code_block(channels)), delete_after=15 )
async def monitored(self, message): with self.transaction() as trans: trans.execute(q.get_monitored) monitored = [MonitoredChannel(*row) for row in trans.fetchall()] users = [ self.get_user_by_id(channel.user_id)['screen_name'] for channel in monitored if str(channel.server_id) == message.server.id ] await self.send_message( message.channel, 'I\'m currently monitoring the following channels:\n{}' .format(f.code_block(users)) )
async def eval_env_inspect(self, message, env_name): environments = self.get_environments(message.author.id) try: env = next(e for e in environments if e.name == env_name) except StopIteration: await self.send_message( message.channel, '{} You don\'t have any environment saved under the name `{}`'. format(message.author.mention, env_name), delete_after=10) await self.send_message( message.channel, '{} `{}` environment was built from:\n{}'.format( message.author.mention, env_name, f.code_block(env.dockerfile, language='dockerfile')))
async def permissions(self, message, channel_id=None): if channel_id is None: channel_id = message.channel.id channel = next( channel for channel in message.server.channels if channel.id == str(channel_id) ) perms = [' - {}'.format(perm) for perm in self.permissions_in(channel)] await self.send_message( message.channel, 'In {}, I can:\n{}' .format(f.channel(channel_id), f.code_block(perms)), delete_after = 30 )
async def eval_env_map(self, message): environments = self.get_environments(message.author.id) padding = max(map(lambda env: len(env.language), environments), default=0) mapping = [ '{:{}} ➡ {}'.format(env.language, padding, env.name) for env in environments ] await self.send_message( message.channel, '{} Here is your eval mapping\n{}' .format( message.author.mention, f.code_block(mapping) ) )
async def twitch_top_channels(self, message, count=10): streams = await self.api.top_channels(count) info = [ (stream.channel.display_name, '🕹 {}'.format(stream.game), '👀 {:,}'.format(stream.viewers), stream.channel.status) for stream in streams ] await self.send_message( message.channel, 'Top {} games on Twitch right now\n{}' .format(len(streams), f.code_block(f.pad_rows(info, ' | '))), delete_after=15 )
async def trivia_stats_all(self, message, topic=None): ranks = self.get_ranks(message.server.id, topic) ranks = ranks[:10] def user_name(u_id): user = self.bot.find_user(str(u_id)) return user.name if user else '???' leaderboard = '\n'.join( '#{:>2} {:<30} ({:>3} pts)'.format(i + 1, user_name(user_id), points) for i, (points, user_id) in enumerate(ranks)) for_string = '' if topic is None else ' for `{}`'.format(topic) await self.send_message( message.channel, 'Top {} on this server{}:\n{}'.format(len(ranks), for_string, f.code_block(leaderboard)))
async def deleted_messages(self, message, user_id, count=5): with self.transaction() as trans: trans.execute(q.last_deleted_logs, dict( author_id = user_id, limit = count )) results = trans.fetchall() messages = [ '{}{}'.format(row[0], ' '.join(row[1])) for row in results ] await self.send_message( message.channel, 'last **{}** deleted messages from <@{}>:\n{}' .format(len(results), user_id, f.code_block(messages)), delete_after = 30 )
def format_tweet(tweet): text = ('Last tweet from `@{screen_name}`:\n\n' '{text}\n' '**{retweets}** 🔄 **{favourites}** 👍').format( screen_name=tweet['user']['screen_name'], text=f.code_block(tweet['text']), retweets=tweet['retweet_count'], favourites=tweet['favorite_count']) try: entities = tweet['extended_entities']['media'] media_urls = [entity['media_url_https'] for entity in entities] text += ('\n\nMedia files attached in the tweet:\n{}'.format( '\n'.join(media_urls))) except: pass return text
def format_price(ticker, exchange): name, symbol = ticker['name'], ticker['symbol'] change_1h = float(ticker.get('percent_change_1h', 0)) change_24h = float(ticker.get('percent_change_24h', 0)) change_7d = float(ticker.get('percent_change_7d', 0)) exchanges = list() if exchange is not None: exchanges.append( (exchange.upper(), ticker['price_{}'.format(exchange.lower())])) exchanges.append(('USD', ticker['price_usd'])) if symbol != 'BTC': btc_price = float(ticker['price_btc']) btc_price_string = '{} (1 BTC ~= {:.3f} {})'.format( btc_price, 1 / btc_price, symbol) exchanges.append(('BTC', btc_price_string)) price_message = '\n'.join('{} :: {}'.format(exchange, value) for exchange, value in exchanges) changes = (change_1h, change_24h, change_7d) periods = ('hour', 'day', 'week') change_message = '\n'.join('{} {:<{}} % over the last {}'.format( '-' if change < 0 else '+', abs(change), max(map(lambda x: len(str(abs(x))), changes)), period) for change, period in zip(changes, periods)) reply_message = '{} ({})\n{}\n{}\n{}\n{}'.format( name, symbol, '=' * (len(name) + len(symbol) + 3), price_message, '_' * (len(name) + len(symbol) + 3), change_message) last_updated_stamp = int(ticker['last_updated']) time_diff = int(time()) - last_updated_stamp if time_diff < 60: last_updated = '{} second{} ago'.format(time_diff, 's' if time_diff != 1 else '') else: minute_diff = time_diff // 60 last_updated = '~{} minute{} ago'.format( minute_diff, 's' if minute_diff != 1 else '') return ('{}\n*last updated: {}*'.format( f.code_block(reply_message, language='asciidoc'), last_updated))
async def end_giveaway(self, giveaway): registered = self.in_progress[giveaway.server.id] del self.in_progress[giveaway.server.id] if len(registered) == 0: await self.send_message( giveaway.server.default_channel, 'No one registered for the giveaway 😢\nNo one wins') else: winner = choice(list(registered)) await self.send_message( giveaway.server.default_channel, '{} You are the giveaway winner!\n' 'I will whisper you your prize shortly'.format(winner.mention)) await self.send_message( winner, 'You won the giveaway of {} on `{}`\n' 'Here is your prize:\n' '{}'.format(giveaway.user.mention, giveaway.server.name, f.code_block(giveaway.content)))
async def roll_dice_command(self, message, dice): grouped_dice = group_dice(dice) enforce_dnd_invariants(grouped_dice) results = map(roll_die, grouped_dice) response = ( '{} 🎲 rolling your dice\n' '{}' .format( message.author.mention, f.code_block('\n'.join(results)) ) ) await self.send_message( message.channel, response, delete_after = 30 )
def format_tweet(tweet): time_difference = datetime.now() - tweet_time(tweet) screen_name = tweet['user']['screen_name'] text = ( 'Last tweet from `@{screen_name}` ({ago}):\n\n' '{text}\n' '🔄 **{retweets}** ❤ **{favourites}**\n\n' '**__source__: {tweet_link}**\n\n' '*Click on the reactions below to retweet or like the tweet*' ).format( screen_name = screen_name, text = f.code_block(tweet['text']), retweets = tweet['retweet_count'], favourites = tweet['favorite_count'], ago = naturaltime(time_difference), tweet_link = 'https://twitter.com/{}/status/{}'.format(screen_name, tweet['id']) ) return text
async def plugin_help(self, message, plugin_name): plugin_name = plugin_name.lower() if plugin_name not in self.enabled_plugins_names: return plugin = self.get_plugin(plugin_name) def hooks_description(hooks): if hooks: hook_descriptions = ( hook.__doc__.strip() for hook in hooks if hook.__doc__ ) return '/* {} */'.format(' | '.join(hook_descriptions)) return '' raw_components =[ '{}{}'.format( validator.parser.name, hooks_description(validator.hooks) ) for validator, _ in plugin.actions ] components = sorted( re.sub(' +',' ', re.sub(r'[(,)]', '', name)).split(' ') for name in raw_components ) lines = [ ' '.join(comp) for comp in components ] help_message = f.code_block(lines, language='css') await self.send_message( message.channel, '{} `{}` plugin commands:\n\n{}' .format(message.author.mention, plugin_name, help_message), delete_after=30 )
async def convert(self, message, unit_values): converted = [(uv, system_convert(uv)) for uv in unit_values] output = ['{} = {}'.format(uv, conv) for uv, conv in converted] for t, uvs in groupby(converted, key=lambda uvs: type(uvs[0].unit)): values = list(map(lambda x: x[0], uvs)) if len(values) >= 2: summed = sum_units(*values) converted_summed = system_convert(summed) output.append( '{} total: {} = {}' .format(t.__name__.lower(), summed, converted_summed) ) await self.send_message( message.channel, 'Converted units\n{}' .format(f.code_block(output)), delete_after = 60 )
async def eval_env_inspect(self, message, env_name): environments = self.get_environments(message.author.id) try: env = next(e for e in environments if e.name == env_name) except StopIteration: await self.send_message( message.channel, '{} You don\'t have any environment saved under the name `{}`' .format(message.author.mention, env_name), delete_after=10 ) await self.send_message( message.channel, '{} `{}` environment was built from:\n{}' .format( message.author.mention, env_name, f.code_block(env.dockerfile, language='dockerfile') ) )
async def twitter_three_legged_action(self, tweet, channel, user, action, description): oauth_user = self.get_user_oauth(user) if oauth_user is None: await self.inform_user_about_connections(user) return user_api = self.get_user_api(oauth_user) try: action(user_api, tweet) except Exception as e: await self.send_message( user, 'I couldn\'t {} `{}`\'s tweet for you\n' 'Twitter said:\n{}'.format(description, tweet['user']['screen_name'], f.code_block(str(e.response_data)))) else: await self.send_message(channel, '{} I {} `{}`\'s tweet for you 👍'.format( user.mention, PAST_FORMS[description], tweet['user']['screen_name']), delete_after=5)
async def eval_langs(self, message): await self.send_message( message.channel, f.code_block('\n'.join( f'{lang: <10} -> {spec.image: <15} {spec.command("file.ext")}' for lang, spec in EVALSPEC_PER_LANGUAGES.items())))
async def send_update(): if logs: tail = ''.join(logs[-C.MAX_STREAM_LINES:]) await self.bot.edit_message(message, f.code_block(tail))