async def tac(self, ctx): """Toggle AutoCucumber. Usage: tac""" echeck_perms(ctx, ('bot_owner', )) self.enabled = not self.enabled await ctx.send('Autocucumber is now ' + ('on.' if self.enabled else 'off.'))
async def add_emote(self, ctx, _emote: str): """Add a Twitch, FrankerFaceZ, BetterTTV, or Discord emote to the current server. Usage: add_emote [name of emote]""" echeck_perms(ctx, ('bot_owner', )) emote = _emote.replace(':', '') ext = 'png' async with aiohttp.ClientSession(loop=self.loop) as session: with async_timeout.timeout(13): try: async with session.get( 'https://static-cdn.jtvnw.net/emoticons/v1/' + str(self.bot.emotes['twitch'][emote]['image_id']) + '/1.0') as resp: emote_img = await resp.read() except KeyError: # let's try frankerfacez try: async with session.get( 'https://cdn.frankerfacez.com/emoticon/' + str(self.bot.emotes['ffz'][emote]) + '/1') as resp: emote_img = await resp.read() except KeyError: # let's try BetterTTV try: async with session.get( self.bot.emotes['bttv'][emote]) as resp: emote_img = await resp.read() except KeyError: # let's try Discord await self.bot.say( '**No such emote!** I can fetch from Twitch, FrankerFaceZ, BetterTTV, or Discord (soon).' ) return False result = await self.bot.create_custom_emoji(ctx.message.server, name=emote, image=emote_img) await self.bot.say('Added. ' + str(result))
async def guildtree(self, ctx, *ids: str): """List the guilds I am in (tree version). Usage: guildtree""" echeck_perms(ctx, ('bot_owner', )) pager = commands.Paginator(prefix='```diff') guilds: List[discord.Guild] if ids: s_map = {i.id: i for i in self.bot.guilds} for sid in ids: with assert_msg( ctx, '**ID** `%s` **is invalid. (must be 18 numbers)**' % sid): check(len(sid) == 18) try: guilds.append(s_map[sid]) except KeyError: await ctx.send('guild ID **%s** not found.' % sid) return False else: guilds = self.bot.guilds for guild in guilds: pager.add_line('+ ' + guild.name + ' [{0} members] [ID {1}]'.format( str(len(guild.members)), guild.id)) for channel in guild.channels: xname = channel.name if str(channel.type) == 'voice': xname = '[voice] ' + xname pager.add_line(' • ' + xname) for page in pager.pages: await ctx.send(page)
async def event_calls(self, ctx): """Get the specific event calls. Usage: event_calls""" echeck_perms(ctx, ('bot_owner',)) emb = discord.Embed(color=random.randint(1, 255**3-1), title='Event Calls') emb.description = 'Here are all the event calls made.' author = self.bot.user emb.set_author(name=str(author), icon_url=(author.avatar_url if author.avatar_url else author.default_avatar_url)) emb.add_field(name='Total', value=sum(self.bot.event_calls.values())) fmap = { 'Servers': '', 'Messages': '', 'Updates': '', 'Socket': '', 'Other': '' } for ev, count in self.bot.event_calls.items(): if ev.startswith('server'): fmap['Servers'] += '**{}**: {}\n'.format(ev, count) elif ev.endswith('update'): fmap['Updates'] += '**{}**: {}\n'.format(ev, count) elif 'message' in ev: fmap['Messages'] += '**{}**: {}\n'.format(ev, count) elif ev.startswith('socket'): fmap['Socket'] += '**{}**: {}\n'.format(ev, count) else: fmap['Other'] += '**{}**: {}\n'.format(ev, count) for name, value in fmap.items(): if value: emb.add_field(name=name, value=value) await self.bot.say(embed=emb)
async def embed_from_json(self, ctx, *, js_text: str): """Send an embed from JSON. Usage: embed_from_json [json]""" echeck_perms(ctx, ('bot_owner', )) class SemiEmbed: def __init__(self, obj): self.obj = obj def to_dict(self): return self.obj try: embed_obj = json.loads(js_text) except json.decoder.JSONDecodeError: await ctx.send(':warning: **Invalid JSON data!**') else: sembed = SemiEmbed(embed_obj) try: await ctx.send(embed=sembed) except discord.HTTPException as e: if '400' in str(e): await ctx.send( ':warning: **Couldn\'t send embed, check your data!**') else: raise e
async def repeat(self, ctx, times : int, *, command: str): """Repeats a command a specified number of times. Usage: repeat [times] [command]""" echeck_perms(ctx, ('bot_admin',)) msg = copy.copy(ctx.message) msg.content = command for i in range(times): await self.bot.process_commands(msg, ctx.prefix)
async def sendfile(self, ctx, path: str = 'assets/soon.gif', msg: str = '📧 File incoming!'): """Send a file to Discord. Usage: sendfile [file path] {message}""" echeck_perms(ctx, ('bot_owner', )) await ctx.send(msg, file=discord.File(path))
async def guildlist(self, ctx): """List the guilds I am in. Usage: guildlist""" echeck_perms(ctx, ('bot_owner', )) pager = commands.Paginator() for guild in self.bot.guilds: pager.add_line(guild.name) for page in pager.pages: await ctx.send(page)
async def serverlist(self, ctx): """List the servers I am in. Usage: serverlist""" echeck_perms(ctx, ('bot_owner',)) pager = commands.Paginator() for server in self.bot.servers: pager.add_line(server.name) for page in pager.pages: await self.bot.say(page)
async def messages(self, ctx, *number: int): """Read contact messages. Usage: messages {number}""" echeck_perms(ctx, ('bot_owner', )) def chan(msg): if 'guild' in msg: try: guild = {s.id: s for s in self.bot.guilds}[msg['guild_id']] except KeyError: return 'guild-removed' try: channel = {c.id: c for c in guild.channels}[msg['channel_id']].name except KeyError: return 'deleted-channel' msg['channel'] = channel return channel else: return 'was-pm' if number: nums = number else: nums = range(self.bot.store.get('msgs_read_index', 0), len(self.bot.store['owner_messages'])) for num in nums: msg = self.bot.store['owner_messages'][num] emb = discord.Embed(color=random.randint(1, 255**3 - 1)) author = await self.bot.get_user_info(msg['user_id']) emb.set_author(name=str(author), icon_url=author.avatar_url) emb.description = msg['message'] emb.add_field(name='User Tag', value=msg['user']) emb.add_field(name='Nickname', value=msg['nick']) emb.add_field(name='Message ID', value=msg['message_id']) emb.add_field(name='User ID', value=msg['user_id']) emb.add_field(name='Channel', value='#' + chan(msg) + '\nID: `' + msg['channel_id'] + '`') emb.add_field(name='PM?', value=('Yes' if msg['pm'] else 'No')) emb.add_field(name='Date and Time', value=msg['time']) emb.add_field(name='Timestamp', value=msg['timestamp']) emb.add_field(name='Contains Mention?', value=('Yes' if msg['contains_mention'] else 'No')) if 'guild' in msg: emb.add_field(name='guild', value='**' + msg['guild'] + '**\nID: `' + msg['guild_id'] + '`\nMembers at the time: ' + str(msg['guild_members']) + '\nMembers now: ' + str( len({s.id: s for s in self.bot.guilds }[msg['guild_id']].members))) await ctx.send(embed=emb) self.bot.store['msgs_read_index'] = nums[-1] await ctx.send('Finished!')
async def shutdown(self, ctx): """Shut down and stop the bot. Usage: shutdown""" echeck_perms(ctx, ('bot_owner',)) await self.bot.say(':warning: Are you **sure** you want to stop the bot? Type `yes` to continue.') if not (await self.bot.wait_for_message(timeout=7.0, author=ctx.message.author, channel=ctx.message.channel, check=lambda m: m.content.lower().startswith('yes'))): return await self.bot.logout()
async def rawsetprop(self, ctx, scope: str, pname: str, value: str): """Set the value of a property on any level. Usage: rawsetprop [scope] [property name] [value]""" echeck_perms(ctx, ('bot_admin', )) try: self.bot.store.set_prop(ctx.message, scope, pname, value) except Exception: await ctx.send('âš An error occured.') return await ctx.send('Successfully set `{0}` as `{1}`!'.format(pname, value))
async def emotispam(self, ctx): """Spam some emotes! CRASH WARNING! Warning: Instant crash for desktop users. Only fixable on web or mobile apps. Usage: emotispam""" echeck_perms(ctx, ('bot_owner', )) _em = emojis r = list(range(0, math.ceil(len(emojis) / 2000))) for i in r: await ctx.send(_em[:2000]) _em = _em[2000:]
async def dload(self, ctx): """Load the datastore from disk. Usage: dload""" echeck_perms(ctx, ('bot_owner',)) await self.bot.say('**ARE YOU SURE YOU WANT TO LOAD THE DATASTORE?** *yes, no*') resp = await self.bot.wait_for_message(channel=ctx.message.channel, author=ctx.message.author) if resp.content.lower() == 'yes': await self.bot.store.read() await self.bot.say('**Read the datastore from disk, overwriting current copy!**') else: await self.bot.say('**Didn\'t say yes, aborting.**')
async def broadcast(self, ctx, *, broadcast_text: str): """Broadcast a message to all guilds. Usage: broadcast [message]""" echeck_perms(ctx, ('bot_owner', )) err = '' def get_prefix(s): props = self.bot.store['properties'] servs = props['by_guild'] if s.id in servs: if 'command_prefix' in servs[s.id]: return servs[s.id]['command_prefix'] else: return props['global']['command_prefix'] else: return props['global']['command_prefix'] if self.bot.selfbot: await ctx.send( ''':warning: **This could potentially get you banned with a selfbot.** If you're sure you want to do this, type `yes` within 8 seconds.''') if not (await self.bot.wait_for( 'message', timeout=8.0, check=lambda m: m.content.lower().startswith('yes') and m. author == ctx.author and m.channel == ctx.channel)): return for i in self.bot.guilds: text = broadcast_text.replace('%prefix%', get_prefix(i)) if i.id in self.bot.store['nobroadcast']: pass else: try: self.last_broadcasts[i.id] = await i.default_channel.send( text) except discord.Forbidden: satisfied = False c_count = 0 try_channels = i.channels channel_count = len(try_channels) - 1 while not satisfied: with suppress(discord.Forbidden, discord.HTTPException): self.last_broadcasts[ i.id] = await try_channels[c_count].send(text) satisfied = True if c_count >= channel_count: err += f'`[WARN]` Couldn\'t broadcast to guild **{i.name}**\n' satisfied = True c_count += 1 await asyncio.sleep(0.175) if err: await ctx.send(err)
async def command_calls(self, ctx): """Get the specific command calls. Usage: command_calls""" echeck_perms(ctx, ('bot_owner',)) emb = discord.Embed(color=random.randint(1, 255**3-1), title='Command Calls') emb.description = 'Here are all the command calls made.' author = self.bot.user emb.set_author(name=str(author), icon_url=(author.avatar_url if author.avatar_url else author.default_avatar_url)) emb.add_field(name='Total', value=sum(self.bot.command_calls.values())) for cmd, count in reversed(sorted(self.bot.command_calls.items(), key=lambda i: i[1])): emb.add_field(name=cmd, value=count) await self.bot.say(embed=emb)
async def gemote_msg(self, ctx, *, text: str): """Send a message with emotes, bypassing the cross server emote restriction. Usage: gemote_msg [message]""" echeck_perms(ctx, ('bot_owner', )) emb = discord.Embed(color=random.randint(1, 255**3 - 1)) final = text[:] for emoji in self.bot.get_all_emojis(): final = final.replace(':%s:' % emoji.name, str(emoji).replace(':', ';_!:')) final = final.replace(';_!:', ':') emb.description = final await self.bot.say(embed=emb)
async def restart(self, ctx): """Restarts this bot. Usage: restart""" echeck_perms(ctx, ('bot_owner', )) self.bot.store_writer.cancel() await self.bot.store.commit() if ctx.invoked_with != 'update': await ctx.send( 'I\'ll try to restart. Hopefully I come back alive :stuck_out_tongue:' ) self.logger.info('The bot is now restarting!') # self.bot.is_restart = True os.execl(sys.executable, sys.executable, *sys.argv)
async def restart(self, ctx): """Restarts this bot. Usage: restart""" echeck_perms(ctx, ('bot_owner',)) # for i in self.bot.servers: # await self.bot.send_message(i.default_channel, 'This bot (' + self.bname + ') is now restarting!') self.bot.store_writer.cancel() await self.bot.store.commit() if ctx.invoked_with != 'update': await self.bot.say('I\'ll try to restart. Hopefully I come back alive :stuck_out_tongue:') self.logger.info('The bot is now restarting!') self.bot.is_restart = True os.execl(sys.executable, sys.executable, *sys.argv)
async def ban(self, ctx, *, member: discord.Member): """Ban someone from the server. Usage: ban [member]""" echeck_perms(ctx, ('ban_members', )) await self.bot.say(':hammer: **Are you sure you want to ban ' + member.mention + '?**') if not (await self.bot.wait_for_message( timeout=6.0, author=ctx.message.author, channel=ctx.message.channel, check=lambda m: m.content.lower().startswith('y'))): await self.bot.say('Not banning.') return await self.bot.ban(member) await self.bot.say(':hammer: Banned. It was just about time.')
async def console_msg(self, ctx): """Allow you to type here in the console. Usage: console_msg""" echeck_perms(ctx, ('bot_owner',)) def console_task(ch): while True: text_in = input('Message> ') if text_in == 'quit': return else: self.loop.create_task(self.bot.send_message(ch, text_in)) await self.bot.say('Now entering: Console message mode') print('Type \'quit\' to exit.') await self.loop.run_in_executor(None, console_task, ctx.message.channel) await self.bot.say('Exited console message mode')
async def update(self, ctx): """Auto-updates this bot and restarts if any code was updated. Usage: update""" echeck_perms(ctx, ('bot_owner', )) restart = not ctx.invoked_with.startswith('r') msg = await ctx.send('Trying to update...') r_key = ', now restarting' if restart else '' r_not_key = ', not restarting' if restart else '' dest = ctx.channel if self.bot.selfbot else ctx.author try: gitout = await self.loop.run_in_executor( None, functools.partial(subprocess.check_output, ['git', 'pull'], stderr=subprocess.STDOUT)) gitout = gitout.decode('utf-8') except (subprocess.CalledProcessError, FileNotFoundError) as exp: if ('status 128' in str(exp)) or isinstance( exp, FileNotFoundError): with async_timeout.timeout(25): # for streaming async with self.bot.cog_http.get( 'https://github.com/Armored-Dragon/goldmine/archive/master.zip' ) as r: tarball = await r.read() with zipfile.ZipFile(io.BytesIO(tarball)) as z: z.extractall(os.path.join(self.bot.dir, 'data')) distutils.dir_util.copy_tree( os.path.join(self.bot.dir, 'data', 'goldmine-master'), self.bot.dir) shutil.rmtree( os.path.join(self.bot.dir, 'data', 'goldmine-master')) gitout = 'Successfully updated via zip.\nZip size: ' + str( sys.getsizeof(tarball) / 1048576) + ' MB' else: await msg.edit( content='An error occured while attempting to update!') await dest.send('```' + str(exp) + '```') gitout = False if gitout != False: await dest.send('Update Output:\n```' + gitout + '```') if not gitout: await msg.edit(content=msg.content + f'\nUpdate failed{r_not_key}.' ) elif gitout.split('\n')[-2:][0] == 'Already up-to-date.': await msg.edit(content=f'Bot was already up-to-date{r_not_key}.') else: await msg.edit(content=f'Bot was able to update{r_key}.') if restart: await self.restart.invoke(ctx)
async def screenshot(self, ctx): """Take a screenshot. Usage: screenshot""" echeck_perms(ctx, ('bot_owner', )) if have_pil and (sys.platform not in ['linux', 'linux2']): grabber = ImageGrab else: grabber = pyscreenshot image = grabber.grab() img_bytes = io.BytesIO() image.save(img_bytes, format='PNG') img_bytes.seek(0) await self.bot.upload( img_bytes, filename='screenshot.png', content='This is *probably* what my screen looks like right now.')
async def msg_rate(self, ctx): """Get the message rate. Usage: msg_rate""" echeck_perms(ctx, ('bot_owner',)) msg = await self.bot.say('Please wait...') start_time = datetime.now() m = {'messages': 0} async def msg_task(m): while True: await self.bot.wait_for_message() m['messages'] += 1 task = self.loop.create_task(msg_task(m)) await asyncio.sleep(8) task.cancel() time_elapsed = datetime.now() - start_time time_elapsed = time_elapsed.total_seconds() await self.bot.edit_message(msg, 'I seem to be getting ' + str(round(m['messages'] / time_elapsed, 2)) + ' messages per second.')
async def dload(self, ctx): """Load the datastore from disk. Usage: dload""" echeck_perms(ctx, ('bot_owner', )) await ctx.send( '**ARE YOU SURE YOU WANT TO LOAD THE DATASTORE?** *yes, no*') resp = await self.bot.wait_for( 'message', timeout=15, check=lambda m: m.channel == ctx.channel and m.author == ctx.author ) if resp.content.lower() == 'yes': self.bot.store.read() await ctx.send( '**Read the datastore from disk, overwriting current copy!**') else: await ctx.send('**Didn\'t say yes, aborting.**')
async def ban(self, ctx, *, member: discord.Member): """Ban someone from the guild. Usage: ban [member]""" echeck_perms(ctx, ('ban_members', )) await ctx.send(':hammer: **Are you sure you want to ban ' + member.mention + '?**') if not (await self.bot.wait_for( 'message', timeout=6.0, check=lambda m: m.content.lower().startswith('y') and m.channel == ctx.channel and m.author == ctx.author)): await ctx.send('Not banning.') return await member.ban( reason= 'Ban was requested by command (from someone with the Ban Members permission)' ) await ctx.send(':hammer: Banned. It was just about time.')
async def seref(self, ctx, *, code: str): """Evaluate some code (multi-statement) in command scope. Usage: seref [code to execute]""" echeck_perms(ctx, ('bot_owner',)) dc = self.dc_funcs def print(*ina: str): self.loop.create_task(self.bot.say(' '.join(ina))) return True try: ev_output = exec(bdel(bdel(code, '```python'), '```py').strip('`')) except Exception as e: ev_output = 'An exception of type %s occured!\n' % type(e).__name__ + str(e) o = str(ev_output) if ev_output is None: await self.bot.say('✅') return if ctx.invoked_with.startswith('r'): await self.bot.say(o) else: await self.bot.say('```py\n' + o + '```')
async def render(self, ctx, *, webpage: str): """Render a webpage to image. Usage: render [url]""" echeck_perms(ctx, ('bot_owner', )) await self.bot.say( ':warning: Not yet working.' 'Type `yes` within 6 seconds to proceed and maybe crash your bot.') if not (await self.bot.wait_for_message( timeout=6.0, author=ctx.message.author, channel=ctx.message.channel, check=lambda m: m.content.lower().startswith('yes'))): return try: self.web_render = scr.Screenshot() except ImportError: await self.bot.say('The bot owner hasn\'t enabled this feature!') return image = self.web_render.capture(webpage) await self.bot.upload(io.BytesIO(image), filename='webpage.png')
async def memberlist(self, ctx, *server_ids: str): """List the members of a server. Usage: memberlist [server ids]""" echeck_perms(ctx, ('bot_owner',)) if not server_ids: await self.bot.say('**You need to specify at least 1 server ID!**') return False pager = commands.Paginator(prefix='```diff') pager.add_line('< -- SERVERS <-> MEMBERS -- >') server_table = {i.id: i for i in self.bot.servers} for sid in server_ids: with assert_msg(ctx, f'**ID** `{sid}` **is invalid. (must be 18 numbers)**'): check(len(sid) == 18) try: server = server_table[sid] except KeyError: await self.bot.say(f'**ID** `{sid}` **was not found.**') return False pager.add_line('+ ' + server.name + ' [{0} members] [ID {1}]'.format(str(len(server.members)), server.id)) for member in server.members: pager.add_line('- ' + str(member)) for page in pager.pages: await self.bot.say(page)
async def setprop(self, ctx, pname: str, *, value: str): """Set the value of a property on server level. Usage: setprop [property name] [value]""" echeck_perms(ctx, ('manage_server', )) self.bot.store.set_prop(ctx.message, 'by_server', pname, value) await self.bot.say(':white_check_mark:')