import discord import asyncio from .utils.dataIO import dataIO from discord.ext import commands from cogs.utils import checks import os import re class Star: def __init__(self, bot): self.bot = bot self.settings = dataIO.load_json("data/star/settings.json") @commands.group(pass_context=True) @checks.admin_or_permissions(manage_channels=True) async def starboard(self, ctx): """Commands for managing the starboard""" if ctx.invoked_subcommand is None: await self.bot.send_cmd_help(ctx) @starboard.group(pass_context=True, name="role", aliases=["roles"]) async def _roles(self, ctx): """Add or remove roles allowed to add to the starboard""" if ctx.invoked_subcommand is None: await self.bot.send_cmd_help(ctx) async def get_everyone_role(self, server): for role in server.roles: if role.is_everyone: return role async def check_server_emojis(self, server, emoji): server_emoji = None for emojis in server.emojis: if emojis.id in emoji: server_emoji = emojis return server_emoji @starboard.command(pass_context=True, name="setup", aliases=["set"]) async def setup_starboard(self, ctx, channel: discord.Channel=None, emoji="⭐", role:discord.Role=None): """Sets the starboard channel, emoji and role""" server = ctx.message.server if channel is None: channel = ctx.message.channel if "<" in emoji and ">" in emoji: emoji = await self.check_server_emojis(server, emoji) if emoji is None: await self.bot.send_message(ctx.message.channel, "That emoji is not on this server!") return else: emoji = ":" + emoji.name + ":" + emoji.id if role is None: role = await self.get_everyone_role(server) self.settings[server.id] = {"emoji": emoji, "channel": channel.id, "role": [role.id], "threshold": 0, "messages": [], "ignore": []} dataIO.save_json("data/star/settings.json", self.settings) await self.bot.say("Starboard set to {}".format(channel.mention)) @starboard.command(pass_context=True, name="clear") async def clear_post_history(self, ctx): """Clears the database of previous starred messages""" self.settings[ctx.message.server.id]["messages"] = [] dataIO.save_json("data/star/settings.json", self.settings) await self.bot.send_message(ctx.message.channel, "Done! I will no longer track starred messages older than right now.") @starboard.command(pass_context=True, name="ignore") async def toggle_channel_ignore(self, ctx, channel:discord.Channel=None): if channel is None: channel = ctx.message.channel if channel.id in self.settings[ctx.message.server.id]["ignore"]: self.settings[ctx.message.server.id]["ignore"].remove(channel.id) await self.bot.send_message(ctx.message.channel, "{} removed from the ignored channel list!".format(channel.mention)) else: self.settings[ctx.message.server.id]["ignore"].append(channel.id) await self.bot.send_message(ctx.message.channel, "{} added to the ignored channel list!".format(channel.mention)) dataIO.save_json("data/star/settings.json", self.settings) @commands.command(pass_context=True) @checks.admin_or_permissions(manage_messages=True) async def star(self, ctx, msg_id): """Manually add message to the starboard follows same restrictions does not have a threshold""" server = ctx.message.server channel = ctx.message.channel msg = await self.bot.get_message(channel, msg_id) if server.id not in self.settings: return if msg.channel.id in self.settings[server.id]["ignore"]: return if not await self.check_roles(ctx.message.author, msg.author, server): return emoji =self.settings[server.id]["emoji"] threshold = self.settings[server.id]["threshold"] count = await self.get_count(server, msg) if await self.check_is_posted(server, msg): channel = self.bot.get_channel(self.settings[server.id]["channel"]) msg_id, count = await self.get_posted_message(server, msg) if msg_id is not None: msg_edit = await self.bot.get_message(channel, msg_id) await self.bot.edit_message(msg_edit, new_content="{} **#{}**".format(reaction.emoji, count-1)) return # else: channel2 = self.bot.get_channel(id=self.settings[server.id]["channel"]) em = await self.build_embed(msg) post_msg = await self.bot.send_message(channel2, "{} **#{}**".format(emoji, 1), embed=em) past_message_list = self.settings[server.id]["messages"] past_message_list.append({"original_message":msg.id, "new_message":post_msg.id,"count":1}) dataIO.save_json("data/star/settings.json", self.settings) @starboard.command(pass_context=True, name="emoji") async def set_emoji(self, ctx, emoji="⭐"): """Set the emoji for the starboard defaults to ⭐""" server = ctx.message.server if server.id not in self.settings: await self.bot.send_message(ctx.message.channel, "I am not setup for the starboard on this server!\ \nuse starboard set to set it up.") return is_server_emoji = False if "<" in emoji and ">" in emoji: emoji = await self.check_server_emojis(server, emoji) if emoji is None: await self.bot.send_message(ctx.message.channel, "That emoji is not on this server!") return else: is_server_emoji = True emoji = ":" + emoji.name + ":" + emoji.id self.settings[server.id]["emoji"] = emoji dataIO.save_json("data/star/settings.json", self.settings) if is_server_emoji: await self.bot.send_message(ctx.message.channel, "Starboard emoji set to <{}>.".format(emoji)) else: await self.bot.send_message(ctx.message.channel, "Starboard emoji set to {}.".format(emoji)) @starboard.command(pass_context=True, name="channel") async def set_channel(self, ctx, channel:discord.Channel=None): """Set the channel for the starboard""" server = ctx.message.server if server.id not in self.settings: await self.bot.send_message(ctx.message.channel, "I am not setup for the starboard on this server!\ \nuse starboard set to set it up.") return if channel is None: channel = ctx.message.channel self.settings[server.id]["channel"] = channel.id dataIO.save_json("data/star/settings.json", self.settings) await self.bot.send_message(ctx.message.channel, "Starboard channel set to {}.".format(channel.mention)) @starboard.command(pass_context=True, name="threshold") async def set_threshold(self, ctx, threshold: int=0): """Set the threshold before posting to the starboard""" server = ctx.message.server if server.id not in self.settings: await self.bot.send_message(ctx.message.channel, "I am not setup for the starboard on this server!\ \nuse starboard set to set it up.") return self.settings[server.id]["threshold"] = threshold dataIO.save_json("data/star/settings.json", self.settings) await self.bot.send_message(ctx.message.channel, "Starboard threshold set to {}.".format(threshold)) @_roles.command(pass_context=True, name="add") async def add_role(self, ctx, role:discord.Role=None): """Add a role allowed to add messages to the starboard defaults to @everyone""" server = ctx.message.server if server.id not in self.settings: await self.bot.send_message(ctx.message.channel, "I am not setup for the starboard on this server!\ \nuse starboard set to set it up.") return everyone_role = await self.get_everyone_role(server) if role is None: role = everyone_role if role.id in self.settings[server.id]["role"]: await self.bot.send_message(ctx.message.channel, "{} can already add to the starboard!".format(role.name)) return if everyone_role.id in self.settings[server.id]["role"] and role != everyone_role: self.settings[server.id]["role"].remove(everyone_role.id) self.settings[server.id]["role"].append(role.id) dataIO.save_json("data/star/settings.json", self.settings) await self.bot.send_message(ctx.message.channel, "Starboard role set to {}.".format(role.name)) @_roles.command(pass_context=True, name="remove", aliases=["del", "rem"]) async def remove_role(self, ctx, role:discord.Role): """Remove a role allowed to add messages to the starboard""" server = ctx.message.server everyone_role = await self.get_everyone_role(server) if role.id in self.settings[server.id]["role"]: self.settings[server.id]["role"].remove(role.id) if self.settings[server.id]["role"] == []: self.settings[server.id]["role"].append(everyone_role.id) dataIO.save_json("data/star/settings.json", self.settings) await self.bot.send_message(ctx.message.channel, "{} removed from starboard.".format(role.name)) async def check_roles(self, user, author, server): """Checks if the user is allowed to add to the starboard Allows bot owner to always add messages for testing disallows users from adding their own messages""" has_role = False for role in user.roles: if role.id in self.settings[server.id]["role"]: has_role = True if user is author: has_role = False if user.id == self.bot.settings.owner: has_role = True return has_role async def check_is_posted(self, server, message): is_posted = False for past_message in self.settings[server.id]["messages"]: if message.id == past_message["original_message"]: is_posted = True return is_posted async def check_is_added(self, server, message): is_posted = False for past_message in self.settings[server.id]["messages"]: if message.id == past_message["new_message"]: is_posted = True return is_posted async def get_count(self, server, message): count = 0 for past_message in list(self.settings[server.id]["messages"]): if message.id == past_message["original_message"]: count = past_message["count"] return count async def get_posted_message(self, server, message): msg_list = self.settings[server.id]["messages"] for past_message in msg_list: if message.id == past_message["original_message"]: msg = past_message msg_list.remove(msg) msg["count"] += 1 msg_list.append(msg) self.settings[server.id]["messages"] = msg_list dataIO.save_json("data/star/settings.json", self.settings) return msg["new_message"], msg["count"] async def build_embed(self, msg): author = msg.author channel = msg.channel url = "\n\n[Click to see context](https://discordapp.com/channels/{}/{}/{})" url = url.format(msg.server.id, channel.id, msg.id) if msg.embeds != []: embed = msg.embeds[0] # .to_dict() # print(embed) em = discord.Embed(timestamp=msg.timestamp) if "title" in embed: em.title = embed["title"] if "thumbnail" in embed: em.set_thumbnail(url=embed["thumbnail"]["url"]) if "description" in embed: em.description = msg.clean_content + "\n\n" + embed["description"] + url if "description" not in embed: em.description = msg.clean_content + url if "url" in embed: em.url = embed["url"] if "footer" in embed: em.set_footer(text=embed["footer"]["text"]) if "author" in embed: postauthor = embed["author"] if "icon_url" in postauthor: em.set_author(name=postauthor["name"], icon_url=postauthor["icon_url"]) else: em.set_author(name=postauthor["name"]) if "author" not in embed: em.set_author(name=author.name, icon_url=author.avatar_url) if "color" in embed: em.color = embed["color"] if "color" not in embed: if author.bot is True: em.color = discord.Colour(0xff470f) else: em.color = author.top_role.color if "image" in embed: em.set_image(url=embed["image"]["url"]) if embed["type"] == "image": em.type = "image" if ".png" in embed["url"] or ".jpg" in embed["url"]: em.set_thumbnail(url="") em.set_image(url=embed["url"]) else: em.set_thumbnail(url=embed["url"]) em.set_image(url=embed["url"]+"."+embed["thumbnail"]["url"].rsplit(".")[-1]) if embed["type"] == "gifv": em.type = "gifv" em.set_thumbnail(url=embed["url"]) em.set_image(url=embed["url"]+".gif") else: em = discord.Embed(timestamp=msg.timestamp) if author.bot is True: em.color = discord.Colour(0xff470f) else: em.color = author.top_role.color em.description = msg.content + url em.set_author(name=author.display_name, icon_url=author.avatar_url) if msg.attachments != []: em.set_image(url=msg.attachments[0]["url"]) em.set_footer(text='{} | {}'.format(channel.server.name, channel.name)) return em async def on_reaction_add(self, reaction, user): server = reaction.message.server msg = reaction.message if server.id not in self.settings: return if msg.channel.id in self.settings[server.id]["ignore"]: return if not await self.check_roles(user, msg.author, server): return if reaction.message.channel.id == self.settings[server.id]["channel"]: return react =self.settings[server.id]["emoji"] if react in str(reaction.emoji): threshold = self.settings[server.id]["threshold"] count = reaction.count if count is None: count = 0 if await self.check_is_posted(server, msg): channel = self.bot.get_channel(self.settings[server.id]["channel"]) msg_id, count2 = await self.get_posted_message(server, msg) if msg_id is not None: msg_edit = await self.bot.get_message(channel, msg_id) await self.bot.edit_message(msg_edit, new_content="{} **#{}**".format(reaction.emoji, count)) return if count < threshold: store = {"original_message":msg.id, "new_message":None,"count":count} has_message = None for message in self.settings[server.id]["messages"]: if msg.id == message["original_message"]: has_message = message if has_message is not None: self.settings[server.id]["messages"].remove(has_message) self.settings[server.id]["messages"].append(store) dataIO.save_json("data/star/settings.json", self.settings) else: self.settings[server.id]["messages"].append(store) dataIO.save_json("data/star/settings.json", self.settings) return # else: channel2 = self.bot.get_channel(id=self.settings[server.id]["channel"]) em = await self.build_embed(msg) post_msg = await self.bot.send_message(channel2, "{} **#{}**".format(reaction.emoji, count), embed=em) past_message_list = self.settings[server.id]["messages"] past_message_list.append({"original_message":msg.id, "new_message":post_msg.id,"count":count}) dataIO.save_json("data/star/settings.json", self.settings) else: return def check_folder(): if not os.path.exists('data/star'): os.mkdir('data/star') def check_files(): data = {} f = 'data/star/settings.json' if not os.path.exists(f): dataIO.save_json(f, data) def setup(bot): check_folder() check_files() bot.add_cog(Star(bot))