async def remindme(self, ctx, pre, *, arguments): """ Set a reminder Usage: >remindme in <some time> to <something> >remindme on <YYYY/MM/DD> [HH:mm:ss] to <something> """ try: time, thing = arguments.split(' to ') except ValueError: return await util.send_command_help(ctx) now = arrow.utcnow() if pre == 'on': # user inputs date date = arrow.get(time) seconds = date.timestamp - now.timestamp elif pre == 'in': # user inputs time delta seconds = util.timefromstring(time) date = now.shift(seconds=+seconds) else: return await ctx.send(f"Invalid prefix `{pre}`\nUse `on` for date and `in` for time") db.execute("INSERT INTO reminders VALUES(?, ?, ?, ?, ?, ?)", (ctx.author.id, ctx.guild.id, now.timestamp, date.timestamp, thing, ctx.message.jump_url)) self.cache_needs_refreshing = True await ctx.send(f":pencil: Reminding you in **{util.stringfromtime(seconds)}** " f"`[ {date.format('DD/MM/YYYY HH:mm:ss')} UTC ]` to \n> {thing}")
async def check_reminders(self): """Checks all current reminders""" if self.cache_needs_refreshing: self.cache_needs_refreshing = False self.reminder_list = db.query("SELECT * FROM reminders") if not self.reminder_list: return now = arrow.utcnow().timestamp for reminder in self.reminder_list: # check if timestamp is in future # don't set variables yet to make runs as lightweight as possible if reminder[3] > now: continue user_id, guild_id, created_on, timestamp, thing, message_link = reminder user = self.bot.get_user(user_id) if user is not None: guild = self.bot.get_guild(guild_id) if guild is None: guild = "Deleted guild" date = arrow.get(created_on) try: await user.send(f":alarm_clock: The reminder you set {date.humanize()} `[ {date.format('DD/MM/YYYY HH:mm:ss')} ]` " f"in **{guild}** has expired!\n> {thing}\nContext: {message_link}") logger.info(f'reminded {user} to "{thing}"') except discord.errors.Forbidden: logger.warning(f'Unable to remind {user}, missing permissions') else: logger.info(f'deleted expired reminder by unknown user {user_id}') db.execute("""DELETE FROM reminders WHERE user_id = ? AND guild_id = ? AND message_link = ?""", (user_id, guild_id, message_link)) self.cache_needs_refreshing = True
async def whitelist_global(self, ctx, *, user: discord.User): """Whitelist user globally.""" db.execute("DELETE FROM blacklist_global_users WHERE user_id = ?", (user.id, )) await ctx.send( f":white_check_mark: **{user}** is no longer globally blacklisted from using Miso Bot" )
async def votechannel_add(self, ctx, *, channel: discord.TextChannel): """Set a channel to be a voting channel.""" db.execute( "INSERT OR IGNORE INTO votechannels values(?, ?)", (ctx.guild.id, channel.id), ) await ctx.send(f"{channel.mention} is now a voting channel.")
async def blacklist_global(self, ctx, *, user: discord.User): """Blacklist someone from Miso Bot""" db.execute("INSERT OR IGNORE INTO blacklist_global_users VALUES(?)", (user.id, )) await ctx.send( f":white_check_mark: **{user}** is now globally blacklisted from using Miso Bot" )
async def add(self, ctx, *, keyword): """Add a notification""" dm = ctx.guild is None if dm: guild_id = 0 else: await ctx.message.delete() guild_id = ctx.guild.id check = db.query( "SELECT * FROM notifications WHERE guild_id = ? and user_id = ? and keyword = ?", (guild_id, ctx.author.id, keyword), ) if check is not None: return await ctx.send( ":warning: You already have this notification!") db.execute( "REPLACE INTO notifications values(?, ?, ?)", (guild_id, ctx.author.id, keyword), ) await ctx.author.send( f":white_check_mark: New keyword notification `{keyword}` set " + ("globally" if dm else f"in `{ctx.guild.name}`")) if not dm: await ctx.send("Set a notification!" + ( "" if dm else f" Check your DMs {emojis.VIVISMIRK}"))
async def remove(self, ctx, *, keyword): """Remove notification.""" dm = ctx.guild is None if dm: guild_id = 0 else: await ctx.message.delete() guild_id = ctx.guild.id check = db.query( "SELECT * FROM notifications WHERE guild_id = ? and user_id = ? and keyword = ?", (guild_id, ctx.author.id, keyword), ) if check is None: return await ctx.send(":warning: You don't have that notification." ) db.execute( "DELETE FROM notifications where guild_id = ? and user_id = ? and keyword = ?", (guild_id, ctx.author.id, keyword), ) await ctx.author.send( f":white_check_mark: Keyword notification `{keyword}` that you set " + ("globally" if dm else f"in `{ctx.guild.name}`") + " has been removed.") if not dm: await ctx.send("removed a notification!" + ( "" if dm else f" Check your DMs {emojis.VIVISMIRK}"))
async def remove(self, ctx, name): """Remove a role from the picker.""" roles = db.query("select rolename from roles where guild_id = ?", (ctx.guild.id,)) if name in [x[0] for x in roles]: db.execute("DELETE FROM roles WHERE guild_id = ? and rolename = ?", (ctx.guild.id, name)) await ctx.send(f"Removed `{name}` from the role picker.") else: return await ctx.send(":warning: Could not find this role from the picker")
async def add(self, ctx, role, name): """Add a role to the picker.""" role_to_add = await util.get_role(ctx, role) if role_to_add is None: return await ctx.send(":warning: Could not get this role") db.execute("REPLACE INTO roles VALUES(?, ?, ?)", (ctx.guild.id, name, role_to_add.id)) await ctx.send(embed=discord.Embed(description=f"{role_to_add.mention} added to picker as `{name}`"))
def save_wpm(user, wpm, accuracy, wordcount, language, race): if wpm == 0: return db.execute( "INSERT INTO typingdata VALUES (?, ?, ?, ?, ?, ?, ?)", (arrow.utcnow().timestamp, user.id, wpm, accuracy, wordcount, race, language), )
async def whitelist_user(self, ctx, *, member: discord.Member): """Whitelist a member of this server.""" db.execute( "DELETE FROM blacklisted_users WHERE guild_id = ? AND user_id = ?", (ctx.guild.id, member.id), ) await ctx.send( f":white_check_mark: **{member}** is no longer blacklisted")
async def deleted_unignore(self, ctx, *, channel: discord.TextChannel): """Unignore channel from logging deleted messages.""" db.execute( "delete from deleted_messages_mask where guild_id = ? and channel_id = ?", (ctx.guild.id, channel.id), ) await ctx.send( f"{channel.mention} is no longer ignored from message logging")
async def editprofile_description(self, ctx, *, text): if text.strip() == '': return await util.send_command_help(ctx) db.execute("INSERT OR IGNORE INTO profiles VALUES (?, ?, ?, ?)", (ctx.author.id, None, None, None)) db.execute("UPDATE profiles SET description = ? WHERE user_id = ?", (text[1:], ctx.author.id)) await ctx.send("Description updated!")
async def on_raw_reaction_add(self, payload): """Starboard""" if payload.emoji.name == "⭐": starboard_settings = db.query( "SELECT starboard_toggle, starboard_amount, starboard_channel FROM guilds WHERE guild_id = ?", (payload.guild_id,) ) if starboard_settings is None: # starboard not configured on this server return else: starboard_settings = starboard_settings[0] if not util.int_to_bool(starboard_settings[0]): return message = await self.bot.get_channel(payload.channel_id).fetch_message(payload.message_id) for react in message.reactions: if react.emoji == payload.emoji.name: if react.count < starboard_settings[1]: return else: reaction_count = react.count break channel_id = starboard_settings[2] channel = payload.member.guild.get_channel(channel_id) if channel is None: return board_msg_id = db.query( "SELECT starboard_message_id FROM starboard WHERE message_id = ?", (payload.message_id,) ) if board_msg_id is None: # message is not on board yet, content = discord.Embed(color=discord.Color.gold()) content.set_author( name=f"{message.author}", icon_url=message.author.avatar_url ) jump = f"\n\n[context]({message.jump_url})" content.description = message.content[:2048-len(jump)] + jump content.timestamp = message.created_at content.set_footer(text=f"{reaction_count} ⭐ #{message.channel.name}") if len(message.attachments) > 0: content.set_image(url=message.attachments[0].url) board_message = await channel.send(embed=content) db.execute("INSERT INTO starboard VALUES(?, ?)", (payload.message_id, board_message.id)) else: # message is on board, update star count board_message = await channel.fetch_message(board_msg_id[0][0]) content = board_message.embeds[0] content.set_footer(text=f"{reaction_count} ⭐ #{message.channel.name}") await board_message.edit(embed=content)
async def blacklist_channel(self, ctx, textchannel: discord.TextChannel): """Blacklist a channel.""" db.execute( "INSERT OR IGNORE INTO blacklisted_channels VALUES(?, ?)", (ctx.guild.id, textchannel.id), ) await ctx.send( f":white_check_mark: {textchannel.mention} has been blacklisted from command usage" )
async def blacklist_user(self, ctx, *, member: discord.Member): """Blacklist member of this server.""" db.execute( "INSERT OR IGNORE INTO blacklisted_users VALUES(?, ?)", (ctx.guild.id, member.id), ) await ctx.send( f":white_check_mark: **{member}** has been blacklisted from using commands on this server" )
async def patron_remove(self, ctx, user): """Remove a patron.""" discord_user = await util.get_user(ctx, user) db.execute( "DELETE FROM patrons WHERE user_id = ?", (discord_user.id if discord_user is not None else int(user), )) await ctx.send( f"Removed **{discord_user if discord_user is not None else int(user)}** from patrons" )
async def whitelist_channel(self, ctx, textchannel: discord.TextChannel): """Whitelist a channel.""" db.execute( "DELETE FROM blacklisted_channels WHERE guild_id = ? AND channel_id = ?", (ctx.guild.id, textchannel.id), ) await ctx.send( f":white_check_mark: {textchannel.mention} is no longer blacklisted" )
async def editprofile_background(self, ctx, url): db.execute( "INSERT OR IGNORE INTO profiles VALUES (?, ?, ?, ?)", (ctx.author.id, None, None, None), ) db.execute( "UPDATE profiles SET background_url = ? WHERE user_id = ?", (url, ctx.author.id), ) await ctx.send(":white_check_mark: Background image updated!")
async def patron_toggle(self, ctx, user: discord.User): """Toggle user's patron status.""" current = util.int_to_bool( db.query("SELECT currently_active FROM patrons WHERE user_id = ?", (user.id, ))[0][0]) db.execute( "UPDATE patrons SET currently_active = ? WHERE user_id = ?", (util.bool_to_int(not current), user.id), ) await ctx.send(f"**{user}** patreon activity set to **{not current}**")
async def patron_add(self, ctx, user, tier, patron_since=None): """Add a new patron.""" discord_user = await util.get_user(ctx, user) if discord_user is None: return await ctx.send(f"Cannot find user {user}") since_ts = arrow.get(patron_since).timestamp db.execute("INSERT INTO patrons VALUES(?, ?, ?, ?)", (discord_user.id, int(tier), since_ts, 1)) await ctx.send(f"**{discord_user}** is now a patreon!")
async def whitelist_command(self, ctx, *, command): """Whitelist a command.""" cmd = self.bot.get_command(command) if cmd is None: return await ctx.send(f":warning: `{command}` is not a command!") db.execute( "DELETE FROM blacklisted_commands WHERE guild_id = ? AND command = ?", (ctx.guild.id, str(cmd)), ) await ctx.send(f":white_check_mark: `{cmd}` is no longer blacklisted")
async def minecraft(self, ctx, address=None, port=None): """Get the status of a minecraft server.""" if address == "set": if port is None: return await ctx.send( f"Save minecraft server address for this discord server:\n" f"`{ctx.prefix}minecraft set <address>` (port defaults to 25565)\n" f"`{ctx.prefix}minecraft set <address>:<port>`") address = port.split(":")[0] try: port = int(port.split(":")[1]) except IndexError: port = 25565 db.execute( """REPLACE INTO minecraft VALUES (?, ?, ?)""", (ctx.guild.id, address, port), ) return await ctx.send( f"Minecraft server of this discord set to `{address}:{port}`") if address is None: serverdata = db.query( """SELECT address, port FROM minecraft WHERE guild_id = ?""", (ctx.guild.id, ), ) if serverdata is None: return await ctx.send( "No minecraft server saved for this discord server!") else: address, port = serverdata[0] server = await self.bot.loop.run_in_executor( None, lambda: minestat.MineStat(address, int(port or "25565"))) content = discord.Embed() content.colour = discord.Color.green() if server.online: content.add_field(name="Server Address", value=f"`{server.address}`") content.add_field(name="Version", value=server.version) content.add_field( name="Players", value=f"{server.current_players}/{server.max_players}") content.add_field(name="Latency", value=f"{server.latency}ms") content.set_footer(text=f"Message of the day: {server.motd}") else: content.description = ":warning: **Server is offline**" content.set_thumbnail( url="https://vignette.wikia.nocookie.net/potcoplayers/images/c/c2/" "Minecraft-icon-file-gzpvzfll.png/revision/latest?cb=20140813205910" ) await ctx.send(embed=content)
async def blacklist_command(self, ctx, *, command): """Blacklist a command.""" cmd = self.bot.get_command(command) if cmd is None: return await ctx.send(f":warning: `{command}` is not a command!") db.execute( "INSERT OR IGNORE INTO blacklisted_commands VALUES(?, ?)", (ctx.guild.id, str(cmd)), ) await ctx.send( f":white_check_mark: `{cmd}` has been blacklisted on this server")
async def votechannel_remove(self, ctx, *, channel: discord.TextChannel): """Remove voting channel.""" if db.query( "SELECT * FROM votechannels WHERE guild_id = ? and channel_id = ?", (ctx.guild.id, channel.id)) is None: return await ctx.send( f":warning: {channel.mention} is not a voting channel!") db.execute( "DELETE FROM votechannels where guild_id = ? and channel_id = ?", (ctx.guild.id, channel_id)) await ctx.send(f"{channel.mention} is no longer a voting channel.")
async def editprofile_background(self, ctx, url): patrons = db.query( "select user_id from patrons where currently_active = 1") if ctx.author != self.bot.owner: if ctx.author.id not in [x[0] for x in patrons]: return await ctx.send( "Sorry, only patreon supporters can use this feature!") db.execute("INSERT OR IGNORE INTO profiles VALUES (?, ?, ?, ?)", (ctx.author.id, None, None, None)) db.execute("UPDATE profiles SET background_url = ? WHERE user_id = ?", (url, ctx.author.id)) await ctx.send("Background image updated!")
async def patron_toggle(self, ctx, user): """Toggle user's patron status.""" discord_user = await util.get_user(ctx, user) if discord_user is None: return await ctx.send(f"Cannot find user {user}") current = util.int_to_bool( db.query("SELECT currently_active FROM patrons WHERE user_id = ?", (discord_user.id, ))[0][0]) db.execute("UPDATE patrons SET currently_active = ? WHERE user_id = ?", (util.bool_to_int(not current), discord_user.id)) await ctx.send( f"**{discord_user}** patreon activity set to **{not current}**")
async def add(self, ctx, *, keyword): """Add a notification""" await ctx.message.delete() check = db.query("SELECT * FROM notifications WHERE guild_id = ? and user_id = ? and keyword = ?", (ctx.guild.id, ctx.author.id, keyword)) if check is not None: return await ctx.send(f"You already have this notification {self.emojis.get('hyunjinwtf')}") db.execute("REPLACE INTO notifications values(?, ?, ?)", (ctx.guild.id, ctx.author.id, keyword)) await ctx.author.send(f"New notification for keyword `{keyword}` set in `{ctx.guild.name}` ") await ctx.send(f"Set a notification! Check your DMs {self.emojis.get('vivismirk')}")
async def remove(self, ctx, *, keyword): """Remove notification""" await ctx.message.delete() check = db.query("SELECT * FROM notifications WHERE guild_id = ? and user_id = ? and keyword = ?", (ctx.guild.id, ctx.author.id, keyword)) if check is None: return await ctx.send(f"You don't have that notification {self.emojis.get('hyunjinwtf')}") db.execute("DELETE FROM notifications where guild_id = ? and user_id = ? and keyword = ?", (ctx.guild.id, ctx.author.id, keyword)) await ctx.author.send(f"Notification for keyword `{keyword}` removed for `{ctx.guild.name}` ") await ctx.send(f"removed a notification! Check your DMs {self.emojis.get('vivismirk')}")
async def add(self, ctx, name, *, response): """Add a new command.""" if name in self.bot_command_list(): return await ctx.send(f"Sorry, `{ctx.prefix}{name}` is already a built in command!") elif name in custom_command_list(ctx.guild.id): return await ctx.send(f"Sorry, the custom command `{ctx.prefix}{name}` " f"already exists on this server!") db.execute( "INSERT INTO customcommands VALUES (?, ?, ?, ?, ?)", (ctx.guild.id, name, response, arrow.utcnow().timestamp, ctx.author.id) ) await ctx.send(f"Custom command `{ctx.prefix}{name}` " f"successfully added with the response `{response}`")