From 6f96858392865c48ab8dd205f087cbc14c1c11cb Mon Sep 17 00:00:00 2001 From: TrustyJAID Date: Sun, 27 Jan 2019 01:54:12 -0700 Subject: [PATCH] [Away] Give some more flair to listening and gaming This gives a little bit more flair to the listening and gaming options providing details about the users activity such as: Game details if the game provides it or a thumbnail. Listening shows the current placement in the song just like the audio cog as well as the album art now. You can also now set an image as the response if embeds are enabled and the image is a valid embed image. This also fixes a bug when the bot restarts removing old settings and a bug with replacing mentions in listening status. --- away/away.py | 181 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 114 insertions(+), 67 deletions(-) diff --git a/away/away.py b/away/away.py index dd29cfe..b2cfe96 100644 --- a/away/away.py +++ b/away/away.py @@ -1,96 +1,133 @@ import discord from redbot.core import Config, commands, checks from typing import Optional +import datetime +import re +IMAGE_LINKS = re.compile(r"(http[s]?:\/\/[^\"\']*\.(?:png|jpg|jpeg|gif|png))") BaseCog = getattr(commands, "Cog", object) + class Away(BaseCog): """Le away cog""" default_global_settings = {"ign_servers": []} - default_user_settings = {"MESSAGE": False, "IDLE_MESSAGE": False, - "DND_MESSAGE": False, "OFFLINE_MESSAGE": False, - "GAME_MESSAGE":{}, "STREAMING_MESSAGE":False, - "LISTENING_MESSAGE":False} + default_user_settings = { + "MESSAGE": False, + "IDLE_MESSAGE": False, + "DND_MESSAGE": False, + "OFFLINE_MESSAGE": False, + "GAME_MESSAGE": {}, + "STREAMING_MESSAGE": False, + "LISTENING_MESSAGE": False, + } def __init__(self, bot): self.bot = bot self._away = Config.get_conf(self, 8423491260, force_registration=True) - self._away.register_global(**self.default_global_settings) self._away.register_user(**self.default_user_settings) + def _draw_play(self, song): + song_start_time = song.start + total_time = song.duration + current_time = datetime.datetime.utcnow() + elapsed_time = current_time - song_start_time + sections = 12 + loc_time = round((elapsed_time / total_time) * sections) # 10 sections + + bar_char = "\N{BOX DRAWINGS HEAVY HORIZONTAL}" + seek_char = "\N{RADIO BUTTON}" + play_char = "\N{BLACK RIGHT-POINTING TRIANGLE}" + msg = "\n" + play_char + " " + + for i in range(sections): + if i == loc_time: + msg += seek_char + else: + msg += bar_char + + msg += " `{:.7}`/`{:.7}`".format(str(elapsed_time), str(total_time)) + return msg + async def make_embed_message(self, author, message, state=None): """ Makes the embed reply """ - avatar = author.avatar_url_as() # This will return default avatar if no avatar is present + avatar = author.avatar_url_as() # This will return default avatar if no avatar is present color = author.color - + if message: + link = IMAGE_LINKS.search(message) + if link: + message = message.replace(link.group(0), " ") if state == "away": em = discord.Embed(description=message, color=color) - em.set_author( - name="{} is currently away".format(author.display_name), - icon_url=avatar - ) + em.set_author(name="{} is currently away".format(author.display_name), icon_url=avatar) elif state == "idle": em = discord.Embed(description=message, color=color) - em.set_author( - name="{} is currently idle".format(author.display_name), - icon_url=avatar - ) + em.set_author(name="{} is currently idle".format(author.display_name), icon_url=avatar) elif state == "dnd": em = discord.Embed(description=message, color=color) em.set_author( - name="{} is currently do not disturb".format(author.display_name), - icon_url=avatar + name="{} is currently do not disturb".format(author.display_name), icon_url=avatar ) elif state == "offline": em = discord.Embed(description=message, color=color) em.set_author( - name="{} is currently offline".format(author.display_name), - icon_url=avatar + name="{} is currently offline".format(author.display_name), icon_url=avatar ) elif state == "gaming": em = discord.Embed(description=message, color=color) em.set_author( name=f"{author.display_name} is currently playing {author.activity.name}", - icon_url=avatar + icon_url=avatar, ) + em.title = getattr(author.activity, "details", None) + thumbnail = getattr(author.activity, "large_image_url", None) + if thumbnail: + em.set_thumbnail(url=thumbnail) elif state == "listening": - em = discord.Embed(description=message, color=author.activity.color) - artist_title = f"{author.activity.title} by " + ", ".join(a for a in author.activity.artists) - limit = 256 - (len(author.display_name) + 27) # incase we go over the max allowable size + em = discord.Embed(color=author.activity.color) + artist_title = f"{author.activity.title} by " + ", ".join( + a for a in author.activity.artists + ) + limit = 256 - ( + len(author.display_name) + 27 + ) # incase we go over the max allowable size em.set_author( name=f"{author.display_name} is currently listening to {artist_title[:limit]}", - icon_url=avatar + icon_url=avatar, ) + em.description = message + "\n" + self._draw_play(author.activity) + # em.set_footer(text=author.activity.duration) + em.set_thumbnail(url=author.activity.album_cover_url) elif state == "streaming": color = int("6441A4", 16) em = discord.Embed(color=color) em.description = message + "\n" + author.activity.url + em.title = getattr(author.activity, "details", None) em.set_author( name=f"{author.display_name} is currently streaming {author.activity.name}", - icon_url=avatar + icon_url=avatar, ) else: em = discord.Embed(color=color) - em.set_author( - name="{} is currently away".format(author.display_name), - icon_url=avatar - ) + em.set_author(name="{} is currently away".format(author.display_name), icon_url=avatar) + if link and state not in ["listening", "gaming"]: + em.set_image(url=link.group(0)) return em async def find_user_mention(self, message): """ Replaces user mentions with their username """ + print(message) for word in message.split(): - if word.startswith("<@") and word.endswith(">"): - mention = word.replace("<@", "").replace(">", "").replace("!", "") - user = await self.bot.get_user_info(int(mention)) - message = message.replace(word, "@" + user.name) + match = re.search(r"<@!?([0-9]+)>", word) + if match: + user = await self.bot.get_user_info(int(match.group(1))) + message = re.sub(match.re, "@" + user.name, message) return message async def make_text_message(self, author, message, state=None): @@ -119,9 +156,12 @@ class Away(BaseCog): author.display_name, author.activity.name, message ) elif state == "listening": - artist_title = f"{author.activity.title} by " + ", ".join(a for a in author.activity.artists) - msg = "{} is currently listening to {} and has set the following message: `{}`".format( - author.display_name, artist_title, message + artist_title = f"{author.activity.title} by " + ", ".join( + a for a in author.activity.artists + ) + currently_playing = self._draw_play(author.activity) + msg = "{} is currently listening to {} and has set the following message: `{}`\n{}".format( + author.display_name, artist_title, message, currently_playing ) elif state == "streaming": msg = "{} is currently streaming at {} and has set the following message: `{}`".format( @@ -131,7 +171,7 @@ class Away(BaseCog): msg = "{} is currently away".format(author.display_name) return msg - async def is_mod_or_admin(self, member:discord.Member): + async def is_mod_or_admin(self, member: discord.Member): guild = member.guild if member == guild.owner: return True @@ -161,7 +201,7 @@ class Away(BaseCog): continue away_msg = await self._away.user(author).MESSAGE() if away_msg: - if type(away_msg) is tuple: + if type(away_msg) in [tuple, list]: # This is just to keep backwards compatibility away_msg, delete_after = away_msg else: @@ -175,11 +215,11 @@ class Away(BaseCog): continue idle_msg = await self._away.user(author).IDLE_MESSAGE() if idle_msg and author.status == discord.Status.idle: - if type(idle_msg) is tuple: + if type(idle_msg) in [tuple, list]: idle_msg, delete_after = idle_msg else: delete_after = None - if message.channel.permissions_for(guild.me).embed_links: + if message.channel.permissions_for(guild.me).embed_links: em = await self.make_embed_message(author, idle_msg, "idle") await message.channel.send(embed=em, delete_after=delete_after) else: @@ -188,11 +228,11 @@ class Away(BaseCog): continue dnd_msg = await self._away.user(author).DND_MESSAGE() if dnd_msg and author.status == discord.Status.dnd: - if type(dnd_msg) is tuple: + if type(dnd_msg) in [tuple, list]: dnd_msg, delete_after = dnd_msg else: delete_after = None - if message.channel.permissions_for(guild.me).embed_links: + if message.channel.permissions_for(guild.me).embed_links: em = await self.make_embed_message(author, dnd_msg, "dnd") await message.channel.send(embed=em, delete_after=delete_after) else: @@ -201,11 +241,11 @@ class Away(BaseCog): continue offline_msg = await self._away.user(author).OFFLINE_MESSAGE() if offline_msg and author.status == discord.Status.offline: - if type(offline_msg) is tuple: + if type(offline_msg) in [tuple, list]: offline_msg, delete_after = offline_msg else: delete_after = None - if message.channel.permissions_for(guild.me).embed_links: + if message.channel.permissions_for(guild.me).embed_links: em = await self.make_embed_message(author, offline_msg, "offline") await message.channel.send(embed=em, delete_after=delete_after) else: @@ -215,7 +255,7 @@ class Away(BaseCog): streaming_msg = await self._away.user(author).STREAMING_MESSAGE() if streaming_msg and type(author.activity) is discord.Streaming: streaming_msg, delete_after = streaming_msg - if message.channel.permissions_for(guild.me).embed_links: + if message.channel.permissions_for(guild.me).embed_links: em = await self.make_embed_message(author, streaming_msg, "streaming") await message.channel.send(embed=em, delete_after=delete_after) else: @@ -225,11 +265,11 @@ class Away(BaseCog): listening_msg = await self._away.user(author).LISTENING_MESSAGE() if listening_msg and type(author.activity) is discord.Spotify: listening_msg, delete_after = listening_msg - if message.channel.permissions_for(guild.me).embed_links: + if message.channel.permissions_for(guild.me).embed_links: em = await self.make_embed_message(author, listening_msg, "listening") await message.channel.send(embed=em, delete_after=delete_after) else: - msg = await self.make_text_message(author, offline_msg, "listening") + msg = await self.make_text_message(author, listening_msg, "listening") await message.channel.send(msg, delete_after=delete_after) continue gaming_msgs = await self._away.user(author).GAME_MESSAGE() @@ -237,17 +277,17 @@ class Away(BaseCog): for game in gaming_msgs: if game in author.activity.name.lower(): game_msg, delete_after = gaming_msgs[game] - if message.channel.permissions_for(guild.me).embed_links: + if message.channel.permissions_for(guild.me).embed_links: em = await self.make_embed_message(author, game_msg, "gaming") await message.channel.send(embed=em, delete_after=delete_after) - break # Let's not accidentally post more than one + break # Let's not accidentally post more than one else: msg = await self.make_text_message(author, game_msg, "gaming") await message.channel.send(msg, delete_after=delete_after) - break + break @commands.command(name="away") - async def away_(self, ctx, delete_after:Optional[int]=None, *, message:str=None): + async def away_(self, ctx, delete_after: Optional[int] = None, *, message: str = None): """ Tell the bot you're away or back. @@ -268,7 +308,7 @@ class Away(BaseCog): await ctx.send(msg) @commands.command(name="idle") - async def idle_(self, ctx, delete_after:Optional[int]=None, *, message:str=None): + async def idle_(self, ctx, delete_after: Optional[int] = None, *, message: str = None): """ Set an automatic reply when you're idle. @@ -289,7 +329,7 @@ class Away(BaseCog): await ctx.send(msg) @commands.command(name="offline") - async def offline_(self, ctx, delete_after:Optional[int]=None, *, message:str=None): + async def offline_(self, ctx, delete_after: Optional[int] = None, *, message: str = None): """ Set an automatic reply when you're offline. @@ -310,7 +350,7 @@ class Away(BaseCog): await ctx.send(msg) @commands.command(name="dnd", aliases=["donotdisturb"]) - async def donotdisturb_(self, ctx, delete_after:Optional[int]=None, *, message:str=None): + async def donotdisturb_(self, ctx, delete_after: Optional[int] = None, *, message: str = None): """ Set an automatic reply when you're dnd. @@ -331,7 +371,7 @@ class Away(BaseCog): await ctx.send(msg) @commands.command(name="streaming") - async def streaming_(self, ctx, delete_after:Optional[int]=None, *, message:str=None): + async def streaming_(self, ctx, delete_after: Optional[int] = None, *, message: str = None): """ Set an automatic reply when you're streaming. @@ -352,7 +392,7 @@ class Away(BaseCog): await ctx.send(msg) @commands.command(name="listening") - async def listening_(self, ctx, delete_after:Optional[int]=None, *, message:str=" "): + async def listening_(self, ctx, delete_after: Optional[int] = None, *, message: str = " "): """ Set an automatic reply when you're listening to Spotify. @@ -366,11 +406,15 @@ class Away(BaseCog): msg = "The bot will no longer reply for you when you're mentioned while listening to Spotify." else: await self._away.user(author).LISTENING_MESSAGE.set((message, delete_after)) - msg = "The bot will now reply for you when you're mentioned while listening to Spotify." + msg = ( + "The bot will now reply for you when you're mentioned while listening to Spotify." + ) await ctx.send(msg) @commands.command(name="gaming") - async def gaming_(self, ctx, game:str, delete_after:Optional[int]=None, *, message:str=None): + async def gaming_( + self, ctx, game: str, delete_after: Optional[int] = None, *, message: str = None + ): """ Set an automatic reply when you're playing a specified game. @@ -419,12 +463,14 @@ class Away(BaseCog): """View your current away settings""" author = ctx.author msg = "" - data = {"MESSAGE":"Away", - "IDLE_MESSAGE":"Idle", - "DND_MESSAGE":"Do not disturb", - "OFFLINE_MESSAGE": "Offline", - "LISTENING_MESSAGE":"Listening", - "STREAMING_MESSAGE": "Streaming"} + data = { + "MESSAGE": "Away", + "IDLE_MESSAGE": "Idle", + "DND_MESSAGE": "Do not disturb", + "OFFLINE_MESSAGE": "Offline", + "LISTENING_MESSAGE": "Listening", + "STREAMING_MESSAGE": "Streaming", + } settings = await self._away.user(author).get_raw() for attr, name in data.items(): if type(settings[attr]) in [tuple, list]: @@ -459,9 +505,10 @@ class Away(BaseCog): msg += f"{game}: {status_msg}\n" if ctx.channel.permissions_for(ctx.me).embed_links: - em = discord.Embed(description = msg[:2048], color = author.color) - em.set_author(name=f"{author.display_name}'s away settings", icon_url=author.avatar_url) + em = discord.Embed(description=msg[:2048], color=author.color) + em.set_author( + name=f"{author.display_name}'s away settings", icon_url=author.avatar_url + ) await ctx.send(embed=em) else: await ctx.send(f"{author.display_name} away settings\n" + msg) -