async def userstats(self, ctx, member: typing.Optional[discord.Member] = None, **flags): if member is None: member = ctx.author clauses = [] role_filter = flags.get('role').title() faction_filter = flags.get('faction').title() with self.bot.db.conn.cursor() as cur: clauses.append(cur.mogrify( 'player_id=%s', (str(member.id), )).decode('utf-8')) if role_filter != '': clauses.append(cur.mogrify( 'rolename=%s', (role_filter, )).decode('utf-8')) if faction_filter != '': clauses.append(cur.mogrify( 'faction=%s', (faction_filter, )).decode('utf-8')) clauses = ' AND '.join(clauses) query = ('SELECT result, COUNT(RESULT) FROM players' ' WHERE {} GROUP BY result ORDER BY result DESC;'.format(clauses)) cur.execute(query) results = cur.fetchall() wins = next((result[1] for result in results if result[0]), 0) losses = next((result[1] for result in results if not result[0]), 0) total = wins + losses if total == 0: return await ctx.send('No games played!') await ctx.send(f'Games: {total}\nWins: {wins}\nWinrate: {round(100 * wins/total)}%')
async def avatar(self, ctx, **flags): """Get your own, or another user's avatar""" target = await BetterUserConverter().convert(ctx, flags.get("target")) new_size = constrained_round(flags["size"]) formats = ["png", "jpeg", "webp", "jpg"] if f := flags.get("format"): main_format = f
async def snipe(self, ctx, **flags): """Shows the most recently deleted messages in a given channel""" # i know i shouldnt be using json for this channel = flags.get('channel') or ctx.channel with open('./json_files/snipes.json', 'r') as f: snipes = json.load(f) try: channel_snipes = snipes[str(channel.id)] except KeyError: return await ctx.send(f"{channel} has no deleted messages.") embeds = [] for snipe in reversed(channel_snipes[:flags.get('limit')]): author = self.bot.get_user(int( snipe['author'])) or await self.bot.fetch_user( int(snipe['author'])) embed = discord.Embed(colour=self.bot.colour) desc = snipe['content'] if not desc and snipe.get('embed'): desc = '`<Embedded Message>`' embed.description = desc since = dt.strptime(snipe['created_at'], '%Y-%m-%d %H:%M:%S.%f') embed.set_author(name=f"{author} said in {str(channel)}", icon_url=author.avatar_url) embed.timestamp = since embeds.append(embed) source = paginator.EmbedSource(embeds, footer=False) await paginator.CatchAllMenu(source).start(ctx)
async def hl_block(ctx, **flags): """Add or remove a user from your list of people who won't highlight you, or just view the list Use the --add flag to add a user, and use --remove to do the opposite""" if not flags.get('add') and not flags.get('remove'): if b := ctx.bot.user_cache[ctx.author.id]['hl_blocks']: blocked = [ctx.bot.get_user(i).__str__() for i in b] else: blocked = ["No blocked users"] await ctx.quick_menu(blocked, 10, delete_message_after=True) return
async def hl_whitelist(ctx, **flags): """Whitelist a guild for highlighting This will restrict highlights to only be allowed from guilds on the list""" if not flags.get("add") and not flags.get("remove"): if b := ctx.bot.user_cache[ctx.author.id]["hl_whitelist"]: whitelisted = [f"{ctx.bot.get_guild(i)} ({i})" for i in b] else: whitelisted = ["Highlight guild whitelist is empty"] await ctx.paginate(whitelisted, 10, delete_message_after=True) return
async def purge(self, ctx, amount: int, **flags): """Purges a given amount of messages.""" amount += 1 await ctx.message.delete() if user := flags.get('user'): await ctx.channel.purge(limit=amount, check=lambda msg: msg.author == user) return await ctx.send( f'{ctx.tick()} **{amount - 1}** messages by {user} have been purged', delete_after=3)
async def args_edit(self, ctx, **flags): """Edit the bot""" if pres := flags.get('presence'): if type_dict.get(pres[0]) is None: await self.bot.change_presence(status=ctx.me.status) elif type_dict.get(pres[0]) == 'streaming': pres.pop(0) await self.bot.change_presence(activity=discord.Streaming( name=' '.join(pres), url='https://www.twitch.tv/#')) else: await self.bot.change_presence(status=ctx.me.status, activity=discord.Activity( type=type_dict[pres.pop(0)], name=' '.join(pres)))
async def oldest_scores(ctx, **flags): level = flags.get("level") offset = 0 message = await ctx.send(embed=discord.Embed( title=f"Processing Data...", colour=discord.Colour(0x3586ff))) scores = get_oldest_scores_leaderboard(unbroken=flags["unbreaking"]) if level: scores = compute_oldest_ranks([ score for score in scores if score["level_short_name"] == str(level) ]) l = all_levels.getByShortName(str(level)) if l and flags["uploadhistory"]: data = { "any": l.leaderboard["any"]["top_history"], "unbroken": l.leaderboard["unbroken"]["top_history"], } with open("data/temp.temp", "w") as f: json.dump(data, f) with open("data/temp.temp", "rb") as f: await ctx.send( file=discord.File(f, filename=f"oldest_data_{level}.json")) now = time.time() await message.delete() pages = menus.MenuPages(source=OldestLeaderboardViewer( scores, offset, flags["unbreaking"], flags["mobile"]), clear_reactions_after=True) await pages.start(ctx)
async def weather(self, ctx, city, **flags): """ Shows the weather in your city. If you want the temperature to display in farenheit, add `-unit f` at the end of your command usage. If you want kelvin, add `-unit k` at the end. (Celsius is the default) """ try: async with self.http as http: data = await http.get( f"http://api.openweathermap.org/data/2.5/weather?appid={self.bot.config.weather}&q={city}") await http.close() if not str(unit := flags.get('unit') or 'c').startswith(('c', 'k', 'f')): return await ctx.send( f"**{unit}** is an invalid unit! Please make sure your unit starts with either **c**, **k** or **f**") embed = discord.Embed(colour=self.bot.colour) temperature = round(cyberformat.get_temperature(data['main']['temp'], unit), 1) feels_like = round(cyberformat.get_temperature(data['main']['feels_like'], unit), 1) embed.title = data['name'] weather = data['weather'][0] sunrise = dt.utcfromtimestamp(data['sys']['sunrise']).strftime("%I:%M %p") sunset = dt.utcfromtimestamp(data['sys']['sunset']).strftime("%I:%M %p") embed.description = f"**{weather['main'].title()}** - {weather['description'].capitalize()}\n" embed.description += f"<:temperature:742933558221340723> **{temperature}**° {unit[:1].capitalize()} (Feels Like **{feels_like}**° {unit[:1].capitalize()})\n" embed.description += f"☀️ Sunrise: **{sunrise}** UTC • Sunset: **{sunset}** UTC" embed.set_thumbnail(url="https://i.dlpng.com/static/png/6552264_preview.png") await ctx.send(embed=embed)
async def specs(self, ctx, user: Member = None, flags: flags.FlagParser(remove=bool) = flags.EmptyFlags): user = user if user else ctx.author uspecs = await self.bot.db.fetch('SELECT * FROM specs WHERE uid=$1;', user.id) if not uspecs: return await ctx.error( f'Specs not found for that user. Tell them to fill in this form\n<https://inv.wtf/sk1spec>' ) else: if isinstance(flags, dict) and flags.get( 'remove', False) and ctx.author.guild_permissions.manage_messages: con = await self.bot.db.acquire() async with con.transaction(): query = 'DELETE FROM specs WHERE uid=$1;' await self.bot.db.execute(query, user.id) await self.bot.db.release(con) await user.remove_roles( self.guild.get_role(595626786549792793), reason=f'Specs removed by {ctx.author}') return await ctx.success( f'Successfully removed specs for {user}') uspecs = uspecs[0] def escape(text: str): text = discord.utils.escape_markdown(text) text = re.sub(r'<a?:[a-zA-Z0-9\_]+:([0-9]+)>', '', text, 0, re.MULTILINE) return text embed = discord.Embed( color=user.color, timestamp=datetime.datetime.now( datetime.timezone.utc)).set_author( name=str(user), icon_url=user.avatar_url_as(static_format='png', size=2048), url=f'https://inv.wtf/sk1spec').add_field( name='» CPU', value=escape(uspecs['cpu'][:1024]), inline=False).add_field( name='» GPU', value=escape(uspecs['gpu'][:1024]), inline=False).add_field( name='» RAM', value=escape(uspecs['ram'][:1024]), inline=False).add_field( name='» Operating System', value=escape(uspecs['os'][:1024]), inline=False) return await ctx.send(embed=embed)
async def _dev_extensions(self, ctx, **flags): """Manage extensions""" async with ctx.loading(): mode_mapping = { "r": self.bot.reload_extension, "l": self.bot.load_extension, "u": self.bot.unload_extension, } if flags.get("pull"): await do_shell("git pull") mode = mode_mapping.get(flags["mode"]) extensions = (neo.conf["exts"] if flags["extension"][0] == "~" else flags["extension"]) for ext in extensions: mode(ext)
async def _dev_extensions(self, ctx, **flags): """Manage extensions""" async with ctx.loading(): mode_mapping = { 'r': self.bot.reload_extension, 'l': self.bot.load_extension, 'u': self.bot.unload_extension } if flags.get('pull'): await do_shell('git pull') mode = mode_mapping.get(flags['mode']) extensions = conf.get( 'exts') if flags['extension'][0] == '~' else flags['extension'] for ext in extensions: mode(ext)
await ctx.bot.user_cache.refresh() @flags.add_flag("-a", "--add", nargs="*") @flags.add_flag("-r", "--remove", nargs="*") @commands.command(name="whitelist", aliases=["wl"], cls=flags.FlagCommand) async def hl_whitelist(ctx, **flags): """Whitelist a guild for highlighting This will restrict highlights to only be allowed from guilds on the list""" if not flags.get("add") and not flags.get("remove"): if b := ctx.bot.user_cache[ctx.author.id]["hl_whitelist"]: whitelisted = [f"{ctx.bot.get_guild(i)} ({i})" for i in b] else: whitelisted = ["Highlight guild whitelist is empty"] await ctx.paginate(whitelisted, 10, delete_message_after=True) return strategy = "array_append" if flags.get("add") else "array_remove" snowflake = (flags.get("add") or flags.get("remove"))[0] async with ctx.loading(): await ctx.bot.pool.execute( f"UPDATE user_data SET hl_whitelist = {strategy}(hl_whitelist, $1) WHERE " "user_id=$2", int(snowflake), ctx.author.id, ) await ctx.bot.user_cache.refresh() @commands.command(name="remove", aliases=["rm", "delete", "del", "yeet"]) async def remove_highlight(ctx, highlight_index: commands.Greedy[int]): """ Remove one, or multiple highlights by index """
"""Edit the bot""" if pres := flags.get('presence'): if type_dict.get(pres[0]) is None: await self.bot.change_presence(status=ctx.me.status) elif type_dict.get(pres[0]) == 'streaming': pres.pop(0) await self.bot.change_presence(activity=discord.Streaming( name=' '.join(pres), url='https://www.twitch.tv/#')) else: await self.bot.change_presence(status=ctx.me.status, activity=discord.Activity( type=type_dict[pres.pop(0)], name=' '.join(pres))) if nick := flags.get('nick'): await ctx.me.edit(nick=nick if nick != 'None' else None) if stat := flags.get('status'): await self.bot.change_presence(status=status_dict[stat.lower()], activity=ctx.me.activity) await ctx.message.add_reaction(ctx.tick(True)) @commands.group(invoke_without_command=True) async def sudo(self, ctx, target: Union[discord.Member, discord.User, None], *, command): """Run command as another user""" if not isinstance(target, (discord.Member, discord.User)): new_ctx = await copy_ctx(ctx, command, author=ctx.author) await new_ctx.reinvoke() return new_ctx = await copy_ctx(ctx, command, author=target) await self.bot.invoke(new_ctx)
async def args_edit(self, ctx, **flags): """Edit the bot""" if pres := flags.get("presence"): if type_dict.get(pres[0]) is None: await self.bot.change_presence(status=ctx.me.status) elif type_dict.get(pres[0]) == "streaming": pres.pop(0) await self.bot.change_presence(activity=discord.Streaming( name=" ".join(pres), url="https://www.twitch.tv/#")) else: await self.bot.change_presence( status=ctx.me.status, activity=discord.Activity(type=type_dict[pres.pop(0)], name=" ".join(pres)), ) if nick := flags.get("nick"): await ctx.me.edit(nick=nick if nick != "None" else None) if stat := flags.get("status"): await self.bot.change_presence(status=status_dict[stat.lower()], activity=ctx.me.activity) await ctx.message.add_reaction(ctx.tick(True)) @commands.group(invoke_without_command=True) async def sudo(self, ctx, target: Union[discord.Member, discord.User, None], *, command): """Run command as another user, or with all checks bypassed""" if not isinstance(target, (discord.Member, discord.User)): new_ctx = await copy_ctx(ctx, command, author=ctx.author) await new_ctx.reinvoke() return new_ctx = await copy_ctx(ctx, command, author=target)
class Dev(commands.Cog): """Commands made to assist with bot development""" def __init__(self, bot): self.bot = bot self.scope = {} self.retain = True self._last_result = None async def cog_check(self, ctx): return await self.bot.is_owner(ctx.author) @commands.command(aliases=['sh']) async def shell(self, ctx, *, args: CBStripConverter): """Invokes the system shell, attempting to run the inputted command""" hl_lang = 'sh' if 'cat' in args: hl_lang = return_lang_hl(args) if 'git diff' in args: hl_lang = 'diff' async with ctx.loading(tick=False): stdout, stderr = await do_shell(args) output = clean_bytes(stdout) + '\n' + textwrap.indent( clean_bytes(stderr), '[stderr] ') pages = group(output, 1500) pages = [ctx.codeblock(page, hl_lang) for page in pages] await ctx.quick_menu(pages, 1, delete_message_after=True, timeout=1800) @commands.command(name='eval') async def eval_(self, ctx, *, body: CBStripConverter): """Runs code that you input to the command""" env = { 'bot': self.bot, 'ctx': ctx, 'channel': ctx.channel, 'author': ctx.author, 'guild': ctx.guild, 'message': ctx.message, '_': self._last_result } env.update(globals()) if self.retain: env.update(self.scope) stdout = io.StringIO() to_return = None to_compile = f'async def func(scope, should_retain=True):' \ f'\n try:' \ f'\n{textwrap.indent(body, " ")}' \ f'\n finally:' \ f'\n if not should_retain:' \ f'\n return' \ f'\n scope.update(locals())' async with ctx.loading(exc_ignore=HandleTb): try: import_expression.exec(to_compile, env) except Exception as e: raise HandleTb(ctx, e) evaluated_func = env['func'] try: with redirect_stdout(stdout): result = await evaluated_func(self.scope, self.retain) or '' except Exception as e: raise HandleTb(ctx, e) else: value = stdout.getvalue() or '' self._last_result = result to_return = f'{value}{result}' if to_return: pages = group(to_return, 1500) pages = [ctx.codeblock(page, 'py') for page in pages] await ctx.quick_menu(pages, 1, delete_message_after=True, timeout=1800) @commands.command() async def debug(self, ctx, *, command_string): """Runs a command, checking for errors and returning exec time""" start = time.perf_counter() new_ctx = await copy_ctx(ctx, command_string) stdout = io.StringIO() try: with redirect_stdout(stdout): await new_ctx.reinvoke() except Exception: await ctx.message.add_reaction('❗') value = stdout.getvalue() paginator = commands.Paginator(prefix='```py') for line in (value + traceback.format_exc()).split('\n'): paginator.add_line(line) for page in paginator.pages: await ctx.author.send(page) return end = time.perf_counter() await ctx.send(f'Cmd `{command_string}` executed in {end - start:.3f}s' ) @commands.command() async def sql(self, ctx, *, query: CBStripConverter): """Run SQL statements""" is_multistatement = query.count(';') > 1 if is_multistatement: strategy = self.bot.conn.execute else: strategy = self.bot.conn.fetch start = time.perf_counter() results = await strategy(query) dt = (time.perf_counter() - start) * 1000.0 rows = len(results) if is_multistatement or rows == 0: return await ctx.send(f'`{dt:.2f}ms: {results}`') rkeys = [*results[0].keys()] headers = [ textwrap.shorten(col, width=40 // len(rkeys), placeholder='') for col in rkeys ] r2 = [list(r.values()) for r in results] r = [] for item in r2: for i in item: r.append( textwrap.shorten(str(i), width=40 // len(rkeys), placeholder='')) r = group(r, len(rkeys)) table = tabulate(r, headers=headers, tablefmt='pretty') pages = [ctx.codeblock(page) for page in group(table, 1500)] await ctx.quick_menu( pages, 1, delete_message_after=True, timeout=300, template=discord.Embed(color=discord.Color.main).set_author( name=f'Returned {rows} {pluralize("row", rows)} in {dt:.2f}ms') ) @commands.group(name='dev', invoke_without_command=True) async def dev_command_group(self, ctx): """Some dev commands""" await ctx.send( "We get it buddy, you're super cool because you can use the dev commands" ) @dev_command_group.command(name='delete', aliases=['del']) async def delete_bot_msg(self, ctx, message_ids: commands.Greedy[int]): for m_id in message_ids: converter = commands.MessageConverter() m = await converter.convert(ctx, str(m_id)) if not m.author.bot: raise commands.CommandError( 'I can only delete my own messages') await m.delete() await ctx.message.add_reaction(ctx.tick(True)) @dev_command_group.command(name='source', aliases=['src']) async def _dev_src(self, ctx, *, obj): new_ctx = await copy_ctx(ctx, f'eval return inspect!.getsource({obj})') await new_ctx.reinvoke() @dev_command_group.group(name='scope', invoke_without_command=True) async def _dev_scope(self, ctx, toggle: BoolConverter = None): if toggle is None: pages = group(str(self.scope), 1500) pages = [ctx.codeblock(page, 'py') for page in pages] await ctx.quick_menu(pages, 1, template=discord.Embed( title=f'Retain: {self.retain}', color=discord.Color.main), delete_message_after=True, timeout=300) return async with ctx.loading(): self.retain = toggle @_dev_scope.command(name='flush') async def _clear_scope(self, ctx): async with ctx.loading(): self.scope = {} @flags.add_flag('-s', '--status', default='online', choices=['online', 'offline', 'dnd', 'idle']) @flags.add_flag('-p', '--presence', nargs='+', dest='presence') @flags.add_flag('-n', '--nick', nargs='?', const='None') @flags.command(name='edit') async def args_edit(self, ctx, **flags): """Edit the bot""" if pres := flags.get('presence'): if type_dict.get(pres[0]) is None: await self.bot.change_presence(status=ctx.me.status) elif type_dict.get(pres[0]) == 'streaming': pres.pop(0) await self.bot.change_presence(activity=discord.Streaming( name=' '.join(pres), url='https://www.twitch.tv/#')) else: await self.bot.change_presence(status=ctx.me.status, activity=discord.Activity( type=type_dict[pres.pop(0)], name=' '.join(pres))) if nick := flags.get('nick'): await ctx.me.edit(nick=nick if nick != 'None' else None)
class HighlightCommands(commands.Cog): def __init__(self, bot): self.bot = bot @flags.add_flag('highlight', nargs='+') @flags.add_flag('-re', '--regex', action='store_true') @commands.command(cls=flags.FlagCommand) async def add(ctx, **flags): """ Add a new highlight! When a highlighted word is used, you'll get notified! If the --regex flag is passed, the highlight will be compiled as a regex """ subbed = re.sub(fr"{ctx.prefix}h(igh)?l(ight)? add", '', ctx.message.content) highlight_words = re.sub(r"--?re(gex)?", '', subbed).strip() if flags['regex']: check_regex(highlight_words) else: highlight_words = re.escape(highlight_words) active = await ctx.bot.conn.fetch('SELECT kw FROM highlights WHERE user_id=$1', ctx.author.id) if len(active) >= MAX_HIGHLIGHTS: raise commands.CommandError(f'You may only have {MAX_HIGHLIGHTS} highlights at a time') if highlight_words in [rec['kw'] for rec in active]: raise commands.CommandError('You already have a highlight with this trigger') await ctx.bot.conn.execute( 'INSERT INTO highlights(user_id, kw) VALUES ( $1, $2 )', ctx.author.id, fr"{highlight_words}") ctx.bot.dispatch('hl_update') await ctx.message.add_reaction(ctx.tick(True)) @commands.command(name='exclude', aliases=['mute', 'ignore', 'exc']) async def exclude_guild(ctx, highlight_index, guild_id: int = None): """Add and remove guilds to be ignored from highlight notifications. Currently ignored guilds will be un-ignored if passed a second time """ if not index_check(highlight_index): raise commands.CommandError('Specify a highlight by its index (found in your list of highlights)') highlight_index = int(highlight_index) guild_id = guild_id or ctx.guild.id user_hl = [hl for hl in ctx.bot.get_cog("HlMon").cache if hl.user_id == ctx.author.id] current = user_hl[highlight_index - 1].exc_guilds strategy = "array_remove" if current and guild_id in current else "array_append" await ctx.bot.conn.execute(f'UPDATE highlights SET exclude_guild = {strategy}(exclude_guild, $1) WHERE ' 'user_id=$2 AND kw=$3', guild_id, ctx.author.id, user_hl[highlight_index - 1].kw) ctx.bot.dispatch('hl_update') await ctx.message.add_reaction(ctx.tick(True)) @flags.add_flag('-a', '--add', nargs='*') @flags.add_flag('-r', '--remove', nargs='*') @commands.command(name='block', aliases=['blocks'], cls=flags.FlagCommand) async def hl_block(ctx, **flags): """Add or remove a user from your list of people who won't highlight you, or just view the list Use the --add flag to add a user, and use --remove to do the opposite""" if not flags.get('add') and not flags.get('remove'): if b := ctx.bot.user_cache[ctx.author.id]['hl_blocks']: blocked = [ctx.bot.get_user(i).__str__() for i in b] else: blocked = ["No blocked users"] await ctx.quick_menu(blocked, 10, delete_message_after=True) return strategy = 'array_append' if flags.get('add') else 'array_remove' person = await commands.UserConverter().convert(ctx, (flags.get('add') or flags.get('remove'))[0]) async with ctx.loading(): await ctx.bot.conn.execute(f"UPDATE user_data SET hl_blocks = {strategy}(hl_blocks, $1) WHERE " "user_id=$2", person.id, ctx.author.id) await ctx.bot.build_user_cache()