"""This file contains the Reminder Discord Cog extension. """ from re import A import discord from discord.ext import commands from asyncio import sleep import time from py_files.src.cog_utils.reminder_heap import ReminderHeap class Reminder(commands.Cog): """Reminder provides functions related to reminding users. """ def __init__(self, bot) -> None: """Constructs a Reminder object """ self.bot = bot self.reminders = ReminderHeap() @commands.Cog.listener() async def on_ready(self): await self.update_reminder() async def update_reminder(self): while True: await sleep(5) while self.reminders.peek_reminder() is not None and\ time.time() >= self.reminders.peek_reminder(): ctx = self.reminders.pop_reminder() # remindme command if ctx.remind_self: reply = f"Hey {ctx.author.mention}, don't forget"\ f'about this:\n```{ctx.reminder}```' await ctx.reply(reply) # remind command else: reply = f'Hey {ctx.member.mention}, {ctx.author.mention} '\ f'wanted you to remember about this:\n'\ f'```{ctx.reminder}```' await ctx.reply(reply) @commands.command(name='remindme') async def remind_me(self, ctx: commands.Context) -> None: """Adds a reminder for the user. Args: ctx: A discord command Context. Returns: None. Example Usage: !remindme 1y2mo5d30min remind me to do something """ err_msg = 'Please enter your reminder in the following format:\n'\ f'```{self.bot.command_prefix}remindme 1y2mo5d30min remind'\ 'me to do something.```'\ 'Where:\n```y: year, mo: month, d: days, min: minutes```' msg = ctx.message.content.split() if len(msg) <= 2: await ctx.send(err_msg) return ctx.remind_self = True epoch_time = await self._parse_str_time(ctx, msg[1], err_msg) # return if invalid str_time formatting if not epoch_time: return # join reminder request reminder = ' '.join(msg[2:]) self.reminders.add_reminder(ctx, reminder, epoch_time) await ctx.message.add_reaction(self.bot.reactions['checkmark']) @commands.command(name='remind') async def remind(self, ctx: commands.Context) -> None: err_msg = 'Please enter your reminder in the following format:\n'\ f'```{self.bot.command_prefix}remind @user 1y2mo5d30min remind'\ 'me to do something.```'\ 'Where:\n```y: year, mo: month, d: days, min: minutes```' msg = ctx.message.content.split() if len(msg) <= 3: await ctx.send(err_msg) return try: member = await ctx.guild.fetch_member(msg[1][2:-1]) except: await ctx.send('Cannot find user.') return ctx.remind_self = False ctx.member = member # TODO: not getting stored epoch_time = await self._parse_str_time(ctx, msg[2], err_msg) # return if invalid str_time formatting if not epoch_time: return # join reminder request reminder = ' '.join(msg[3:]) self.reminders.add_reminder(ctx, reminder, epoch_time) await ctx.message.add_reaction(self.bot.reactions['checkmark']) @commands.command(name='myreminders') async def check_reminders(self, ctx: commands.Context) -> None: author_id = ctx.author.id reply = [] reminders = self.reminders.check_reminder(author_id) if not reminders: await ctx.reply(f'You do not have any reminders, use the' f'`{self.bot.command_prefix}remindme` command ' 'to set reminders!') return for cnt, rem in enumerate(reminders): temp = [f'{cnt+1}.)'] content = rem.reminder if len(content) > 37: content = f'{content[:38]}...' temp.append('{:<40}'.format(content)) temp.append('in') temp.append(f'`{self._remaining_time(rem.epoch_time)}`') reply.append(' '.join(temp)) # embed format title = f"{ctx.author}'s Reminders" desc = '\n'.join(reply) embed = discord.Embed( title=title, description=desc ) embed.color = discord.Color.from_rgb(255, 161, 122) await ctx.send(embed=embed) def _remaining_time(self, epoch_time: float) -> str: """ """ total_min = (epoch_time - time.time()) / 60 result = [] # year if total_min >= 525960: yr = total_min // 525960 total_min = total_min % 525960 result.append(f'{int(yr)}yr') # month if total_min >= 43800: mo = total_min // 43800 total_min = total_min % 43800 result.append(f'{int(mo)}mo') # day if total_min >= 1440: day = total_min // 1440 total_min = total_min % 1440 result.append(f'{int(day)}day') # hour if total_min >= 60: hr = total_min // 60 total_min = total_min % 60 result.append(f'{int(hr)}hr') # minute result.append(f'{int(total_min)}min') return ' '.join(result) async def _parse_str_time(self, ctx: commands.Context, str_time: str, err_msg: str) -> float: """Parses a str str_time into an int. Args: ctx: A discord command Context. str_time: A str time. err_msg: An error message to send when format error occurs. Returns: A float time in epoch. """ total_mins = 0 str_time = str_time.lower() # year if 'yr' in str_time: try: ind = str_time.find('yr') yr = int(str_time[:ind]) total_mins += 525960 * yr str_time = str_time[ind+2:] except: await ctx.send(err_msg) return # month if 'mo' in str_time: try: ind = str_time.find('mo') month = int(str_time[:ind]) total_mins += 43800 * month str_time = str_time[ind+2:] except: await ctx.send(err_msg) return # day if 'd' in str_time: try: ind = str_time.find('d') day = int(str_time[:ind]) total_mins += 1440 * day str_time = str_time[ind+1:] except: await ctx.send(err_msg) return # hour if 'hr' in str_time: try: ind = str_time.find('hr') hour = int(str_time[:ind]) total_mins += 60 * hour str_time = str_time[ind+2:] except: await ctx.send(err_msg) return # minute if 'min' in str_time: try: ind = str_time.find('min') minute = int(str_time[:ind]) total_mins += minute except: await ctx.send(err_msg) return # non-valid str if total_mins == 0: await ctx.send(err_msg) return return total_mins * 60 + time.time() async def setup(bot): await bot.add_cog(Reminder(bot))