async def topservers(self, ctx): """See your top servers by XP.""" data = await self.bot.db.execute( """ SELECT guild_id, SUM(h0+h1+h2+h3+h4+h5+h6+h7+h8+h9+h10+h11+h12+h13+h14+h15+h16+h17+h18+h19+h20+h21+h22+h23) as xp FROM user_activity WHERE user_id = %s GROUP BY guild_id ORDER BY xp DESC """, ctx.author.id, ) rows = [] total_xp = 0 for i, (guild_id, xp) in enumerate(data, start=1): guild = self.bot.get_guild(guild_id) if guild is None: guild_name = guild_id else: guild_name = guild.name level = util.get_level(xp) total_xp += xp rows.append(f"`#{i}` **{guild_name}** — Level **{level}**") content = discord.Embed() content.set_author( name= f"Top servers by XP for {util.displayname(ctx.author, escape=False)}", icon_url=ctx.author.avatar_url, ) content.set_footer( text=f"Combined global level {util.get_level(total_xp)}") content.colour = ctx.author.color await util.send_as_pages(ctx, content, rows)
async def activity(self, ctx, user: typing.Optional[discord.Member] = None, scope=""): """See your hourly activity chart (GMT).""" if user is None: user = ctx.author is_global = scope.lower() == "global" if is_global: global_activity = await self.bot.db.execute( """ SELECT h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13,h14,h15,h16,h17,h18,h19,20,h21,h22,h23 FROM user_activity WHERE user_id = %s GROUP BY guild_id """, user.id, ) if global_activity: activity_data = [] for i in range(24): activity_data.append(sum(r[i] for r in global_activity)) xp = sum(activity_data) else: activity_data = [0] * 24 xp = 0 else: activity_data = await self.bot.db.execute( """ SELECT h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13,h14,h15,h16,h17,h18,h19,20,h21,h22,h23 FROM user_activity WHERE user_id = %s AND guild_id = %s """, user.id, ctx.guild.id, one_row=True, ) xp = sum(activity_data) if activity_data else 0 if xp == 0: return ctx.send("No data!") level = util.get_level(xp) title = ( f"LVL {level} | {xp - util.get_xp(level)}/" f"{util.xp_to_next_level(level)} XP to levelup | Total xp: {xp}") await self.bot.loop.run_in_executor( None, lambda: plotter.create_graph( activity_data, str(user.color), title=title)) with open("downloads/graph.png", "rb") as img: await ctx.send( f"`Hourly cumulative {'global' if is_global else 'server'} activity for {user}`", file=discord.File(img), )
async def on_message(self, message): """Listener that gets called on every message.""" if not self.bot.is_ready(): return self.stats_messages += 1 self.bot.cache.event_triggers["message"] += 1 # ignore DMs if message.guild is None: return if message.channel.id in self.bot.cache.votechannels: # votechannels votechannel_type = await self.bot.db.execute( "SELECT voting_type FROM voting_channel WHERE channel_id = %s", message.channel.id, one_value=True, ) if votechannel_type == "rating": for e in ["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣"]: await message.add_reaction(e) elif votechannel_type == "voting": await message.add_reaction(emojis.UPVOTE) await message.add_reaction(emojis.DOWNVOTE) # xp gain message_xp = util.xp_from_message(message) if self.xp_cache.get(str(message.guild.id)) is None: self.xp_cache[str(message.guild.id)] = {} try: self.xp_cache[str(message.guild.id)][str( message.author.id)]["xp"] += message_xp self.xp_cache[str(message.guild.id)][str( message.author.id)]["messages"] += 1 except KeyError: self.xp_cache[str(message.guild.id)][str(message.author.id)] = { "xp": message_xp, "messages": 1, "bot": message.author.bot, } # if bot account, ignore everything after this if message.author.bot: return # announce_levelup = self.bot.cache.levelupmessage.get(str(message.guild.id), False) # disabled for now announce_levelup = False autoresponses = self.bot.cache.autoresponse.get( str(message.guild.id), True) # log emojis unicode_emojis = util.find_unicode_emojis(message.content) custom_emojis = util.find_custom_emojis(message.content) for emoji_name in unicode_emojis: if self.emoji_usage_cache["unicode"].get(str( message.guild.id)) is None: self.emoji_usage_cache["unicode"][str(message.guild.id)] = {} if (self.emoji_usage_cache["unicode"][str(message.guild.id)].get( str(message.author.id)) is None): self.emoji_usage_cache["unicode"][str(message.guild.id)][str( message.author.id)] = {} try: self.emoji_usage_cache["unicode"][str(message.guild.id)][str( message.author.id)][emoji_name] += 1 except KeyError: self.emoji_usage_cache["unicode"][str(message.guild.id)][str( message.author.id)][emoji_name] = 1 for emoji_name, emoji_id in custom_emojis: if self.emoji_usage_cache["custom"].get(str( message.guild.id)) is None: self.emoji_usage_cache["custom"][str(message.guild.id)] = {} if (self.emoji_usage_cache["custom"][str(message.guild.id)].get( str(message.author.id)) is None): self.emoji_usage_cache["custom"][str(message.guild.id)][str( message.author.id)] = {} try: self.emoji_usage_cache["custom"][str(message.guild.id)][str( message.author.id)][str(emoji_id)]["uses"] += 1 except KeyError: self.emoji_usage_cache["custom"][str(message.guild.id)][str( message.author.id)][str(emoji_id)] = { "uses": 1, "name": emoji_name } if autoresponses: await self.easter_eggs(message) # level up message if announce_levelup: activity_data = await self.bot.db.execute( "SELECT * FROM user_activity WHERE user_id = %s AND guild_id = %s", message.author.id, message.guild.id, one_row=True, ) if activity_data: xp = sum(activity_data[3:]) level_before = util.get_level(xp - message_xp) level_now = util.get_level(xp) if level_now > level_before: try: await message.channel.send( f"{message.author.mention} just leveled up! (level **{level_now}**)", delete_after=5, ) except discord.errors.Forbidden: pass
async def profile(self, ctx, user: discord.Member = None): """Your personal customizable user profile.""" if user is None: user = ctx.author badges = [] badge_classes = { "dev": "fab fa-dev", "patreon": "fab fa-patreon", "lastfm": "fab fa-lastfm", "sunsign": "fas fa-sun", "location": "fas fa-compass", "bot": "fas fa-robot", } def get_font_size(username): length = len(username) if length < 15: return "24px" elif length < 20: return "18px" elif length < 25: return "15px" else: return "11px" def make_badge(classname): return f'<li class="badge-container"><i class="corner-logo {classname}"></i></li>' if user.id == self.bot.owner_id: badges.append(make_badge(badge_classes["dev"])) if user.bot: badges.append(make_badge(badge_classes["bot"])) if await queries.is_donator(ctx, user): badges.append(make_badge(badge_classes["patreon"])) user_settings = await self.bot.db.execute( "SELECT lastfm_username, sunsign, location_string FROM user_settings WHERE user_id = %s", user.id, one_row=True, ) if user_settings: if user_settings[0] is not None: badges.append(make_badge(badge_classes["lastfm"])) if user_settings[1] is not None: badges.append(make_badge(badge_classes["sunsign"])) if user_settings[2] is not None: badges.append(make_badge(badge_classes["location"])) server_activity = await self.bot.db.execute( """ SELECT h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13,h14,h15,h16,h17,h18,h19,h20,h21,h22,h23 as xp FROM user_activity WHERE user_id = %s AND guild_id = %s """, user.id, ctx.guild.id, one_row=True, ) server_xp = sum(server_activity) if server_activity else 0 global_activity = await self.bot.db.execute( """ SELECT h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13,h14,h15,h16,h17,h18,h19,h20,h21,h22,h23 as xp FROM user_activity WHERE user_id = %s GROUP BY guild_id """, user.id, ) if global_activity: new_global_activity = [] for i in range(24): new_global_activity.append(sum(r[i] for r in global_activity)) global_xp = sum(new_global_activity) else: new_global_activity = [0] * 24 global_xp = 0 if user.bot: description = "I am a bot<br>BEEP BOOP" else: description = "You should change this by using<br>>editprofile description" profile_data = await self.bot.db.execute( """ SELECT description, background_url, background_color, show_graph FROM user_profile WHERE user_id = %s """, user.id, one_row=True, ) fishy = await self.bot.db.execute( """ SELECT fishy_count FROM fishy WHERE user_id = %s """, user.id, one_value=True, ) if profile_data: description, background_url, background_color, show_graph = profile_data if description is not None: description = bleach.clean( description.replace("\n", "<br>"), tags=bleach.sanitizer.ALLOWED_TAGS + ["br"], ) background_url = background_url or "" background_color = (("#" + background_color) if background_color is not None else user.color) else: background_color = user.color background_url = "" show_graph = True command_uses = await self.bot.db.execute( """ SELECT SUM(uses) FROM command_usage WHERE user_id = %s GROUP BY user_id """, user.id, one_value=True, ) replacements = { "BACKGROUND_IMAGE": background_url, "WRAPPER_CLASS": "custom-bg" if background_url != "" else "", "SIDEBAR_CLASS": "blur" if background_url != "" else "", "OVERLAY_CLASS": "overlay" if background_url != "" else "", "USER_COLOR": background_color, "AVATAR_URL": user.avatar_url_as(size=128, format="png"), "USERNAME": user.name, "DISCRIMINATOR": f"#{user.discriminator}", "DESCRIPTION": description, "FISHY_AMOUNT": fishy or 0, "SERVER_LEVEL": util.get_level(server_xp), "GLOBAL_LEVEL": util.get_level(global_xp), "ACTIVITY_DATA": str(new_global_activity), "CHART_MAX": max(new_global_activity), "COMMANDS_USED": command_uses or 0, "BADGES": "\n".join(badges), "USERNAME_SIZE": get_font_size(user.name), "SHOW_GRAPH": "true" if show_graph else "false", "DESCRIPTION_HEIGHT": "250px" if show_graph else "350px", } payload = { "html": util.format_html(self.profile_html, replacements), "width": 600, "height": 400, "imageFormat": "png", } buffer = await util.render_html(self.bot, payload) await ctx.send( file=discord.File(fp=buffer, filename=f"profile_{user.name}.png"))