├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── README.md └── Sx4 ├── cogs ├── animals.py ├── antiad.py ├── antilink.py ├── autorole.py ├── economy.py ├── fun.py ├── general.py ├── giveaway.py ├── help.py ├── image.py ├── logs.py ├── mod.py ├── music.py ├── owner.py ├── page.py ├── selfroles.py ├── serverlog.py ├── serverpost.py ├── status.py └── welcomer.py ├── main.py └── utils ├── PagedResult.py ├── arg.py ├── arghelp.py ├── checks.py ├── ctime.py ├── data.py ├── database.py ├── dateify.py └── paged.py /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Device**: 27 | The device you were using at the time of the bug 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # __Sx4__ 2 | 3 | Sx4 is a mutlipurpose bot, this means it can be used for many different purposes making it easier for you to focus your whole server around a few bots. It also has over 210 commands (Over 500 including sub commands) for many different purposes 4 | 5 | __Moderation__ 6 | 7 | Sx4 includes a variety of different moderation commands so you can organize your server to the best ability, it has things such as antilink, antiinvite, selfroles, autorole, a warning system, basic mod commands (mute, kick, ban etc) and so much more! All these things can also be logged in an optional mod-log to keep track of who's been muted, kicked, banned etc. You can also add reasons after the action has happened to make sure they are valid actions! 8 | 9 | __Economy__ 10 | 11 | Sx4 is mainly based around it's economy system with many ways you can make money, you can get daily money where you can build up 12 | streaks as long as you come back everyday to collect your daily money, the higher streak the more chance you have of being 13 | rewarded a crate the higher the streak the higher chance of a better crate and a better reward. You can buy different pickaxes 14 | which can give you a variety of materials at a max of 1 per material as well as some money, pickaxes have durability and always 15 | guarentee profit with the added benefit of materials so the better the pickaxe the better the rewards, another way you can make 16 | money easily is, fishing, by default you can fish and it will give you a random amount between $2 to $15 every 5 minutes as long as 17 | you revisit the command every 5 minutes but you can buy rods with durability which give extra profit per fish so that you can make 18 | extra money at the cost of the rod price. 19 | A really effective way of collecting materials is miners you can buy them using the currency and they 20 | give you a variety of materials but it's not limited to 1 material you can have multiple of the same (miners are stackable) and 21 | then you can also gain materials through using your pickaxe and opening crates. With these materials you can purchase factories 22 | these factories yield you money depending on how hard it is obtaining the factory (factories are also stackable), or you can even 23 | sell your stuff on an online auction house built into the bot where you can also buy items off other users who also use the bot. 24 | You can also get some bonus money by simply voting for the bot to rocket your start in the economy, make sure to vote every 12 25 | hours as it's very profitable in the long run (If you give your referral links to friends you get bonus money just for referring them) and it doubles on weekends due to votes counting as 2 so double the reward! 26 | 27 | __Utility__ 28 | 29 | Sx4 has many utility commands such as commands like serverinfo, userinfo, channelinfo and roleinfo which gives detailed info on the desired user/role/server/channel. There are also commands such as invites which displays how many invites a user has for the current server, their placement for amount of invites and the percent of the server they have invited. This and so much more! 30 | 31 | __Logging__ 32 | 33 | Sx4 can log your server to make sure your server stays safe, it has a very detailed logging system where it logs:
34 | • Deleted messages
35 | • Edited messages
36 | • When a user gets banned
37 | • When a user gets unbanned
38 | • When a user joins/changes/leaves a voice channel
39 | • When a user joins the server
40 | • When a user leaves the server
41 | • When a user gets a role
42 | • When a user is removed from a role
43 | • When a user has a nickname change
44 | • When a user is server muted/deafened in a voice channel
45 | • Permissions updates on a role, shows what perms have been removed/added 46 | 47 | __Welcomer__ 48 | 49 | Sx4 has a welcomer which is highly customizable, you can edit the message it welcomes the user with and even the leave message, or you can just choose for it to be sent to the user's dms which automatically disables the leave message. You also have the option for your message to be displayed in an embed and a image welcomer options with a customizable banner. 50 | 51 | __Music__ 52 | 53 | Sx4 has 18 music commands and is really simple to use all you do is play a song or playlist and as long as you're in a voice channel it'll stream smooth music to your ears for you to enjoy, with commands such as play, search, playlist, seek, rewind, movesong and more you will not be left with little choice. 54 | 55 | __Fun__ 56 | 57 | There are many fun commands on Sx4 to keep you entertained, there are commands such as rock paper scissors which you can play against the bot (the bot logs how many you've won/lost in stats) you can also marry/divorce other users which can be displayed on your very own customizable profile, as well as use google, steam, urbandictionary, steamsearch so you can search for games easily, a randomly generated minesweeper with the new addition of spoilers, google translate and much more! 58 | -------------------------------------------------------------------------------- /Sx4/cogs/animals.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | from utils import checks 4 | from urllib.request import Request, urlopen 5 | import json 6 | import urllib 7 | import requests 8 | 9 | class animals: 10 | def __init__(self, bot, connection): 11 | self.bot = bot 12 | self.db = connection 13 | 14 | @commands.command() 15 | async def catfact(self, ctx): 16 | """Learn cat stuff""" 17 | url = "https://catfact.ninja/fact" 18 | request = Request(url) 19 | data = json.loads(urlopen(request).read().decode()) 20 | s=discord.Embed(description=data["fact"], colour=ctx.message.author.colour) 21 | s.set_author(name="Did you know?") 22 | s.set_thumbnail(url="https://emojipedia-us.s3.amazonaws.com/thumbs/120/twitter/134/cat-face_1f431.png") 23 | await ctx.send(embed=s) 24 | 25 | @commands.command() 26 | async def dog(self, ctx): 27 | """Shows a random dog""" 28 | url = "https://dog.ceo/api/breeds/image/random" 29 | request = Request(url) 30 | request.add_header('User-Agent', 'Mozilla/5.0') 31 | data = json.loads(urlopen(request).read().decode()) 32 | s=discord.Embed(description=":dog:", colour=ctx.message.author.colour) 33 | s.set_image(url=data["message"]) 34 | try: 35 | await ctx.send(embed=s) 36 | except: 37 | await ctx.send("The dog didn't make it, sorry :no_entry:") 38 | 39 | @commands.command() 40 | async def birb(self, ctx): 41 | url = "https://api.alexflipnote.xyz/birb" 42 | try: 43 | response = requests.get(url, timeout=2).json() 44 | except: 45 | return await ctx.send("Request timed out :no_entry:") 46 | s=discord.Embed(description=":bird:", colour=ctx.author.colour) 47 | s.set_image(url=response["file"]) 48 | s.set_footer(text="api.alexflipnote.xyz") 49 | await ctx.send(embed=s) 50 | 51 | @commands.command() 52 | async def cat(self, ctx): 53 | """Shows a random cat""" 54 | try: 55 | response = requests.get("http://aws.random.cat/meow", timeout=2).json() 56 | except: 57 | return await ctx.send("Request timed out :no_entry:") 58 | image = response["file"] 59 | s=discord.Embed(description=":cat:", colour=ctx.message.author.colour) 60 | s.set_image(url=image) 61 | try: 62 | await ctx.send(embed=s) 63 | except: 64 | await ctx.send("The cat didn't make it, sorry :no_entry:") 65 | 66 | @commands.command() 67 | async def duck(self, ctx): 68 | "Shows a random duck" 69 | url = "https://random-d.uk/api/v1/random" 70 | request = Request(url) 71 | request.add_header('User-Agent', 'Mozilla/5.0') 72 | data = json.loads(urlopen(request).read().decode()) 73 | s=discord.Embed(description=":duck:", colour=ctx.message.author.colour) 74 | s.set_image(url=data["url"]) 75 | s.set_footer(text="Powered by random-d.uk") 76 | try: 77 | await ctx.send(embed=s) 78 | except: 79 | await ctx.send("The duck didn't make it, sorry :no_entry:") 80 | 81 | @commands.command() 82 | async def fox(self, ctx): 83 | "Shows a random fox" 84 | url = "https://randomfox.ca/floof/" 85 | request = Request(url) 86 | request.add_header('User-Agent', 'Mozilla/5.0') 87 | data = json.loads(urlopen(request).read().decode()) 88 | s=discord.Embed(description=":fox:", colour=ctx.message.author.colour) 89 | s.set_image(url=data["image"]) 90 | try: 91 | await ctx.send(embed=s) 92 | except: 93 | await ctx.send("The Fox didn't make it, sorry :no_entry:") 94 | 95 | def setup(bot, connection): 96 | bot.add_cog(animals(bot, connection)) -------------------------------------------------------------------------------- /Sx4/cogs/antiad.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | import rethinkdb as r 4 | from utils import checks 5 | from datetime import datetime 6 | from collections import deque, defaultdict 7 | import os 8 | import re 9 | import logging 10 | from cogs import mod 11 | import asyncio 12 | import random 13 | from utils import arghelp, arg 14 | import time 15 | 16 | reinvite = re.compile("(?:[\s \S]|)*(?:https?://)?(?:www.)?(?:discord.gg|(?:canary.)?discordapp.com/invite)/((?:[a-zA-Z0-9]){2,32})(?:[\s \S]|)*", re.IGNORECASE) 17 | 18 | 19 | class antiad: 20 | 21 | def __init__(self, bot, connection): 22 | self.bot = bot 23 | self.db = connection 24 | 25 | @commands.group(usage="") 26 | async def antiinvite(self, ctx): 27 | """Block out those discord invite advertisers""" 28 | server = ctx.guild 29 | if ctx.invoked_subcommand is None: 30 | await arghelp.send(self.bot, ctx) 31 | else: 32 | r.table("antiad").insert({"id": str(server.id), "toggle": False, "modtoggle": True, "admintoggle": False, "bottoggle": True, "baninvites": False, "channels": [], "action": None, "attempts": 3, "users": []}).run(self.db, durability="soft") 33 | 34 | @antiinvite.command() 35 | @checks.has_permissions("manage_guild") 36 | async def toggle(self, ctx): 37 | """Toggle antiinvite on or off""" 38 | server = ctx.guild 39 | data = r.table("antiad").get(str(server.id)) 40 | if data["toggle"].run(self.db, durability="soft") == True: 41 | data.update({"toggle": False}).run(self.db, durability="soft") 42 | await ctx.send("Anti-invite has been **Disabled**") 43 | return 44 | if data["toggle"].run(self.db, durability="soft") == False: 45 | data.update({"toggle": True}).run(self.db, durability="soft") 46 | await ctx.send("Anti-invite has been **Enabled**") 47 | return 48 | 49 | @antiinvite.command() 50 | @checks.has_permissions("manage_guild") 51 | async def banusernames(self, ctx): 52 | """Ban users if they join with an advertising discord link username""" 53 | server = ctx.guild 54 | data = r.table("antiad").get(str(server.id)) 55 | if data["baninvites"].run(self.db, durability="soft") == True: 56 | data.update({"baninvites": False}).run(self.db, durability="soft") 57 | await ctx.send("I will no longer ban users with a discord link as their name.") 58 | return 59 | if data["baninvites"].run(self.db, durability="soft") == False: 60 | data.update({"baninvites": True}).run(self.db, durability="soft") 61 | await ctx.send("I will now ban users with a discord link as their name.") 62 | return 63 | 64 | @antiinvite.command() 65 | @checks.has_permissions("manage_guild") 66 | async def action(self, ctx, action: str): 67 | """Set an action (mute, kick, ban, none) to happen when a user reaches a certain amount of posted invites (defaults at 3 but can be changed using `s?antiinvite attempts `)""" 68 | data = r.table("antiad").get(str(ctx.guild.id)) 69 | if action.lower() in ["none", "off"]: 70 | await ctx.send("Auto mod for antiinvite is now disabled.") 71 | data.update({"action": None}).run(self.db, durability="soft") 72 | elif action.lower() in ["mute", "kick", "ban"]: 73 | await ctx.send("Users who post **{}** {} will now receive a **{}**".format(data["attempts"].run(self.db, durability="soft"), "invite" if data["attempts"].run(self.db, durability="soft") == 1 else "invites", action.lower())) 74 | data.update({"action": action.lower()}).run(self.db, durability="soft") 75 | else: 76 | await ctx.send("That is not a valid action :no_entry:") 77 | 78 | @antiinvite.command() 79 | @checks.has_permissions("manage_guild") 80 | async def attempts(self, ctx, attempts: int): 81 | """Sets the amount of invites which can be sent by a user before an action happens""" 82 | data = r.table("antiad").get(str(ctx.guild.id)) 83 | if attempts < 1: 84 | return await ctx.send("The amount of sent invites needs to be 1 or above :no_entry:") 85 | if attempts > 500: 86 | return await ctx.send("The max amount of attempts is 500 :no_entry:") 87 | if data["action"].run(self.db, durability="soft"): 88 | await ctx.send("Users who post **{}** {} will now receive a **{}**".format(attempts, "invite" if attempts == 1 else "invites", data["action"].run(self.db, durability="soft"))) 89 | else: 90 | await ctx.send("Attempts set to **{}** to make the bot do an action after **{}** {}, use `{}antiinvite action `".format(attempts, attempts, "attempt" if attempts == 1 else "attempts", ctx.prefix)) 91 | data.update({"attempts": attempts}).run(self.db, durability="soft") 92 | 93 | @antiinvite.command(aliases=["reset"]) 94 | async def resetattempts(self, ctx, user: str=None): 95 | """Resets the attempts of a user""" 96 | if not user: 97 | user = ctx.author 98 | else: 99 | user = arg.get_server_member(ctx, user) 100 | if not user: 101 | return await ctx.send("I could not find that user :no_entry:") 102 | data = r.table("antiad").get(str(ctx.guild.id)) 103 | if str(user.id) not in data["users"].map(lambda x: x["id"]).run(self.db, durability="soft"): 104 | return await ctx.send("This user doesn't have any attempts :no_entry:") 105 | else: 106 | if data["users"].filter(lambda x: x["id"] == str(user.id))[0]["attempts"].run(self.db, durability="soft") == 0: 107 | return await ctx.send("This user doesn't have any attempts :no_entry:") 108 | else: 109 | await ctx.send("**{}** attempts have been reset.".format(user)) 110 | data.update({"users": r.row["users"].map(lambda x: r.branch(x["id"] == str(user.id), x.merge({"attempts": 0}), x))}).run(self.db, durability="soft") 111 | 112 | @antiinvite.command() 113 | @checks.has_permissions("manage_guild") 114 | async def modtoggle(self, ctx): 115 | """Choose whether you want your mods to be able to send invites or not (manage_message and above are classed as mods)""" 116 | server = ctx.guild 117 | data = r.table("antiad").get(str(server.id)) 118 | if data["modtoggle"].run(self.db, durability="soft") == True: 119 | data.update({"modtoggle": False}).run(self.db, durability="soft") 120 | await ctx.send("Mods will now not be affected by anti-invite.") 121 | return 122 | if data["modtoggle"].run(self.db, durability="soft") == False: 123 | data.update({"modtoggle": True}).run(self.db, durability="soft") 124 | await ctx.send("Mods will now be affected by anti-invite.") 125 | return 126 | 127 | @antiinvite.command() 128 | @checks.has_permissions("manage_guild") 129 | async def admintoggle(self, ctx): 130 | """Choose whether you want your admins to be able to send invites or not (administrator perms are classed as admins)""" 131 | server = ctx.guild 132 | data = r.table("antiad").get(str(server.id)) 133 | if data["admintoggle"].run(self.db, durability="soft") == True: 134 | data.update({"admintoggle": False}).run(self.db, durability="soft") 135 | await ctx.send("Admins will now not be affected by anti-invite.") 136 | return 137 | if data["admintoggle"].run(self.db, durability="soft") == False: 138 | data.update({"admintoggle": True}).run(self.db, durability="soft") 139 | await ctx.send("Admins will now be affected by anti-invite.") 140 | return 141 | 142 | @antiinvite.command() 143 | @checks.has_permissions("manage_guild") 144 | async def togglebot(self, ctx): 145 | """Choose whether bots can send invites or not""" 146 | server = ctx.guild 147 | data = r.table("antiad").get(str(server.id)) 148 | if data["bottoggle"].run(self.db, durability="soft") == True: 149 | data.update({"bottoggle": False}).run(self.db, durability="soft") 150 | await ctx.send("Bots will now not be affected by anti-invite.") 151 | return 152 | if data["bottoggle"].run(self.db, durability="soft") == False: 153 | data.update({"bottoggle": True}).run(self.db, durability="soft") 154 | await ctx.send("Bots will now be affected by anti-invite.") 155 | return 156 | 157 | @antiinvite.command() 158 | @checks.has_permissions("manage_guild") 159 | async def togglechannel(self, ctx, channel: discord.TextChannel=None): 160 | """Choose what channels you want to count towards antiinvite""" 161 | server = ctx.guild 162 | data = r.table("antiad").get(str(server.id)) 163 | if not channel: 164 | channel = ctx.channel 165 | if str(channel.id) in data["channels"].run(self.db, durability="soft"): 166 | data.update({"channels": r.row["channels"].difference([str(channel.id)])}).run(self.db, durability="soft") 167 | await ctx.send("Anti-invite is now enabled in <#{}>".format(str(channel.id))) 168 | else: 169 | data.update({"channels": r.row["channels"].append(str(channel.id))}).run(self.db, durability="soft") 170 | await ctx.send("Anti-invite is now disabled in <#{}>".format(str(channel.id))) 171 | 172 | @antiinvite.command() 173 | async def stats(self, ctx): 174 | """View the settings of the antiinvite in your server""" 175 | serverid=ctx.guild.id 176 | server=ctx.guild 177 | s=discord.Embed(colour=0xfff90d) 178 | s.set_author(name="Anti-invite Settings", icon_url=self.bot.user.avatar_url) 179 | data = r.table("antiad").get(str(server.id)) 180 | msg = "" 181 | if data["toggle"].run(self.db, durability="soft") == True: 182 | toggle = "Enabled" 183 | else: 184 | toggle = "Disabled" 185 | if data["modtoggle"].run(self.db, durability="soft") == False: 186 | mod = "Mods **Can** send links" 187 | else: 188 | mod = "Mods **Can't** send links" 189 | if data["bottoggle"].run(self.db, durability="soft") == False: 190 | bottoggle = "Bots **Can** send links" 191 | else: 192 | bottoggle = "Bots **Can't** send links" 193 | if data["admintoggle"].run(self.db, durability="soft") == False: 194 | admin = "Admins **Can** send links" 195 | else: 196 | admin = "Admins **Can't** send links" 197 | if data["action"].run(self.db, durability="soft"): 198 | action = "Sending {} {} will result in a {}".format(data["attempts"].run(self.db, durability="soft"), "invite" if data["attempts"].run(self.db, durability="soft") == 1 else "invites", data["action"].run(self.db, durability="soft")) 199 | else: 200 | action = "Disabled" 201 | s.add_field(name="Status", value=toggle) 202 | s.add_field(name="Mod Perms", value=mod) 203 | s.add_field(name="Admin Perms", value=admin) 204 | s.add_field(name="Bots", value=bottoggle) 205 | s.add_field(name="Auto Mod", value=action) 206 | s.add_field(name="Ban Users with Invites in their names", value="Yes" if data["baninvites"].run(self.db) else "No") 207 | for channelid in data["channels"].run(self.db, durability="soft"): 208 | channel = discord.utils.get(server.channels, id=int(channelid)) 209 | msg += channel.mention + "\n" 210 | s.add_field(name="Disabled Channels", value=msg if msg != "" else "None") 211 | await ctx.send(embed=s) 212 | 213 | async def on_member_join(self, member): 214 | server = member.guild 215 | if r.table("antiad").get(str(server.id))["baninvites"].run(self.db) == True: 216 | if reinvite.match(member.name): 217 | try: 218 | invite = await self.bot.get_invite(reinvite.match(member.name).group(1)) 219 | if invite.guild == server: 220 | return 221 | else: 222 | reason = "Invite in username" 223 | action = "Ban (Automatic)" 224 | author = member 225 | await server.ban(member, reason=reason) 226 | await mod._log(self.bot, self.bot.user, server, action, reason, author, self.db) 227 | except: 228 | return 229 | 230 | async def on_message(self, message): 231 | serverid = message.guild.id 232 | server = message.guild 233 | author = message.author 234 | channel = message.channel 235 | data = r.table("antiad").get(str(serverid)) 236 | if not data.run(self.db): 237 | return 238 | if author == self.bot.user: 239 | return 240 | if data["modtoggle"].run(self.db, durability="soft") == False: 241 | if channel.permissions_for(author).manage_messages: 242 | return 243 | if data["admintoggle"].run(self.db, durability="soft") == False: 244 | if channel.permissions_for(author).administrator: 245 | return 246 | if data["bottoggle"].run(self.db, durability="soft") == False: 247 | if author.bot: 248 | return 249 | if str(channel.id) in data["channels"].run(self.db, durability="soft"): 250 | return 251 | if data["toggle"].run(self.db, durability="soft") == True: 252 | if reinvite.match(message.content): 253 | try: 254 | invite = await self.get_invite(reinvite.match(message.content).group(1)) 255 | if "guild" in invite: 256 | if invite["guild"]["id"] == str(server.id): 257 | return 258 | elif "channel" in invite: 259 | pass 260 | else: 261 | return 262 | await message.delete() 263 | msg = "{}, You are not allowed to send invite links here :no_entry:".format(author.mention) 264 | if data["action"].run(self.db, durability="soft"): 265 | if str(author.id) not in data["users"].map(lambda x: x["id"]).run(self.db, durability="soft"): 266 | amount = 1 267 | userdata = {} 268 | userdata["attempts"] = amount 269 | userdata["id"] = str(author.id) 270 | data.update({"users": r.row["users"].append(userdata)}).run(self.db, durability="soft", noreply=True) 271 | else: 272 | amount = data["users"].filter(lambda x: x["id"] == str(author.id))[0]["attempts"].run(self.db, durability="soft") + 1 273 | msg = "{}, You are not allowed to send invite links here, If you continue you will receive a {}. **({}/{})** :no_entry:".format(author.mention, data["action"].run(self.db, durability="soft"), amount, data["attempts"].run(self.db, durability="soft")) 274 | if amount >= data["attempts"].run(self.db, durability="soft"): 275 | if data["action"].run(self.db, durability="soft") == "ban": 276 | try: 277 | reason = "Auto ban (Sent {} invite link(s))".format(data["attempts"].run(self.db, durability="soft")) 278 | await server.ban(author, reason=reason) 279 | msg = "**{}** was banned for sending a total of **{}** {}".format(author, data["attempts"].run(self.db, durability="soft"), "invite" if data["attempts"].run(self.db, durability="soft") == 1 else "invites") 280 | amount = 0 281 | action = "Ban (Automatic)" 282 | except: 283 | msg = "I attempted to ban **{}** for posting too many invite links but it failed, check my role is above the users top role and i have sufficient permissions :no_entry:".format(author) 284 | if data["action"].run(self.db, durability="soft") == "kick": 285 | try: 286 | reason = "Auto kick (Sent {} invite link(s))".format(data["attempts"].run(self.db, durability="soft")) 287 | await server.kick(author, reason=reason) 288 | msg = "**{}** was kicked for sending a total of **{}** {}".format(author, data["attempts"].run(self.db, durability="soft"), "invite" if data["attempts"].run(self.db, durability="soft") == 1 else "invites") 289 | amount = 0 290 | action = "Kick (Automatic)" 291 | except: 292 | msg = "I attempted to kick **{}** for posting too many invite links but it failed, check my role is above the users top role and i have sufficient permissions :no_entry: {}".format(author) 293 | if data["action"].run(self.db, durability="soft") == "mute": 294 | if str(server.id) not in r.table("mute").map(lambda x: x["id"]).run(self.db, durability="soft"): 295 | r.table("mute").insert({"id": str(server.id), "users": []}).run(self.db, durability="soft", noreply=True) 296 | mutedata = r.table("mute").get(str(serverid)) 297 | role = discord.utils.get(server.roles, name="Muted - Sx4") 298 | if not role: 299 | try: 300 | role = await server.create_role(name="Muted - Sx4") 301 | except: 302 | msg = "I was unable to make the mute role therefore i was not able to mute {}, check if i have the manage_roles permission :no_entry:".format(author) 303 | if role: 304 | try: 305 | await author.add_roles(role) 306 | msg = "**{}** was muted for 60 minutes for sending a total of **{}** {}".format(author, data["attempts"].run(self.db, durability="soft"), "invite" if data["attempts"].run(self.db, durability="soft") == 1 else "invites") 307 | action = "Mute (Automatic)" 308 | reason = "Auto mute (Sent {} invite link(s))".format(data["attempts"].run(self.db, durability="soft")) 309 | amount = 0 310 | if str(author.id) not in mutedata["users"].map(lambda x: x["id"]).run(self.db, durability="soft"): 311 | userobj = {} 312 | userobj["id"] = str(author.id) 313 | userobj["toggle"] = True 314 | userobj["amount"] = 3600 315 | userobj["time"] = message.created_at.timestamp() 316 | mutedata.update({"users": r.row["users"].append(userobj)}).run(self.db, durability="soft", noreply=True) 317 | else: 318 | mutedata.update({"users": r.row["users"].map(lambda x: r.branch(x["id"] == str(author.id), x.merge({"time": message.created_at.timestamp(), "amount": 3600, "toggle": True}), x))}).run(self.db, durability="soft", noreply=True) 319 | except: 320 | msg = "I attempted to mute **{}** for posting too many invite links but it failed, check that i have the manage_roles permission and that my role is above the mute role :no_entry:".format(author) 321 | data.update({"users": r.row["users"].map(lambda x: r.branch(x["id"] == str(author.id), x.merge({"attempts": amount}), x))}).run(self.db, durability="soft", noreply=True) 322 | await channel.send(msg) 323 | await mod._log(self.bot, self.bot.user, server, action, reason, author, self.db) 324 | except: 325 | return 326 | 327 | async def on_message_edit(self, before, after): 328 | serverid = before.guild.id 329 | server = before.guild 330 | author = before.author 331 | channel = before.channel 332 | data = r.table("antiad").get(str(serverid)) 333 | if not data.run(self.db): 334 | return 335 | if author == self.bot.user: 336 | return 337 | if data["modtoggle"].run(self.db, durability="soft") == False: 338 | if channel.permissions_for(author).manage_messages: 339 | return 340 | if data["admintoggle"].run(self.db, durability="soft") == False: 341 | if channel.permissions_for(author).administrator: 342 | return 343 | if data["bottoggle"].run(self.db, durability="soft") == False: 344 | if author.bot: 345 | return 346 | if str(channel.id) in data["channels"].run(self.db, durability="soft"): 347 | return 348 | if data["toggle"].run(self.db, durability="soft") == True: 349 | if reinvite.match(after.content): 350 | try: 351 | invite = await self.get_invite(reinvite.match(after.content).group(1)) 352 | if "guild" in invite: 353 | if invite["guild"]["id"] == str(server.id): 354 | return 355 | elif "channel" in invite: 356 | pass 357 | else: 358 | return 359 | await after.delete() 360 | msg = "{}, You are not allowed to send invite links here :no_entry:".format(author.mention) 361 | if data["action"].run(self.db, durability="soft"): 362 | if str(author.id) not in data["users"].map(lambda x: x["id"]).run(self.db, durability="soft"): 363 | amount = 1 364 | userdata = {} 365 | userdata["attempts"] = amount 366 | userdata["id"] = str(author.id) 367 | data.update({"users": r.row["users"].append(userdata)}).run(self.db, durability="soft", noreply=True) 368 | else: 369 | amount = data["users"].filter(lambda x: x["id"] == str(author.id))[0]["attempts"].run(self.db, durability="soft", noreply=True) + 1 370 | msg = "{}, You are not allowed to send invite links here, If you continue you will receive a {}. **({}/{})** :no_entry:".format(author.mention, data["action"].run(self.db, durability="soft"), amount, data["attempts"].run(self.db, durability="soft")) 371 | if amount >= data["attempts"].run(self.db, durability="soft"): 372 | if data["action"].run(self.db, durability="soft") == "ban": 373 | try: 374 | reason = "Auto ban (Sent {} invite link(s))".format(data["attempts"].run(self.db, durability="soft")) 375 | await server.ban(author, reason=reason) 376 | msg = "**{}** was banned for sending a total of **{}** {}".format(author, data["attempts"].run(self.db, durability="soft"), "invite" if data["attempts"].run(self.db, durability="soft") == 1 else "invites") 377 | amount = 0 378 | action = "Ban (Automatic)" 379 | except: 380 | msg = "I attempted to ban **{}** for posting too many invite links but it failed, check my role is above the users top role and i have sufficient permissions :no_entry:".format(author) 381 | if data["action"].run(self.db, durability="soft") == "kick": 382 | try: 383 | reason = "Auto kick (Sent {} invite link(s))".format(data["attempts"].run(self.db, durability="soft")) 384 | await server.kick(author, reason=reason) 385 | msg = "**{}** was kicked for sending a total of **{}** {}".format(author, data["attempts"].run(self.db, durability="soft"), "invite" if data["attempts"].run(self.db, durability="soft") == 1 else "invites") 386 | amount = 0 387 | action = "Kick (Automatic)" 388 | except: 389 | msg = "I attempted to kick **{}** for posting too many invite links but it failed, check my role is above the users top role and i have sufficient permissions :no_entry:".format(author) 390 | if data["action"].run(self.db, durability="soft") == "mute": 391 | if str(server.id) not in r.table("mute").map(lambda x: x["id"]).run(self.db, durability="soft"): 392 | r.table("mute").insert({"id": str(server.id), "users": []}).run(self.db, durability="soft", noreply=True) 393 | mutedata = r.table("mute").get(str(serverid)) 394 | role = discord.utils.get(server.roles, name="Muted - Sx4") 395 | if not role: 396 | try: 397 | role = await server.create_role(name="Muted - Sx4") 398 | except: 399 | msg = "I was unable to make the mute role therefore i was not able to mute {}, check if i have the manage_roles permission :no_entry:".format(author) 400 | if role: 401 | try: 402 | await author.add_roles(role) 403 | msg = "**{}** was muted for 60 minutes for sending a total of **{}** {}".format(author, data["attempts"].run(self.db, durability="soft"), "invite" if data["attempts"].run(self.db, durability="soft") == 1 else "invites") 404 | amount = 0 405 | action = "Mute (Automatic)" 406 | reason = "Auto mute (Sent {} invite link(s))".format(data["attempts"].run(self.db, durability="soft")) 407 | if str(author.id) not in mutedata["users"].map(lambda x: x["id"]).run(self.db, durability="soft"): 408 | userobj = {} 409 | userobj["id"] = str(author.id) 410 | userobj["toggle"] = True 411 | userobj["amount"] = 3600 412 | userobj["time"] = after.edited_at.timestamp() 413 | mutedata.update({"users": r.row["users"].append(userobj)}).run(self.db, durability="soft", noreply=True) 414 | else: 415 | mutedata.update({"users": r.row["users"].map(lambda x: r.branch(x["id"] == str(author.id), x.merge({"time": after.edited_at.timestamp(), "amount": 3600, "toggle": True}), x))}).run(self.db, durability="soft", noreply=True) 416 | except: 417 | msg = "I attempted to mute **{}** for posting too many invite links but it failed, check that i have the manage_roles permission and that my role is above the mute role :no_entry:".format(author) 418 | data.update({"users": r.row["users"].map(lambda x: r.branch(x["id"] == str(author.id), x.merge({"attempts": amount}), x))}).run(self.db, durability="soft", noreply=True) 419 | await channel.send(msg) 420 | mod._log(self.bot, self.bot.user, server, action, reason, author, self.db) 421 | except: 422 | return 423 | 424 | async def get_invite(self, invite): 425 | client = self.bot.http 426 | r = discord.http.Route('GET', '/invite/{invite}?with_counts=true', invite=invite) 427 | return await client.request(r) 428 | 429 | def setup(bot, connection): 430 | bot.add_cog(antiad(bot, connection)) -------------------------------------------------------------------------------- /Sx4/cogs/antilink.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | import rethinkdb as r 4 | from utils import checks 5 | from datetime import datetime 6 | from collections import deque, defaultdict 7 | import os 8 | from utils import arghelp 9 | import re 10 | import logging 11 | import asyncio 12 | import random 13 | import time 14 | 15 | 16 | class antilink: 17 | 18 | def __init__(self, bot, connection): 19 | self.bot = bot 20 | self.db = connection 21 | 22 | @commands.group(usage="") 23 | async def antilink(self, ctx): 24 | """Block out those advertisers""" 25 | server = ctx.guild 26 | if ctx.invoked_subcommand is None: 27 | await arghelp.send(self.bot, ctx) 28 | else: 29 | r.table("antilink").insert({"id": str(server.id), "toggle": False, "modtoggle": True, "admintoggle": False, "bottoggle": True, "channels": []}).run(self.db, durability="soft") 30 | 31 | @antilink.command() 32 | @checks.has_permissions("manage_messages") 33 | async def toggle(self, ctx): 34 | """Toggle antilink on or off""" 35 | server = ctx.guild 36 | data = r.table("antilink").get(str(server.id)) 37 | if data["toggle"].run(self.db, durability="soft") == True: 38 | data.update({"toggle": False}).run(self.db, durability="soft") 39 | await ctx.send("Anti-link has been **Disabled**") 40 | return 41 | if data["toggle"].run(self.db, durability="soft") == False: 42 | data.update({"toggle": True}).run(self.db, durability="soft") 43 | await ctx.send("Anti-link has been **Enabled**") 44 | return 45 | 46 | @antilink.command() 47 | @checks.has_permissions("manage_guild") 48 | async def modtoggle(self, ctx): 49 | """Choose whether you want your mods to be able to send links or not (manage_message and above are classed as mods)""" 50 | server = ctx.guild 51 | data = r.table("antilink").get(str(server.id)) 52 | if data["modtoggle"].run(self.db, durability="soft") == True: 53 | data.update({"modtoggle": False}).run(self.db, durability="soft") 54 | await ctx.send("Mods will now not be affected by anti-link.") 55 | return 56 | if data["modtoggle"].run(self.db, durability="soft") == False: 57 | data.update({"modtoggle": True}).run(self.db, durability="soft") 58 | await ctx.send("Mods will now be affected by anti-link.") 59 | return 60 | 61 | @antilink.command() 62 | @checks.has_permissions("manage_guild") 63 | async def admintoggle(self, ctx): 64 | """Choose whether you want your admins to be able to send links or not (administrator perms are classed as admins)""" 65 | server = ctx.guild 66 | data = r.table("antilink").get(str(server.id)) 67 | if data["admintoggle"].run(self.db, durability="soft") == True: 68 | data.update({"admintoggle": False}).run(self.db, durability="soft") 69 | await ctx.send("Admins will now not be affected by anti-link.") 70 | return 71 | if data["admintoggle"].run(self.db, durability="soft") == False: 72 | data.update({"admintoggle": True}).run(self.db, durability="soft") 73 | await ctx.send("Admins will now be affected by anti-link.") 74 | return 75 | 76 | @antilink.command() 77 | @checks.has_permissions("manage_guild") 78 | async def togglebot(self, ctx): 79 | """Choose whether bots can send links or not""" 80 | server = ctx.guild 81 | data = r.table("antilink").get(str(server.id)) 82 | if data["bottoggle"].run(self.db, durability="soft") == True: 83 | data.update({"bottoggle": False}).run(self.db, durability="soft") 84 | await ctx.send("Bots will now not be affected by anti-link.") 85 | return 86 | if data["bottoggle"].run(self.db, durability="soft") == False: 87 | data.update({"bottoggle": True}).run(self.db, durability="soft") 88 | await ctx.send("Bots will now be affected by anti-link.") 89 | return 90 | 91 | @antilink.command() 92 | @checks.has_permissions("manage_guild") 93 | async def togglechannel(self, ctx, channel: discord.TextChannel=None): 94 | """Choose what channels you want to count towards antilink""" 95 | server = ctx.guild 96 | data = r.table("antilink").get(str(server.id)) 97 | if not channel: 98 | channel = ctx.channel 99 | if str(channel.id) in data["channels"].run(self.db, durability="soft"): 100 | data.update({"channels": r.row["channels"].difference([str(channel.id)])}).run(self.db, durability="soft") 101 | await ctx.send("Anti-link is now enabled in <#{}>".format(str(channel.id))) 102 | return 103 | else: 104 | data.update({"channels": r.row["channels"].append(str(channel.id))}).run(self.db, durability="soft") 105 | await ctx.send("Anti-link is now disabled in <#{}>".format(str(channel.id))) 106 | return 107 | 108 | @antilink.command() 109 | async def stats(self, ctx): 110 | """View the settings of the antilink in your server""" 111 | serverid=ctx.guild.id 112 | server=ctx.guild 113 | data = r.table("antilink").get(str(server.id)) 114 | s=discord.Embed(colour=0xfff90d) 115 | s.set_author(name="Anti-link Settings", icon_url=self.bot.user.avatar_url) 116 | msg = "" 117 | if data["toggle"].run(self.db, durability="soft") == True: 118 | toggle = "Enabled" 119 | else: 120 | toggle = "Disabled" 121 | if data["modtoggle"].run(self.db, durability="soft") == False: 122 | mod = "Mods **Can** send links" 123 | else: 124 | mod = "Mods **Can't** send links" 125 | if data["bottoggle"].run(self.db, durability="soft") == False: 126 | bottoggle = "Bots **Can** send links" 127 | else: 128 | bottoggle = "Bots **Can't** send links" 129 | if data["admintoggle"].run(self.db, durability="soft") == False: 130 | admin = "Admins **Can** send links" 131 | else: 132 | admin = "Admins **Can't** send links" 133 | s.add_field(name="Status", value=toggle) 134 | s.add_field(name="Mod Perms", value=mod) 135 | s.add_field(name="Admin Perms", value=admin) 136 | s.add_field(name="Bots", value=bottoggle) 137 | for channelid in data["channels"].run(self.db, durability="soft"): 138 | channel = discord.utils.get(server.channels, id=int(channelid)) 139 | if channel: 140 | msg += channel.mention + "\n" 141 | s.add_field(name="Disabled Channels", value=msg if msg != "" else "None") 142 | await ctx.send(embed=s) 143 | 144 | 145 | async def on_message(self, message): 146 | serverid = message.guild.id 147 | author = message.author 148 | channel = message.channel 149 | data = r.table("antilink").get(str(serverid)) 150 | if data["modtoggle"].run(self.db, durability="soft") == False: 151 | if channel.permissions_for(author).manage_messages: 152 | return 153 | if data["admintoggle"].run(self.db, durability="soft") == False: 154 | if channel.permissions_for(author).administrator: 155 | return 156 | if data["bottoggle"].run(self.db, durability="soft") == False: 157 | if author.bot: 158 | return 159 | if str(channel.id) in data["channels"].run(self.db, durability="soft"): 160 | return 161 | if data["toggle"].run(self.db, durability="soft") == True: 162 | if ("http://" in message.content.lower()) or ("https://" in message.content.lower()): 163 | await message.delete() 164 | await channel.send("{}, You are not allowed to send links here :no_entry:".format(author.mention)) 165 | 166 | async def on_message_edit(self, before, after): 167 | serverid = before.guild.id 168 | author = before.author 169 | channel = before.channel 170 | data = r.table("antilink").get(str(serverid)) 171 | if data["modtoggle"].run(self.db, durability="soft") == False: 172 | if channel.permissions_for(author).manage_messages: 173 | return 174 | if data["admintoggle"].run(self.db, durability="soft") == False: 175 | if channel.permissions_for(author).administrator: 176 | return 177 | if data["bottoggle"].run(self.db, durability="soft") == False: 178 | if author.bot: 179 | return 180 | if str(channel.id) in data["channels"].run(self.db, durability="soft"): 181 | return 182 | if data["toggle"].run(self.db, durability="soft") == True: 183 | if ("http://" in after.content.lower()) or ("https://" in after.content.lower()): 184 | await after.delete() 185 | await channel.send("{}, You are not allowed to send links here :no_entry:".format(author.mention)) 186 | 187 | def setup(bot, connection): 188 | bot.add_cog(antilink(bot, connection)) -------------------------------------------------------------------------------- /Sx4/cogs/autorole.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | from utils import checks 4 | import datetime 5 | from collections import deque, defaultdict 6 | import os 7 | import re 8 | import logging 9 | import rethinkdb as r 10 | import asyncio 11 | import random 12 | import time 13 | from utils import arghelp, arg 14 | import discord 15 | from discord.ext import commands 16 | from random import randint 17 | from random import choice as randchoice 18 | from discord.ext.commands import CommandNotFound 19 | 20 | 21 | class autorole: 22 | def __init__(self, bot, connection): 23 | self.bot = bot 24 | self.db = connection 25 | 26 | @commands.group(usage="") 27 | async def autorole(self, ctx): 28 | """Allows a role to be added to a user when they join the server""" 29 | server = ctx.guild 30 | if ctx.invoked_subcommand is None: 31 | await arghelp.send(self.bot, ctx) 32 | else: 33 | r.table("autorole").insert({"id": str(server.id), "role": None, "toggle": False, "botrole": None}).run(self.db, durability="soft") 34 | 35 | @autorole.command() 36 | @checks.has_permissions("manage_roles") 37 | async def role(self, ctx, *, role: str): 38 | """Set the role to be added to a user when they join""" 39 | server = ctx.guild 40 | role = arg.get_role(ctx, role) 41 | if not role: 42 | return await ctx.send("I could not find that role :no_entry:") 43 | r.table("autorole").get(str(server.id)).update({"role": str(role.id)}).run(self.db, durability="soft") 44 | await ctx.send("The autorole role is now **{}** <:done:403285928233402378>".format(role.name)) 45 | 46 | @autorole.command() 47 | @checks.has_permissions("manage_roles") 48 | async def botrole(self, ctx, *, role: str): 49 | """Set the role to be added to a bot when it joins""" 50 | server = ctx.guild 51 | role = arg.get_role(ctx, role) 52 | if not role: 53 | return await ctx.send("I could not find that role :no_entry:") 54 | r.table("autorole").get(str(server.id)).update({"botrole": str(role.id)}).run(self.db, durability="soft") 55 | await ctx.send("The autorole bot role is now **{}** <:done:403285928233402378>".format(role.name)) 56 | 57 | @autorole.command() 58 | @commands.cooldown(1, 360, commands.BucketType.guild) 59 | @checks.has_permissions("manage_roles") 60 | async def fix(self, ctx): 61 | """Has the bot been offline and missed a few users? Use this to add the role to everyone who doesn't have it""" 62 | server = ctx.guild 63 | data = r.table("autorole").get(str(server.id)).run(self.db) 64 | if not data: 65 | return await ctx.send("You need to set the autorole before you can use this :no_entry:") 66 | if not data["role"]: 67 | return await ctx.send("You need to set the autorole before you can use this :no_entry:") 68 | role = ctx.guild.get_role(int(data["role"])) 69 | if not role: 70 | return await ctx.send("The auto role which is set was deleted or no longer exists :no_entry:") 71 | if data["botrole"]: 72 | botrole = ctx.guild.get_role(int(data["botrole"])) 73 | else: 74 | botrole = data["botrole"] 75 | members = [x for x in ctx.guild.members if not x.bot and role not in x.roles] if botrole else [x for x in ctx.guild.members if role not in x.roles] 76 | bots = [x for x in ctx.guild.members if x.bot and botrole not in x.roles] 77 | added_users, added_bots = 0, 0 78 | if botrole: 79 | for bot in bots: 80 | try: 81 | await bot.add_roles(botrole, reason="Autorole fix") 82 | added_bots += 1 83 | except: 84 | pass 85 | for user in members: 86 | try: 87 | await user.add_roles(role, reason="Autorole fix") 88 | added_users += 1 89 | except: 90 | pass 91 | user_msg = ", I was unable to add the role to **{}** users".format(len(members) - added_users) 92 | bot_msg = ", I was unable to add the role to **{}** bots".format(len(bots) - added_bots) 93 | await ctx.send("Added **{}** to **{}** users{}\n{}".format(role.name, added_users, user_msg if len(members) != added_users else "", "Added **{}** to **{}** bots{}".format(botrole.name, added_bots, bot_msg if len(bots) != added_bots else "") if botrole else "")) 94 | 95 | @autorole.command() 96 | @checks.has_permissions("manage_roles") 97 | async def toggle(self, ctx): 98 | """Toggle autorole on or off""" 99 | server = ctx.guild 100 | data = r.table("autorole").get(str(server.id)) 101 | if data["toggle"].run(self.db, durability="soft") == True: 102 | data.update({"toggle": False}).run(self.db, durability="soft") 103 | await ctx.send("Auto-role has been **Disabled**") 104 | return 105 | if data["toggle"].run(self.db, durability="soft") == False: 106 | data.update({"toggle": True}).run(self.db, durability="soft") 107 | await ctx.send("Auto-role has been **Enabled**") 108 | return 109 | 110 | @autorole.command() 111 | async def stats(self, ctx): 112 | """View the settings of autorole on your server""" 113 | server = ctx.guild 114 | data = r.table("autorole").get(str(server.id)).run(self.db) 115 | s=discord.Embed(colour=0xfff90d) 116 | s.set_author(name="Auto-role Settings", icon_url=self.bot.user.avatar_url) 117 | if data["toggle"] == True: 118 | toggle = "Enabled" 119 | else: 120 | toggle = "Disabled" 121 | s.add_field(name="Status", value=toggle) 122 | if not data["role"]: 123 | s.add_field(name="Auto-role role", value="Not set") 124 | else: 125 | s.add_field(name="Auto-role role", value=ctx.guild.get_role(int(data["role"])).mention if ctx.guild.get_role(int(data["role"])) else "Not set") 126 | if data["botrole"]: 127 | s.add_field(name="Auto-role bot role", value=ctx.guild.get_role(int(data["botrole"])).mention if ctx.guild.get_role(int(data["botrole"])) else "Not set") 128 | else: 129 | s.add_field(name="Auto-role bot role", value="Not set") 130 | await ctx.send(embed=s) 131 | 132 | async def on_member_join(self, member): 133 | server = member.guild 134 | data = r.table("autorole").get(str(server.id)).run(self.db) 135 | role = server.get_role(int(data["role"])) 136 | if data["toggle"] == True: 137 | if member.bot: 138 | if data["botrole"]: 139 | botrole = server.get_role(int(data["botrole"])) 140 | if botrole: 141 | await member.add_roles(botrole, reason="Autorole") 142 | else: 143 | await member.add_roles(role, reason="Autorole") 144 | else: 145 | await member.add_roles(role, reason="Autorole") 146 | else: 147 | await member.add_roles(role, reason="Autorole") 148 | 149 | def setup(bot, connection): 150 | bot.add_cog(autorole(bot, connection)) -------------------------------------------------------------------------------- /Sx4/cogs/giveaway.py: -------------------------------------------------------------------------------- 1 | import discord 2 | import asyncio 3 | from discord.ext import commands 4 | from random import choice as randchoice 5 | import time 6 | import datetime 7 | import html 8 | import random 9 | import math 10 | from utils import arghelp 11 | from PIL import Image, ImageFilter, ImageEnhance 12 | import psutil 13 | from datetime import datetime, timedelta 14 | from utils import checks 15 | import psutil 16 | from urllib.request import Request, urlopen 17 | import json 18 | import urllib 19 | import re 20 | import traceback 21 | from utils import ctime, arg 22 | import os 23 | from random import choice 24 | from threading import Timer 25 | import requests 26 | import rethinkdb as r 27 | from random import randint 28 | from copy import deepcopy 29 | from collections import namedtuple, defaultdict, deque 30 | from copy import deepcopy 31 | from enum import Enum 32 | import asyncio 33 | from difflib import get_close_matches 34 | 35 | class giveaway: 36 | def __init__(self, bot, connection): 37 | self.bot = bot 38 | self.db = connection 39 | self._giveaway_task = bot.loop.create_task(self.check_giveaway()) 40 | 41 | def __unload(self): 42 | self._giveaway_task.cancel() 43 | 44 | @commands.group(usage="") 45 | async def giveaway(self, ctx): 46 | server = ctx.guild 47 | if ctx.invoked_subcommand is None: 48 | await arghelp.send(self.bot, ctx) 49 | else: 50 | r.table("giveaway").insert({"id": str(server.id), "giveaway#": 0, "giveaways": []}).run(self.db, durability="soft") 51 | 52 | @giveaway.command() 53 | async def end(self, ctx, giveaway_id: int): 54 | serverdata = r.table("giveaway").get(str(ctx.guild.id)) 55 | try: 56 | await self.determine_giveaway(serverdata, giveaway_id) 57 | except Exception as e: 58 | await ctx.send(e.args[0]) 59 | 60 | @giveaway.command() 61 | async def reroll(self, ctx, message_id: int, winners: int=None): 62 | users = [] 63 | if not winners: 64 | winners = 1 65 | try: 66 | message = await ctx.channel.get_message(message_id) 67 | except: 68 | return await ctx.send("Make sure you are re-rolling in the same channel as the giveaway message and that the ID is correct :no_entry:") 69 | if message.author != self.bot.user: 70 | return await ctx.send("Make sure the message id is a giveaway message :no_entry:") 71 | try: 72 | if message.embeds[0].footer.text == "Giveaway Ended": 73 | try: 74 | regex = re.match("\*\*(.*)\*\* has won \*\*(.*)\*\*", message.embeds[0].description).group(1) 75 | if regex: 76 | for x in regex.split(", "): 77 | user = discord.utils.get(ctx.guild.members, name=x.split("#")[0], discriminator=x.split("#")[1]) 78 | if user: 79 | users.append(user) 80 | else: 81 | return await ctx.send("That's not a giveaway message :no_entry:") 82 | except: 83 | return await ctx.send("That's not a giveaway message :no_entry:") 84 | else: 85 | return await ctx.send("The giveaway has not finished yet :no_entry:") 86 | except: 87 | return await ctx.send("That's not a giveaway message :no_entry:") 88 | try: 89 | reaction = list(filter(lambda x: x.emoji == "🎉", message.reactions))[0] 90 | except: 91 | return await ctx.send("This message has no :tada: reactions :no_entry:") 92 | try: 93 | winner = random.sample([x for x in await reaction.users().flatten() if x != self.bot.user and x not in users], k=winners) 94 | except: 95 | try: 96 | winner = random.sample([x for x in await reaction.users().flatten() if x != self.bot.user and x not in users], k=len([x for x in await reaction.users().flatten() if x != self.bot.user])) 97 | except: 98 | return await ctx.send("Not enough people reacted on the message to get a new winner :no_entry:") 99 | await ctx.send("The new {} {}, Congratulations :tada:".format("winner is" if len(winner) == 1 else "winners are", ", ".join([x.mention for x in winner]))) 100 | 101 | @giveaway.command() 102 | @checks.has_permissions("manage_roles") 103 | async def delete(self, ctx, giveaway_id: int): 104 | """delete a giveaway""" 105 | server = ctx.guild 106 | serverdata = r.table("giveaway").get(str(server.id)) 107 | giveaway = serverdata["giveaways"].filter(lambda x: x["id"] == giveaway_id).run(self.db) 108 | if not giveaway: 109 | return await ctx.send("That giveaway ID does not exist :no_entry:") 110 | else: 111 | giveaway = giveaway[0] 112 | channel = ctx.guild.get_channel(int(giveaway["channel"])) 113 | if channel: 114 | try: 115 | message = await channel.get_message(int(giveaway["message"])) 116 | try: 117 | await message.delete() 118 | except: 119 | pass 120 | except discord.errors.NotFound: 121 | pass 122 | serverdata.update({"giveaways": r.row["giveaways"].filter(lambda x: x["id"] != giveaway_id)}).run(self.db, durability="soft") 123 | await ctx.send("That giveaway has been cancelled and deleted.") 124 | 125 | @giveaway.command() 126 | @checks.has_permissions("manage_roles") 127 | async def setup(self, ctx, channel: str=None, winners: int=None, duration: str=None, *, giveaway_item: str=None): 128 | """Setup a giveaway, minimum time 120 seconds""" 129 | giveaway = {} 130 | server = ctx.guild 131 | serverdata = r.table("giveaway").get(str(server.id)) 132 | if channel and duration and giveaway_item and winners: 133 | title = "Giveaway" 134 | else: 135 | def checkchar(m): 136 | return m.channel == ctx.channel and m.author == ctx.author and len(m.content) <= 256 137 | def check(m): 138 | return m.channel == ctx.channel and m.author == ctx.author and len(m.content) <= 2000 139 | def check_winner(m): 140 | return m.channel == ctx.channel and m.author == ctx.author and m.content.isdigit() 141 | def check_time(m): 142 | if m.channel == ctx.channel and m.author == ctx.author: 143 | if m.content.lower() == "cancel": 144 | return True 145 | else: 146 | try: 147 | seconds = ctime.convert(m.content.lower()) 148 | except ValueError: 149 | return False 150 | if seconds >= 120 and seconds <= 31556926: 151 | return True 152 | def check_channel(m): 153 | if m.channel == ctx.channel and m.author == ctx.author: 154 | if m.content.lower() == "cancel": 155 | return True 156 | channel = arg.get_text_channel(ctx, m.content) 157 | if channel: 158 | return True 159 | if not channel: 160 | await ctx.send("What channel would you like me to start this giveaway? Type \"cancel\" at anytime to cancel the creation (Respond below)") 161 | try: 162 | channel = await self.bot.wait_for("message", check=check_channel, timeout=300) 163 | if channel.content.lower() == "cancel": 164 | await ctx.send("Cancelled") 165 | return 166 | channel = channel.content 167 | except asyncio.TimeoutError: 168 | await ctx.send("Timed out :stopwatch:") 169 | return 170 | except asyncio.TimeoutError: 171 | await ctx.send("Timed out :stopwatch:") 172 | return 173 | await ctx.send("What do you want to name your giveaway? (Respond below)") 174 | try: 175 | title = await self.bot.wait_for("message", check=checkchar, timeout=300) 176 | if title.content.lower() == "cancel": 177 | await ctx.send("Cancelled") 178 | return 179 | title = title.content 180 | except asyncio.TimeoutError: 181 | await ctx.send("Timed out :stopwatch:") 182 | return 183 | if not winners: 184 | await ctx.send("How many winners would you like? (Respond below)") 185 | try: 186 | winners = await self.bot.wait_for("message", check=check_winner, timeout=300) 187 | if winners.content.lower() == "cancel": 188 | await ctx.send("Cancelled") 189 | return 190 | winners = int(winners.content) 191 | except asyncio.TimeoutError: 192 | await ctx.send("Timed out :stopwatch:") 193 | return 194 | if not duration: 195 | await ctx.send("How long do you want your giveaway to last? (After the numerical value add 'd' for days, 'h' for hours, 'm' for minutes, 's' for seconds) Minimum time: 2 minutes. (Respond below)") 196 | try: 197 | time2 = await self.bot.wait_for("message", check=check_time, timeout=300) 198 | if time2.content.lower() == "cancel": 199 | await ctx.send("Cancelled") 200 | return 201 | duration = time2.content 202 | except asyncio.TimeoutError: 203 | await ctx.send("Timed out :stopwatch:") 204 | return 205 | if not giveaway_item: 206 | await ctx.send("What are you giving away? (Respond below)") 207 | try: 208 | item = await self.bot.wait_for("message", check=check, timeout=300) 209 | if item.content.lower() == "cancel": 210 | await ctx.send("Cancelled") 211 | return 212 | giveaway_item = item.content 213 | except asyncio.TimeoutError: 214 | await ctx.send("Timed out :stopwatch:") 215 | return 216 | 217 | serverdata.update({"giveaway#": r.row["giveaway#"] + 1}).run(self.db, durability="soft") 218 | id = serverdata["giveaway#"].run(self.db, durability="soft") 219 | channel = arg.get_text_channel(ctx, channel) 220 | if not channel: 221 | return await ctx.send("I could not find that channel :no_entry:") 222 | try: 223 | giveaway_seconds = ctime.convert(duration) 224 | except ValueError: 225 | return await ctx.send("Invalid duration format :no_entry:") 226 | if giveaway_seconds < 120: 227 | return await ctx.send("Giveaways have to be at least 2 minutes long :no_entry:") 228 | starttime = datetime.utcnow().timestamp() 229 | endtime = datetime.utcnow().timestamp() + giveaway_seconds 230 | s=discord.Embed(title=title, description="Enter by reacting with :tada:\n\nThis giveaway is for **{}**\nDuration: **{}**\nWinners: **{}**".format(giveaway_item, self.giveaway_time(starttime, endtime), winners), timestamp=datetime.fromtimestamp(datetime.utcnow().timestamp() + giveaway_seconds)) 231 | s.set_footer(text="Ends") 232 | message = await channel.send(embed=s) 233 | await message.add_reaction("🎉") 234 | giveaway["title"] = title 235 | giveaway["endtime"] = datetime.utcnow().timestamp() + giveaway_seconds 236 | giveaway["length"] = giveaway_seconds 237 | giveaway["item"] = giveaway_item 238 | giveaway["channel"] = str(channel.id) 239 | giveaway["message"] = str(message.id) 240 | giveaway["winners"] = winners 241 | giveaway["id"] = id 242 | serverdata.update({"giveaways": r.row["giveaways"].append(giveaway)}).run(self.db, durability="soft") 243 | await ctx.send("Your giveaway has been created :tada:\nGiveaway ID: `{}` (This can be used to delete and end giveaways)".format(id)) 244 | 245 | async def check_giveaway(self): 246 | while not self.bot.is_closed(): 247 | try: 248 | data = r.table("giveaway") 249 | for sdata in data.run(self.db, durability="soft"): 250 | serverdata = data.get(sdata["id"]) 251 | for x in sdata["giveaways"]: 252 | if x["endtime"] <= datetime.utcnow().timestamp(): 253 | try: 254 | await self.determine_giveaway(serverdata, x["id"]) 255 | except: 256 | serverdata.update({"giveaways": r.row["giveaways"].filter(lambda y: y["id"] != x["id"])}).run(self.db, durability="soft", noreply=True) 257 | except Exception as e: 258 | await self.bot.get_channel(344091594972069888).send(e) 259 | await asyncio.sleep(60) 260 | 261 | async def determine_giveaway(self, guild_data, giveaway_id): 262 | guild = self.bot.get_guild(int(guild_data["id"].run(self.db))) 263 | message_data = guild_data["giveaways"].filter(lambda x: x["id"] == giveaway_id).run(self.db) 264 | if not message_data: 265 | raise ValueError("Invalid giveaway ID :no_entry:") 266 | message_data = message_data[0] 267 | channel = guild.get_channel(int(message_data["channel"])) 268 | if channel is None: 269 | raise ValueError("The channel in which that giveaway was hosted has been deleted :no_entry:") 270 | try: 271 | message = await channel.get_message(int(message_data["message"])) 272 | except discord.errors.NotFound as e: 273 | raise discord.errors.NotFound(e.response, "The message in the giveaway no longer exists :no_entry:") 274 | try: 275 | reaction = [x for x in message.reactions if x.emoji == "🎉"][0] 276 | except IndexError: 277 | raise IndexError("There are not any :tada: reactions on that message :no_entry:") 278 | winner = random.sample([x for x in await reaction.users().flatten() if x != self.bot.user], k=min(len([x for x in await reaction.users().flatten() if x != self.bot.user]), message_data["winners"])) 279 | if winner == []: 280 | await channel.send("No one entered the giveaway :no_entry:") 281 | await message.delete() 282 | guild_data.update({"giveaways": r.row["giveaways"].filter(lambda y: y["id"] != message_data["id"])}).run(self.db, durability="soft", noreply=True) 283 | return 284 | s=discord.Embed(title=message_data["title"], description="**{}** has won **{}**".format(", ".join([str(x) for x in winner]), message_data["item"])) 285 | s.set_footer(text="Giveaway Ended") 286 | await message.edit(embed=s) 287 | await channel.send("{}, Congratulations you won the giveaway for **{}**".format(", ".join([x.mention for x in winner]), message_data["item"])) 288 | guild_data.update({"giveaways": r.row["giveaways"].filter(lambda y: y["id"] != message_data["id"])}).run(self.db, durability="soft", noreply=True) 289 | 290 | 291 | def giveaway_time(self, starttime, endtime): 292 | m, s = divmod(endtime - starttime, 60) 293 | h, m = divmod(m, 60) 294 | d, h = divmod(h, 24) 295 | if d == 1: 296 | days = "day" 297 | else: 298 | days = "days" 299 | if h == 1: 300 | hours = "hour" 301 | else: 302 | hours = "hours" 303 | if m == 1: 304 | minutes = "minute" 305 | else: 306 | minutes = "minutes" 307 | if s == 1: 308 | seconds = "seconds" 309 | else: 310 | seconds = "seconds" 311 | duration = ("%d %s " % (d, days) if d != 0 else "") + ("%d %s " % (h, hours) if h != 0 else "") + ("%d %s " % (m, minutes) if m != 0 else "") + ("%d %s " % (s, seconds) if s >= 1 else "") 312 | return duration 313 | 314 | def setup(bot, connection): 315 | bot.add_cog(giveaway(bot, connection)) -------------------------------------------------------------------------------- /Sx4/cogs/help.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | import os 4 | from copy import deepcopy 5 | from collections import namedtuple, defaultdict, deque 6 | from datetime import datetime 7 | from random import randint 8 | from copy import deepcopy 9 | import inspect 10 | from utils import checks 11 | from enum import Enum 12 | import time 13 | import logging 14 | import datetime 15 | import math 16 | from urllib.request import Request, urlopen 17 | import json 18 | from utils.PagedResult import PagedResult 19 | from utils.PagedResult import PagedResultData 20 | import random 21 | from random import choice 22 | import asyncio 23 | from difflib import get_close_matches 24 | 25 | class help: 26 | """help command""" 27 | 28 | def __init__(self, bot, connection): 29 | self.bot = bot 30 | self.db = connection 31 | 32 | @commands.command() 33 | async def help(self, ctx, commandname=None, *, subcommand=None): 34 | if not commandname and not subcommand: 35 | cogs = list(self.bot.cogs) 36 | economy = cogs.index("economy") 37 | cogs[0], cogs[economy] = cogs[economy], cogs[0] 38 | s=discord.Embed(colour=0xffff00) 39 | s.set_footer(text="s?help for more info", icon_url=ctx.message.author.avatar_url) 40 | for cog in cogs: 41 | commands = ", ".join(sorted(["`" + command + "`" for command in self.bot.cogs[cog].bot.all_commands if self.bot.all_commands[command].module[5:].lower() == cog.lower() and self.bot.all_commands[command].hidden == False and command not in self.bot.all_commands[command].aliases], key=lambda x: x.lower())) 42 | commandsnum = len([x for x in self.bot.all_commands if self.bot.all_commands[x].hidden == False and x not in self.bot.all_commands[x].aliases]) 43 | cogsnum = len([x for x in self.bot.all_commands if self.bot.all_commands[x].module[5:].lower() == cog.lower() and self.bot.all_commands[x].hidden == False and x not in self.bot.all_commands[x].aliases]) 44 | s.set_author(name="Help ({} Commands)".format(commandsnum), icon_url=self.bot.user.avatar_url) 45 | if commands != "" and cog != "help": 46 | s.add_field(name=cog.title() + " [{}]".format(cogsnum), value=commands, inline=False) 47 | await ctx.send(embed=s) 48 | elif not subcommand and commandname: 49 | msg = "" 50 | try: 51 | self.bot.all_commands[commandname.lower()] 52 | try: 53 | perms = self.bot.all_commands[commandname.lower()].checks[0] 54 | except: 55 | perms = None 56 | except: 57 | try: 58 | cogcommandsnum = len("\n".join(["`{}` - {}".format(x, self.bot.cogs[commandname.lower()].bot.all_commands[x].help) for x in self.bot.cogs[commandname.lower()].bot.all_commands if self.bot.all_commands[x].module[5:].lower() == commandname.lower() and self.bot.all_commands[x].hidden == False and x not in self.bot.all_commands[x].aliases])) 59 | pages = math.ceil(cogcommandsnum / 2000) 60 | commandnumber = len([x for x in self.bot.cogs[commandname.lower()].bot.all_commands if self.bot.all_commands[x].module[5:].lower() == commandname.lower() and self.bot.all_commands[x].hidden == False and x not in self.bot.all_commands[x].aliases]) 61 | cogcommands = "\n".join(sorted(["`{}` - {}".format(x, self.bot.cogs[commandname.lower()].bot.all_commands[x].help) for x in self.bot.cogs[commandname.lower()].bot.all_commands if self.bot.all_commands[x].module[5:].lower() == commandname.lower() and self.bot.all_commands[x].hidden == False and x not in self.bot.all_commands[x].aliases], key=lambda x: x)) 62 | n = 0 63 | m = 2000 64 | for x in range(pages): 65 | if n != 0: 66 | while cogcommands[n-1:n] != "\n": 67 | n -= 1 68 | while cogcommands[m-1:m] != "\n": 69 | m -= 1 70 | s=discord.Embed(colour=0xffff00, description=cogcommands[n:m]) 71 | if n == 0: 72 | s.set_author(name=commandname.title() + " ({} Commands)".format(commandnumber), icon_url=self.bot.user.avatar_url) 73 | s.set_footer(text="s?help for more info", icon_url=ctx.message.author.avatar_url) 74 | n += 2000 75 | m += 2000 76 | await ctx.send(embed=s) 77 | return 78 | except: 79 | await ctx.send("That is not a valid command or module :no_entry:") 80 | return 81 | if not self.bot.all_commands[commandname.lower()].usage: 82 | for x in self.bot.all_commands[commandname.lower()].params: 83 | if x != "ctx": 84 | if x != "self": 85 | if "=" in str(self.bot.all_commands[commandname.lower()].params[x]): 86 | msg += "[{}] ".format(x) 87 | else: 88 | msg += "<{}> ".format(x) 89 | else: 90 | msg += self.bot.all_commands[commandname.lower()].usage 91 | if not self.bot.all_commands[commandname.lower()].aliases: 92 | aliases = "None" 93 | else: 94 | aliases = ", ".join([x for x in self.bot.all_commands[commandname.lower()].aliases]) 95 | if not perms: 96 | msg = "Usage: {}{} {}\nCommand aliases: {}\nRequired permissions: None\nCommand description: {}".format(ctx.prefix, self.bot.all_commands[commandname.lower()], msg, aliases, self.bot.all_commands[commandname.lower()].help) 97 | else: 98 | msg = "Usage: {}{} {}\nCommand aliases: {}\nRequired permissions: {}\nCommand description: {}".format(ctx.prefix, self.bot.all_commands[commandname.lower()], msg, aliases, 99 | ", ".join(inspect.getclosurevars(perms).nonlocals["perms"]) if perms.__name__ != "is_owner_check" and str(perms).split(" ")[1].split(".")[0] != "is_main_owner" else "Bot Owner", self.bot.all_commands[commandname.lower()].help) 100 | try: 101 | msg += "\n\nSub commands: {}".format(", ".join([x for x in self.bot.all_commands[commandname.lower()].all_commands if x not in self.bot.all_commands[commandname.lower()].all_commands[x].aliases])) 102 | except: 103 | pass 104 | s=discord.Embed(description=msg) 105 | s.set_author(name=self.bot.all_commands[commandname.lower()].name, icon_url=self.bot.user.avatar_url) 106 | await ctx.send(embed=s) 107 | else: 108 | msg = "" 109 | try: 110 | self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()] 111 | try: 112 | perms = self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()].checks[0] 113 | except: 114 | perms = None 115 | except: 116 | await ctx.send("That is not a command :no_entry:") 117 | return 118 | if not self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()].usage: 119 | for x in self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()].params: 120 | if x != "ctx": 121 | if x != "self": 122 | if "=" in str(self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()].params[x]): 123 | msg += "[{}] ".format(x) 124 | else: 125 | msg += "<{}> ".format(x) 126 | else: 127 | msg += self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()].usage 128 | if not self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()].aliases: 129 | aliases = "None" 130 | else: 131 | aliases = ", ".join([x for x in self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()].aliases]) 132 | if not perms: 133 | msg = "Usage: {}{} {}\nCommand aliases: {}\nRequired permissions: None\nCommand description: {}".format(ctx.prefix, self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()], msg, aliases, self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()].help) 134 | else: 135 | msg = "Usage: {}{} {}\nCommand aliases: {}\nRequired permissions: {}\nCommand description: {}".format(ctx.prefix, self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()], msg, aliases, 136 | ", ".join(inspect.getclosurevars(perms).nonlocals["perms"]) if perms.__name__ != "is_owner_check" and str(perms).split(" ")[1].split(".")[0] != "is_main_owner" else "Bot Owner", self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()].help) 137 | s=discord.Embed(description=msg) 138 | s.set_author(name=self.bot.all_commands[commandname.lower()].name + " " + self.bot.all_commands[commandname.lower()].all_commands[subcommand.lower()].name, icon_url=self.bot.user.avatar_url) 139 | await ctx.send(embed=s) 140 | 141 | def setup(bot, connection): 142 | n = help(bot, connection) 143 | bot.remove_command('help') 144 | bot.add_cog(n) 145 | -------------------------------------------------------------------------------- /Sx4/cogs/image.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | import os 4 | from copy import deepcopy 5 | from collections import namedtuple, defaultdict, deque 6 | from datetime import datetime 7 | from random import randint 8 | from copy import deepcopy 9 | from io import BytesIO, StringIO 10 | from utils import checks 11 | from enum import Enum 12 | import time 13 | import logging 14 | import datetime 15 | import math 16 | from utils import arg 17 | from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhance, ImageSequence 18 | from urllib.request import Request, urlopen 19 | import re 20 | import json 21 | import aiohttp 22 | import urllib.request 23 | from utils import data 24 | import requests 25 | import random 26 | from random import choice 27 | import asyncio 28 | from difflib import get_close_matches 29 | 30 | colours = data.read_json("data/colours/colournames.json") 31 | 32 | class image: 33 | """Fun image commands""" 34 | 35 | def __init__(self, bot, connection): 36 | self.bot = bot 37 | self.db = connection 38 | 39 | @commands.command(aliases=["htg"]) 40 | @commands.cooldown(1, 5, commands.BucketType.user) 41 | async def howtogoogle(self, ctx, *, text): 42 | """Shows someone how to use google""" 43 | if len(text) > 50: 44 | return await ctx.send("You can only use **50** characters :no_entry:") 45 | async with ctx.channel.typing(): 46 | async with aiohttp.ClientSession() as session: 47 | async with session.get("http://localhost:8443/api/google?{}".format(urllib.parse.urlencode({"q": text}))) as f: 48 | if f.status == 200: 49 | await ctx.send(file=discord.File(f.content, "google.{}".format(f.headers["Content-Type"].split("/")[1]))) 50 | elif f.status == 400: 51 | await ctx.send(await f.text()) 52 | else: 53 | await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 54 | 55 | @commands.command(usage="[user | image]") 56 | @commands.cooldown(1, 5, commands.BucketType.user) 57 | async def hot(self, ctx, user_or_image: str=None): 58 | """The specified user/image will be called hot by will smith""" 59 | if ctx.message.attachments and not user_or_image: 60 | url = ctx.message.attachments[0].url 61 | elif not ctx.message.attachments and not user_or_image: 62 | url = get_avatar_url(ctx.author) 63 | else: 64 | user = arg.get_server_member(ctx, user_or_image) 65 | if not user: 66 | url = user_or_image 67 | else: 68 | url = get_avatar_url(user) 69 | async with aiohttp.ClientSession() as session: 70 | async with session.get("http://localhost:8443/api/hot?image={}".format(url)) as f: 71 | if f.status == 200: 72 | await ctx.send(file=discord.File(f.content, "hot.{}".format(f.headers["Content-Type"].split("/")[1]))) 73 | elif f.status == 400: 74 | await ctx.send(await f.text()) 75 | else: 76 | await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 77 | 78 | @commands.command(name="discord", usage=" ") 79 | @commands.cooldown(1, 5, commands.BucketType.user) 80 | async def _discord(self, ctx, user: str, *, discord_text: str): 81 | """Recreate a message from discord using this command""" 82 | user = arg.get_server_member(ctx, user) 83 | if not user: 84 | return await ctx.send("Invalid user :no_entry:") 85 | if discord_text.lower().endswith(" --white"): 86 | white = True 87 | discord_text = discord_text[:-8] 88 | else: 89 | white = False 90 | url = "http://localhost:8443/api/discord?image={}&theme={}&{}&colour={}&{}&bot={}".format(get_avatar_url(user), "dark" if not white else "white", urllib.parse.urlencode({"text": discord_text}), 91 | str(user.colour)[1:], urllib.parse.urlencode({"name": user.display_name}), user.bot) 92 | async with aiohttp.ClientSession() as session: 93 | async with session.get(url) as f: 94 | if f.status == 200: 95 | await ctx.send(file=discord.File(f.content, "discord.{}".format(f.headers["Content-Type"].split("/")[1]))) 96 | elif f.status == 400: 97 | await ctx.send(await f.text()) 98 | else: 99 | await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 100 | 101 | @commands.command() 102 | @commands.cooldown(1, 5, commands.BucketType.user) 103 | async def flag(self, ctx, flag_initial: str, *, user: discord.Member=None): 104 | """Put a flag on top of your profile picture""" 105 | if not user: 106 | user = ctx.author 107 | async with aiohttp.ClientSession() as session: 108 | async with session.get("http://localhost:8443/api/flag?image={}&flag={}".format(get_avatar_url(user), flag_initial.lower())) as f: 109 | if f.status == 200: 110 | await ctx.send(file=discord.File(f.content, "flag.{}".format(f.headers["Content-Type"].split("/")[1]))) 111 | elif f.status == 400: 112 | await ctx.send(await f.text()) 113 | else: 114 | await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 115 | 116 | @commands.command(usage="[user | image]") 117 | @commands.cooldown(1, 5, commands.BucketType.user) 118 | async def christmas(self, ctx, *, user_or_image: str=None): 119 | """Turn an image into a christmas themed one""" 120 | if not user_or_image: 121 | if ctx.message.attachments: 122 | url = ctx.message.attachments[0].url 123 | else: 124 | url = get_avatar_url(ctx.author) 125 | else: 126 | user = arg.get_server_member(ctx, user_or_image) 127 | if not user: 128 | url = user_or_image 129 | else: 130 | url = get_avatar_url(user) 131 | async with aiohttp.ClientSession() as session: 132 | async with session.get("http://localhost:8443/api/christmas?image={}".format(url)) as f: 133 | if f.status == 200: 134 | await ctx.send(file=discord.File(f.content, "christmas.{}".format(f.headers["Content-Type"].split("/")[1]))) 135 | elif f.status == 400: 136 | await ctx.send(await f.text()) 137 | else: 138 | await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 139 | 140 | @commands.command(usage="[user | image]") 141 | @commands.cooldown(1, 5, commands.BucketType.user) 142 | async def halloween(self, ctx, *, user_or_image: str=None): 143 | """Turn an image into a halloween themed one""" 144 | if not user_or_image: 145 | if ctx.message.attachments: 146 | url = ctx.message.attachments[0].url 147 | else: 148 | url = get_avatar_url(ctx.author) 149 | else: 150 | user = arg.get_server_member(ctx, user_or_image) 151 | if not user: 152 | url = user_or_image 153 | else: 154 | url = get_avatar_url(user) 155 | async with aiohttp.ClientSession() as session: 156 | async with session.get("http://localhost:8443/api/halloween?image={}".format(url)) as f: 157 | if f.status == 200: 158 | await ctx.send(file=discord.File(f.content, "halloween.{}".format(f.headers["Content-Type"].split("/")[1]))) 159 | elif f.status == 400: 160 | await ctx.send(await f.text()) 161 | else: 162 | await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 163 | 164 | @commands.command(usage="[user | image]") 165 | @commands.cooldown(1, 5, commands.BucketType.user) 166 | async def trash(self, ctx, user_or_imagelink: str=None): 167 | """Make someone look like trash""" 168 | channel = ctx.message.channel 169 | author = ctx.message.author 170 | if not user_or_imagelink: 171 | if ctx.message.attachments: 172 | url = ctx.message.attachments[0].url 173 | else: 174 | url = ctx.author.avatar_url_as(format="png") 175 | else: 176 | user = arg.get_server_member(ctx, user_or_imagelink) 177 | if not user: 178 | url = user_or_imagelink 179 | else: 180 | url = user.avatar_url_as(format="png") 181 | async with aiohttp.ClientSession() as session: 182 | async with session.get("http://localhost:8443/api/trash?image={}".format(url)) as f: 183 | if f.status == 200: 184 | await ctx.send(file=discord.File(f.content, "trash.png")) 185 | elif f.status == 400: 186 | await ctx.send(await f.text()) 187 | else: 188 | await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 189 | 190 | @commands.command(aliases=["www"], usage="[user | image] [user | image]") 191 | @commands.cooldown(1, 5, commands.BucketType.user) 192 | async def whowouldwin(self, ctx, user_or_imagelink: str, user_or_imagelink2: str=None): 193 | """Who would win out of 2 images""" 194 | channel = ctx.channel 195 | author = ctx.author 196 | user = arg.get_server_member(ctx, user_or_imagelink) 197 | if not user: 198 | url1 = user_or_imagelink 199 | else: 200 | url1 = user.avatar_url_as(format="png") 201 | if not user_or_imagelink2: 202 | url2 = author.avatar_url_as(format="png") 203 | else: 204 | user = arg.get_server_member(ctx, user_or_imagelink2) 205 | if not user: 206 | url2 = user_or_imagelink2 207 | else: 208 | url2 = user.avatar_url_as(format="png") 209 | async with aiohttp.ClientSession() as session: 210 | async with session.get("http://localhost:8443/api/www?firstImage={}&secondImage={}".format(url1, url2)) as f: 211 | if f.status == 200: 212 | await ctx.send(file=discord.File(f.content, "www.png")) 213 | elif f.status == 400: 214 | await ctx.send(await f.text()) 215 | else: 216 | await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 217 | 218 | @commands.command(usage="[user | image]") 219 | @commands.cooldown(1, 5, commands.BucketType.user) 220 | async def fear(self, ctx, user_or_imagelink: str=None): 221 | """Make someone look feared of""" 222 | channel = ctx.channel 223 | author = ctx.author 224 | if not user_or_imagelink: 225 | if ctx.message.attachments: 226 | url = ctx.message.attachments[0].url 227 | else: 228 | url = get_avatar_url(author) 229 | else: 230 | user = arg.get_server_member(ctx, user_or_imagelink) 231 | if not user: 232 | url = user_or_imagelink 233 | else: 234 | url = get_avatar_url(user) 235 | async with aiohttp.ClientSession() as session: 236 | async with session.get("http://localhost:8443/api/fear?image={}".format(url)) as f: 237 | if f.status == 200: 238 | await ctx.send(file=discord.File(f.content, "fear.{}".format(f.headers["Content-Type"].split("/")[1]))) 239 | elif f.status == 400: 240 | await ctx.send(await f.text()) 241 | else: 242 | await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 243 | 244 | @commands.command(usage="[user | image]") 245 | @commands.cooldown(1, 5, commands.BucketType.user) 246 | async def emboss(self, ctx, user_or_image: str=None): 247 | """Make a profile picture emboss""" 248 | channel = ctx.channel 249 | author = ctx.author 250 | if not user_or_image: 251 | if ctx.message.attachments: 252 | url = ctx.message.attachments[0].url 253 | else: 254 | url = get_avatar_url(author) 255 | else: 256 | user = arg.get_server_member(ctx, user_or_image) 257 | if not user: 258 | url = user_or_image 259 | else: 260 | url = get_avatar_url(user) 261 | async with aiohttp.ClientSession() as session: 262 | async with session.get("http://localhost:8443/api/emboss?image={}".format(url)) as f: 263 | if f.status == 200: 264 | await ctx.send(file=discord.File(f.content, "emboss.{}".format(f.headers["Content-Type"].split("/")[1]))) 265 | elif f.status == 400: 266 | await ctx.send(await f.text()) 267 | else: 268 | await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 269 | 270 | @commands.command(usage=" [user]") 271 | @commands.cooldown(1, 5, commands.BucketType.user) 272 | async def ship(self, ctx, user1: str, *, user2: str=None): 273 | """Ship 2 users""" 274 | if not user2: 275 | user2 = arg.get_server_member(ctx, user1) 276 | user1 = ctx.author 277 | else: 278 | user1 = arg.get_server_member(ctx, user1) 279 | user2 = arg.get_server_member(ctx, user2) 280 | if not user1 or not user2: 281 | return await ctx.send("Invalid user :no_entry:") 282 | shipname = str(user1.name[:math.ceil(len(user1.name)/2)]) + str(user2.name[math.ceil(len(user2.name)/2):]) 283 | state = random.getstate() 284 | random.seed(user2.id + user1.id) 285 | number = randint(0, 100) 286 | random.setstate(state) 287 | u1avatar = user1.avatar_url_as(format="png") 288 | u2avatar = user2.avatar_url_as(format="png") 289 | async with aiohttp.ClientSession() as session: 290 | async with session.get("http://localhost:8443/api/ship?firstImage={}&secondImage={}".format(u1avatar, u2avatar)) as f: 291 | if f.status == 200: 292 | await ctx.send(content="Ship Name: **{}**\nLove Percentage: **{}%**".format(shipname, number), file=discord.File(f.content, "ship.png")) 293 | elif f.status == 400: 294 | return await ctx.send(await f.text()) 295 | else: 296 | return await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 297 | 298 | @commands.command(usage="[user | image]") 299 | @commands.cooldown(1, 5, commands.BucketType.user) 300 | async def vr(self, ctx, user_or_image: str=None): 301 | """Make someone feel emotional in vr""" 302 | channel = ctx.channel 303 | author = ctx.author 304 | if not user_or_image: 305 | if ctx.message.attachments: 306 | url = ctx.message.attachments[0].url 307 | else: 308 | url = get_avatar_url(author) 309 | else: 310 | user = arg.get_server_member(ctx, user_or_image) 311 | if not user: 312 | url = user_or_image 313 | else: 314 | url = get_avatar_url(user) 315 | async with aiohttp.ClientSession() as session: 316 | async with session.get("http://localhost:8443/api/vr?image={}".format(url)) as f: 317 | if f.status == 200: 318 | await ctx.send(file=discord.File(f.content, "vr.{}".format(f.headers["Content-Type"].split("/")[1]))) 319 | elif f.status == 400: 320 | return await ctx.send(await f.text()) 321 | else: 322 | return await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 323 | 324 | 325 | @commands.command(usage="[user | image]") 326 | @commands.cooldown(1, 5, commands.BucketType.user) 327 | async def shit(self, ctx, user_or_image: str=None): 328 | """Choose who you want to be shit""" 329 | channel = ctx.channel 330 | author = ctx.author 331 | if not user_or_image: 332 | if ctx.message.attachments: 333 | url = ctx.message.attachments[0].url 334 | else: 335 | url = get_avatar_url(author) 336 | else: 337 | user = arg.get_server_member(ctx, user_or_image) 338 | if not user: 339 | url = user_or_image 340 | else: 341 | url = get_avatar_url(user) 342 | async with aiohttp.ClientSession() as session: 343 | async with session.get("http://localhost:8443/api/shit?image={}".format(url)) as f: 344 | if f.status == 200: 345 | await ctx.send(file=discord.File(f.content, "shit.{}".format(f.headers["Content-Type"].split("/")[1]))) 346 | elif f.status == 400: 347 | return await ctx.send(await f.text()) 348 | else: 349 | return await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 350 | 351 | @commands.command(usage="[user | image]") 352 | @commands.cooldown(1, 5, commands.BucketType.user) 353 | async def beautiful(self, ctx, user_or_image: str=None): 354 | """Turn something to a masterpiece""" 355 | channel = ctx.channel 356 | author = ctx.author 357 | if not user_or_image: 358 | if ctx.message.attachments: 359 | url = ctx.message.attachments[0].url 360 | else: 361 | url = get_avatar_url(author) 362 | else: 363 | user = arg.get_server_member(ctx, user_or_image) 364 | if not user: 365 | url = user_or_image 366 | else: 367 | url = get_avatar_url(user) 368 | async with aiohttp.ClientSession() as session: 369 | async with session.get("http://localhost:8443/api/beautiful?image={}".format(url)) as f: 370 | if f.status == 200: 371 | await ctx.send(file=discord.File(f.content, "beautiful.{}".format(f.headers["Content-Type"].split("/")[1]))) 372 | elif f.status == 400: 373 | return await ctx.send(await f.text()) 374 | else: 375 | return await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 376 | 377 | @commands.command(usage="[user | image]") 378 | async def gay(self, ctx, user_or_imagelink: str=None): 379 | """Turn someone or yourself gay""" 380 | channel = ctx.message.channel 381 | author = ctx.message.author 382 | if not user_or_imagelink: 383 | if ctx.message.attachments: 384 | url = ctx.message.attachments[0].url 385 | else: 386 | url = get_avatar_url(author) 387 | else: 388 | user = arg.get_server_member(ctx, user_or_imagelink) 389 | if not user: 390 | url = user_or_imagelink 391 | else: 392 | url = get_avatar_url(user) 393 | async with aiohttp.ClientSession() as session: 394 | async with session.get("http://localhost:8443/api/gay?image={}".format(url)) as f: 395 | if f.status == 200: 396 | await ctx.send(file=discord.File(f.content, "gay.{}".format(f.headers["Content-Type"].split("/")[1]))) 397 | elif f.status == 400: 398 | return await ctx.send(await f.text()) 399 | else: 400 | return await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 401 | 402 | @commands.command() 403 | @commands.cooldown(1, 5, commands.BucketType.user) 404 | async def trumptweet(self, ctx, *, text: str): 405 | """Make trump say something on twitter""" 406 | channel = ctx.channel 407 | author = ctx.author 408 | if len(text) > 250: 409 | await ctx.send("No more than 250 characters :no_entry:") 410 | return 411 | async with aiohttp.ClientSession() as session: 412 | async with session.get("http://localhost:8443/api/trump?text={}".format(text)) as f: 413 | if f.status == 200: 414 | await ctx.send(file=discord.File(f.content, "trump.png")) 415 | elif f.status == 400: 416 | return await ctx.send(await f.text()) 417 | else: 418 | return await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 419 | 420 | @commands.command() 421 | @commands.cooldown(1, 5, commands.BucketType.user) 422 | async def tweet(self, ctx, user: str, *, text: commands.clean_content(fix_channel_mentions=True)): 423 | """Tweet from your or another users account""" 424 | await ctx.channel.trigger_typing() 425 | user = arg.get_server_member(ctx, user) 426 | if not user: 427 | return await ctx.send("I could not find that user :no_entry:") 428 | if len(text) > 250: 429 | await ctx.send("No more than 250 characters :no_entry:") 430 | return 431 | retweets = randint(1, ctx.guild.member_count) 432 | likes = randint(1, ctx.guild.member_count) 433 | urls = list(map(lambda x: x.avatar_url_as(format="png", size=64), random.sample(ctx.guild.members, min(ctx.guild.member_count, 10, likes)))) 434 | data = {"displayName": user.display_name, "name": user.name, "avatarUrl": user.avatar_url_as(format="png", size=128), "urls": urls, "likes": likes, "retweets": retweets, "text": text} 435 | async with aiohttp.ClientSession() as session: 436 | async with session.post("http://localhost:8443/api/tweet", json=data, headers={"Content-Type": "application/json"}) as f: 437 | if f.status == 200: 438 | await ctx.send(file=discord.File(f.content, "tweet.png")) 439 | elif f.status == 400: 440 | return await ctx.send(await f.text()) 441 | else: 442 | return await ctx.send("Oops something went wrong! Status code: {}".format(f.status)) 443 | 444 | @commands.command() 445 | @commands.cooldown(1, 5, commands.BucketType.user) 446 | async def scroll(self, ctx, *, text: str): 447 | """The terrible truth""" 448 | channel = ctx.message.channel 449 | author = ctx.message.author 450 | if len(text) > 80: 451 | await ctx.send("No more than 80 characters :no_entry:") 452 | return 453 | img = Image.open("scroll-meme.png") 454 | draw = ImageDraw.Draw(img) 455 | n = 0 456 | m = 12 457 | char = 12 458 | times = 0 459 | size = 20 460 | description = "" 461 | if (math.ceil(len(str(text))/char)+1) >=6: 462 | for x in range((math.ceil(len(str(text))/char)+1) - 6): 463 | size -= 3 464 | char += 1 465 | for x in range(math.ceil(len(str(text))/char)+1): 466 | if [x for x in text if " " in x]: 467 | for x in range(len([x for x in text if " " in x])+1): 468 | while text[m-1:m] != " " and m != 0 and m != len(str(text)): 469 | m -= 1 470 | times += char 471 | if m == 0: 472 | n = times - char 473 | m = times 474 | description += text[n:m] + "\n" 475 | n = m 476 | m += char 477 | font = ImageFont.truetype("arial.ttf", size) 478 | draw.text((95, 285), description, (0, 0, 0), font=font) 479 | await send_file(ctx, img) 480 | 481 | @commands.command(aliases=["color", "hex"]) 482 | @commands.cooldown(1, 5, commands.BucketType.user) 483 | async def colour(self, ctx, *, colour: str=None): 484 | """View a colours hex code and RGB and a image with the colour, if a colour is not specified it will get a random one""" 485 | if not colour: 486 | colour = ''.join([random.choice('0123456789ABCDEF') for x in range(6)]) 487 | colour = discord.Colour(int(colour, 16)) 488 | colourname = str(colour) 489 | for x in colours: 490 | if str(colour).lower() == colours[x].lower(): 491 | if not re.match("(?:[a-f A-F]|[0-9]){6}" if "#" not in colour else "#(?:[a-f A-F]|[0-9]){6}", colour): 492 | return await ctx.send("Invalid hex :no_entry:") 493 | colourname = x.title() 494 | image = Image.new('RGBA', (100, 100), (colour.r, colour.g, colour.b)) 495 | image.save("result.png") 496 | s=discord.Embed(colour=colour, description="Hex: {}\nRGB: ({}, {}, {})".format(str(colour), colour.r, colour.g, colour.b)) 497 | s.set_image(url="attachment://result.png") 498 | s.set_author(name=colourname, icon_url="attachment://result.png") 499 | await ctx.send(file=discord.File("result.png", "result.png"), embed=s) 500 | try: 501 | os.remove("result.png") 502 | except: 503 | pass 504 | return 505 | colourname = colour 506 | for x in colours: 507 | if x.title() == colour.title(): 508 | colourname = colours[x].lower() 509 | colour = colours[x].lower() 510 | elif "#" + str(colour).replace("#", "").lower() == colours[x].lower(): 511 | if not re.match("(?:[a-f A-F]|[0-9]){6}" if "#" not in colour else "#(?:[a-f A-F]|[0-9]){6}", colour): 512 | return await ctx.send("Invalid hex :no_entry:") 513 | colourname = x.title() 514 | if not re.match("(?:[a-f A-F]|[0-9]){6}" if "#" not in colour else "#(?:[a-f A-F]|[0-9]){6}", colour): 515 | return await ctx.send("Invalid hex :no_entry:") 516 | image = Image.new('RGBA', (100, 100), (discord.Colour(int(colour.replace("#", ""), 16)).r, discord.Colour(int(colour.replace("#", ""), 16)).g, discord.Colour(int(colour.replace("#", ""), 16)).b)) 517 | image.save("result.png") 518 | s=discord.Embed(colour=discord.Colour(int(colour.replace("#", ""), 16)), description="Hex: {}\nRGB: ({}, {}, {})".format("#" + str(colour).replace("#", ""), discord.Colour(int(colour.replace("#", ""), 16)).r, discord.Colour(int(colour.replace("#", ""), 16)).g, discord.Colour(int(colour.replace("#", ""), 16)).b)) 519 | s.set_image(url="attachment://result.png") 520 | s.set_author(name=colourname, icon_url="attachment://result.png") 521 | await ctx.send(file=discord.File("result.png", "result.png"), embed=s) 522 | try: 523 | os.remove("result.png") 524 | except: 525 | pass 526 | 527 | @commands.command() 528 | @commands.cooldown(1, 5, commands.BucketType.user) 529 | async def drift(self, ctx, user: discord.Member, textleft: str, textright: str=None): 530 | """Drift away from something, any words over 10 characters will be ignored""" 531 | channel = ctx.message.channel 532 | author = ctx.message.author 533 | try: 534 | if len(textright) > 50: 535 | await ctx.send("No more than 50 characters on the right sign :no_entry:") 536 | return 537 | except: 538 | pass 539 | if len(textleft) > 50: 540 | await ctx.send("No more than 50 characters on the left sign :no_entry:") 541 | return 542 | img = Image.open("drift-meme.png") 543 | draw = ImageDraw.Draw(img) 544 | n = 0 545 | m = 10 546 | number = 0 547 | times = 0 548 | size = 20 549 | description = "" 550 | for x in range(math.ceil(len(str(textleft))/10)+1): 551 | number += 1 552 | if [x for x in textleft if " " in x]: 553 | for x in range(len([x for x in textleft if " " in x])+1): 554 | while textleft[m-1:m] != " " and m != 0 and m != len(str(textleft)): 555 | m -= 1 556 | times += 10 557 | if m == 0: 558 | n = times - 10 559 | m = times 560 | if number > 4: 561 | size -= 3 562 | description += textleft[n:m] + "\n" 563 | n = m 564 | m += 10 565 | a = 0 566 | b = 13 567 | number2 = 0 568 | times2 = 0 569 | size2 = 20 570 | description2 = "" 571 | if textright: 572 | for x in range(math.ceil(len(str(textright))/13)+1): 573 | number2 += 1 574 | if [x for x in textright if " " in x]: 575 | for x in range(len([x for x in textright if " " in x])+1): 576 | while textright[b-1:b] != " " and b != 0 and b != len(str(textright)): 577 | b -= 1 578 | times += 13 579 | if b == 0: 580 | a = times - 13 581 | b = times 582 | if number2 > 5: 583 | size2 -= 3 584 | description2 += textright[a:b] + "\n" 585 | a = b 586 | b += 13 587 | font = ImageFont.truetype("arial.ttf", size) 588 | font2 = ImageFont.truetype("arial.ttf", size2) 589 | draw.text((125, 60), description, (255, 255, 255), font=font) 590 | if description2 != "": 591 | draw.text((265, 60), description2, (255, 255, 255), font=font2) 592 | img2 = getImage(user.avatar_url.replace("gif", "png").replace("webp", "png")) 593 | img2 = img2.resize((23, 23)) 594 | img.paste(img2, (270, 335)) 595 | await send_file(ctx, img) 596 | 597 | @commands.command(usage="[user | image]") 598 | async def commoncolour(self, ctx, user_or_imagelink: str=None): 599 | """Returns the most common colour from an image""" 600 | if not user_or_imagelink: 601 | if ctx.message.attachments: 602 | url = ctx.message.attachments[0].url 603 | else: 604 | url = ctx.author.avatar_url 605 | else: 606 | user = await arg.get_member(ctx, user_or_imagelink) 607 | if not user: 608 | url = user_or_imagelink 609 | else: 610 | url = user.avatar_url 611 | try: 612 | image = getImage(url).convert("RGB") 613 | except: 614 | return await ctx.send("Invalid Image/User :no_entry:") 615 | pixdata = image.load() 616 | entries = {} 617 | for y in range(image.size[1]): 618 | for x in range(image.size[0]): 619 | if pixdata[x, y] not in entries: 620 | entries[pixdata[x, y]] = 1 621 | else: 622 | entries[pixdata[x, y]] += 1 623 | image = Image.new("RGBA", (300, 50), sorted(entries.items(), key=lambda x: x[1], reverse=True)[0][0]) 624 | hex = '%02x%02x%02x' % sorted(entries.items(), key=lambda x: x[1], reverse=True)[0][0] 625 | await ctx.send(file=get_file(image), embed=discord.Embed(title="Most Common Colour: #{}".format(hex.upper()), description="RGB: {}".format(sorted(entries.items(), key=lambda x: x[1], reverse=True)[0][0]), colour=discord.Colour(int(hex, 16))).set_image(url="attachment://result.png").set_thumbnail(url=url)) 626 | del entries 627 | 628 | 629 | def get_avatar_url(user): 630 | if ".gif" in user.avatar_url: 631 | return user.avatar_url 632 | else: 633 | return user.avatar_url_as(format="png") 634 | 635 | 636 | async def send_file(ctx, img): 637 | temp = BytesIO() 638 | img.save(temp, "png") 639 | temp.seek(0) 640 | await ctx.send(file=discord.File(temp, "result.png")) 641 | 642 | def get_file(img): 643 | temp = BytesIO() 644 | img.save(temp, "png") 645 | temp.seek(0) 646 | return discord.File(temp, "result.png") 647 | 648 | def get_file_gif(img, frames): 649 | temp = BytesIO() 650 | img.save(temp, "gif", save_all=True, append_images=frames) 651 | temp.seek(0) 652 | return discord.File(temp, "result.gif") 653 | 654 | def getImage(url): 655 | r = requests.get(url, stream=True, timeout=3) 656 | img = Image.open(r.raw).convert('RGBA') 657 | return img 658 | 659 | def setup(bot, connection): 660 | bot.add_cog(image(bot, connection)) 661 | -------------------------------------------------------------------------------- /Sx4/cogs/logs.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | from utils import checks 4 | from datetime import datetime 5 | from collections import deque, defaultdict 6 | import os 7 | import re 8 | from . import owner as dev 9 | import logging 10 | import asyncio 11 | import rethinkdb as r 12 | import random 13 | from utils import arghelp 14 | import time 15 | import discord 16 | from discord.ext import commands 17 | from random import randint 18 | from random import choice as randchoice 19 | from discord.ext.commands import CommandNotFound 20 | 21 | class logs: 22 | def __init__(self, bot, connection): 23 | self.bot = bot 24 | self.db = connection 25 | 26 | @commands.group(usage="") 27 | async def logs(self, ctx): 28 | """Log actions in your server""" 29 | server = ctx.guild 30 | if ctx.invoked_subcommand is None: 31 | await arghelp.send(self.bot, ctx) 32 | else: 33 | r.table("logs").insert({"id": str(server.id), "channel": None, "toggle": False}).run(self.db, durability="soft") 34 | 35 | @logs.command() 36 | @checks.has_permissions("manage_guild") 37 | async def channel(self, ctx, channel: discord.TextChannel=None): 38 | """Set the channel where you want stuff to be logged""" 39 | server = ctx.guild 40 | serverdata = r.table("logs").get(str(server.id)) 41 | if not channel: 42 | channel = ctx.message.channel 43 | serverdata.update({"channel": str(channel.id)}).run(self.db, durability="soft") 44 | await ctx.send("Logs will be recorded in <#{}> if toggled on <:done:403285928233402378>".format(channel.id)) 45 | 46 | @logs.command() 47 | @checks.has_permissions("manage_guild") 48 | async def toggle(self, ctx): 49 | """Toggle logs on or off""" 50 | server = ctx.guild 51 | serverdata = r.table("logs").get(str(server.id)) 52 | if serverdata["toggle"].run(self.db, durability="soft") == False: 53 | serverdata.update({"toggle": True}).run(self.db, durability="soft") 54 | await ctx.send("Logs have been toggled **on** <:done:403285928233402378>") 55 | return 56 | if serverdata["toggle"].run(self.db, durability="soft") == True: 57 | serverdata.update({"toggle": False}).run(self.db, durability="soft") 58 | await ctx.send("Logs have been toggled **off** <:done:403285928233402378>") 59 | return 60 | 61 | @logs.command() 62 | async def stats(self, ctx): 63 | server = ctx.guild 64 | serverdata = r.table("logs").get(str(server.id)).run(self.db, durability="soft") 65 | s=discord.Embed(colour=0xffff00) 66 | s.set_author(name="Logs Settings", icon_url=self.bot.user.avatar_url) 67 | s.add_field(name="Status", value="Enabled" if serverdata["toggle"] else "Disabled") 68 | s.add_field(name="Channel", value=server.get_channel(int(serverdata["channel"])).mention if serverdata["channel"] and server.get_channel(int(serverdata["channel"])) else "Not set") 69 | await ctx.send(embed=s) 70 | 71 | def setup(bot, connection): 72 | bot.add_cog(logs(bot, connection)) -------------------------------------------------------------------------------- /Sx4/cogs/owner.py: -------------------------------------------------------------------------------- 1 | import discord 2 | import asyncio 3 | from discord.ext import commands 4 | from random import choice as randchoice 5 | import time 6 | import requests 7 | import datetime 8 | import rethinkdb as r 9 | from discord.ext.commands.view import StringView 10 | import json 11 | import inspect 12 | from utils import arg 13 | import math 14 | import functools 15 | import psutil 16 | from PIL import Image, ImageDraw, ImageFont, ImageOps 17 | from utils import checks 18 | import os 19 | 20 | execution_times = {} 21 | 22 | def log(method): 23 | @functools.wraps(method) 24 | async def timed(*args, **kw): 25 | memory_start = psutil.Process(os.getpid()).memory_info().rss/1000000 26 | start_time = time.time() 27 | result = await method(*args, **kw) 28 | execution_time = int((time.time() - start_time) * 1000) 29 | memory_gained = (psutil.Process(os.getpid()).memory_info().rss/1000000) - memory_start 30 | 31 | method_name = method.__module__ + "." + method.__name__ 32 | if method_name not in execution_times: 33 | execution_times[method_name] = {"average": 0, "data_points": 0, "memory_average": 0} 34 | 35 | entry = execution_times[method_name] 36 | 37 | new_average = ((entry["average"] * entry["data_points"]) + execution_time)/(entry["data_points"] + 1) 38 | new_average_memory = ((entry["memory_average"] * entry["data_points"]) + memory_gained)/(entry["data_points"] + 1) 39 | 40 | entry["average_memory"] = new_average_memory 41 | entry["average"] = new_average 42 | entry["data_points"] += 1 43 | 44 | if "min_execution_time" not in entry: 45 | entry["min_execution_time"] = execution_time 46 | 47 | entry["min_execution_time"] = min(entry["min_execution_time"], execution_time) 48 | 49 | if "max_execution_time" not in entry: 50 | entry["max_execution_time"] = execution_time 51 | 52 | entry["max_execution_time"] = max(entry["max_execution_time"], execution_time) 53 | 54 | if "min_memory_gained" not in entry: 55 | entry["min_memory_gained"] = memory_gained 56 | 57 | entry["min_memory_gained"] = min(entry["min_memory_gained"], memory_gained) 58 | 59 | if "max_memory_gained" not in entry: 60 | entry["max_memory_gained"] = memory_gained 61 | 62 | entry["max_memory_gained"] = max(entry["max_memory_gained"], memory_gained) 63 | print(entry) 64 | return result 65 | return timed 66 | 67 | class owner: 68 | def __init__(self, bot, connection): 69 | self.bot = bot 70 | self.db = connection 71 | 72 | @commands.command(hidden=True) 73 | @checks.is_owner() 74 | async def code(self, ctx, *, command: str=None): 75 | if not command: 76 | command = ctx.command 77 | else: 78 | command = self.bot.get_command(command) 79 | if not command: 80 | return await ctx.send("Invalid command :no_entry:") 81 | wrap = "```py\n{}```" 82 | code = inspect.getsource(command.callback) 83 | code = code.replace("```", "\```") 84 | if len(code) > 1990: 85 | pages = math.ceil(len(code)/1990) 86 | n = 0 87 | m = 1990 88 | for x in range(pages): 89 | if n != 0: 90 | while code[n-1:n] != "\n": 91 | n -= 1 92 | while code[m-1:m] != "\n": 93 | m -= 1 94 | await ctx.send(wrap.format(code[n:m])) 95 | n += 1990 96 | m += 1990 97 | else: 98 | await ctx.send(wrap.format(code)) 99 | 100 | @commands.command(hidden=True) 101 | @checks.is_owner() 102 | async def collage(self, ctx): 103 | pixels = 64 104 | width = math.ceil(math.sqrt(ctx.guild.member_count)*pixels) 105 | height = math.ceil(math.sqrt(ctx.guild.member_count)*pixels) 106 | background = Image.new("RGBA", (width+pixels, height+pixels), (0, 0, 0, 0)) 107 | x, y, i = 0, 0, 0 108 | await ctx.send("Creating collage...") 109 | t1 = time.perf_counter() 110 | for member in ctx.guild.members: 111 | i += 1 112 | print(str(member) + " ({}/{})".format(i, ctx.guild.member_count)) 113 | try: 114 | with open("avatar.png", "wb") as f: 115 | f.write(requests.get(member.avatar_url).content) 116 | image = Image.open("avatar.png").convert("RGBA") 117 | image = image.resize((pixels, pixels)) 118 | background.paste(image, (x, y)) 119 | x += pixels 120 | if x >= width: 121 | y += pixels 122 | x = 0 123 | print("Successful") 124 | except Exception as e: 125 | print(e) 126 | background.save("collage.png") 127 | t2 = time.perf_counter() 128 | try: 129 | await ctx.send(content="Executed in **{}ms**".format(round((t2-t1)*1000)), file=discord.File("collage.png", "collage.png")) 130 | except: 131 | await ctx.send("Executed in **{}ms**\n\nImage saved in hosters files".format(round((t2-t1)*1000))) 132 | return os.remove("avatar.png") 133 | try: 134 | os.remove("collage.png") 135 | os.remove("avatar.png") 136 | except: 137 | pass 138 | 139 | @commands.command(hidden=True, name="as") 140 | @checks.is_main_owner() 141 | async def _as(self, ctx, user: str, command_name: str, *, args: str=""): 142 | user = await arg.get_member(ctx, user) 143 | if not user: 144 | return await ctx.send("You're retarded that's not a user :no_entry:") 145 | else: 146 | ctx.author = user 147 | ctx.message.author = user 148 | if " " in command_name: 149 | command = command_name.split(" ", 1) 150 | try: 151 | command = self.bot.all_commands[command[0]].all_commands[command[1]] 152 | except KeyError: 153 | return await ctx.send("Invalid command :no_entry:") 154 | else: 155 | try: 156 | command = self.bot.all_commands[command_name] 157 | except KeyError: 158 | return await ctx.send("Invalid command :no_entry:") 159 | ctx.message.content = ctx.prefix + command_name + " " + args 160 | ctx.view = StringView(args) 161 | await command.invoke(ctx) 162 | 163 | @commands.command(hidden=True) 164 | @checks.is_owner() 165 | async def commandlog(self, ctx, *, code: str=None): 166 | if not code: 167 | with open("commandlog.json", "wb") as f: 168 | f.write(json.dumps(r.table("botstats").get("stats")["commandlog"].run(self.db, durability="soft")).encode()) 169 | else: 170 | with open("commandlog.json", "wb") as f: 171 | f.write(json.dumps(list(eval(code.replace("data", 'r.table("botstats").get("stats")["commandlog"].run(self.db, durability="soft")')))).encode()) 172 | await ctx.send(file=discord.File("commandlog.json")) 173 | os.remove("commandlog.json") 174 | 175 | @commands.command(hidden=True) 176 | @checks.is_owner() 177 | async def blacklistuser(self, ctx, user: str): 178 | user = await arg.get_member(ctx, user) 179 | r.table("blacklist").insert({"id": "owner", "users": []}).run(self.db, durability="soft") 180 | data = r.table("blacklist").get("owner") 181 | if str(user.id) not in data["users"].run(self.db, durability="soft"): 182 | data.update({"users": r.row["users"].append(str(user.id))}).run(self.db, durability="soft") 183 | await ctx.send("{} has been blacklisted.".format(user)) 184 | elif str(user.id) in data["users"].run(self.db, durability="soft"): 185 | data.update({"users": r.row["users"].difference([str(user.id)])}).run(self.db, durability="soft") 186 | await ctx.send("{} is no longer blacklisted".format(user)) 187 | 188 | @commands.command(hidden=True) 189 | @checks.is_owner() 190 | async def disable(self, ctx, *, command: str): 191 | command = self.bot.get_command(command) 192 | if not command: 193 | return await ctx.send("Invalid command :no_entry:") 194 | command.enabled = not command.enabled 195 | if command.enabled == False: 196 | await ctx.send("`{}` has been disabled.".format(command)) 197 | else: 198 | await ctx.send("`{}` has been enabled.".format(command)) 199 | 200 | @commands.command(hidden=True) 201 | async def modules(self, ctx): 202 | unloaded, loaded = [], [] 203 | list = [x.replace(".py", "") for x in os.listdir("cogs") if ".py" in x] 204 | for x in list: 205 | if not self.bot.get_cog(x): 206 | unloaded.append(x) 207 | else: 208 | loaded.append(x) 209 | s=discord.Embed(title="Modules ({})".format(len(list))) 210 | s.add_field(name="Loaded ({})".format(len(loaded)), value=", ".join(loaded) if loaded != [] else "None", inline=False) 211 | s.add_field(name="Unloaded ({})".format(len(unloaded)), value=", ".join(unloaded) if unloaded != [] else "None", inline=False) 212 | await ctx.send(embed=s) 213 | 214 | @commands.command(hidden=True) 215 | @checks.is_owner() 216 | async def updateavatar(self, ctx, *, url=None): 217 | if not url: 218 | if ctx.message.attachments: 219 | url = ctx.message.attachments[0].url 220 | else: 221 | await ctx.send("Provide a valid image :no_entry:") 222 | return 223 | avatar = requests.get(url).content 224 | try: 225 | await self.bot.user.edit(password=None, avatar=avatar) 226 | except: 227 | return await ctx.send("Clap you've changed my profile picture too many times") 228 | await ctx.send("I have changed my profile picture") 229 | 230 | @commands.command(hidden=True) 231 | @checks.is_owner() 232 | async def httpunban(self, ctx, server_id: str, user_id: str): 233 | user = await self.bot.get_user_info(user_id) 234 | server = self.bot.get_guild(server_id) 235 | await self.bot.http.unban(user_id, server_id) 236 | await ctx.send("I have unbanned **{}** from **{}**".format(user, server)) 237 | 238 | @commands.command(hidden=True) 239 | @checks.is_owner() 240 | async def msg(self, ctx, channel_id, *, text): 241 | await ctx.message.delete() 242 | await self.bot.http.send_message(channel_id, text) 243 | 244 | @commands.command(hidden=True) 245 | @checks.is_owner() 246 | async def shutdown(self, ctx): 247 | await ctx.send("Shutting down...") 248 | await self.bot.logout() 249 | 250 | async def on_guild_join(self, guild): 251 | channel = self.bot.get_channel(493439822682259497) 252 | if channel: 253 | guilds = len(self.bot.guilds) 254 | if guilds % 100 == 0: 255 | await channel.send("{:,} servers :tada:".format(guilds)) 256 | 257 | async def on_guild_remove(self, guild): 258 | channel = self.bot.get_channel(493439822682259497) 259 | if channel: 260 | guilds = len(self.bot.guilds) 261 | if guilds % 100 != 0: 262 | for x in await channel.history(limit=1).flatten(): 263 | if int(x.content.split(" ")[0].replace(",", "")) > guilds: 264 | await x.delete() 265 | 266 | async def on_command(self, ctx, *args, **kwargs): 267 | guild = self.bot.get_guild(330399610273136641) 268 | channel = guild.get_channel(507684635673886742) 269 | webhook = discord.utils.get(await channel.webhooks(), id=507684441020170251) 270 | if checks.is_owner_c(ctx.author): 271 | ctx.command.reset_cooldown(ctx) 272 | try: 273 | s=discord.Embed(colour=0xffff00, timestamp=ctx.message.edited_at if ctx.message.edited_at else ctx.message.created_at) 274 | s.add_field(name="Message", value="Content: {}\nID: {}".format(ctx.message.content, ctx.message.id), inline=False) 275 | s.add_field(name="Channel", value="Name: {}\nID: {}".format(ctx.channel.name, ctx.channel.id), inline=False) 276 | s.add_field(name="Guild", value="Name: {}\nID: {}\nShard: {}\nMember Count: {:,}".format(ctx.guild.name, ctx.guild.id, ctx.guild.shard_id + 1, ctx.guild.member_count), inline=False) 277 | s.add_field(name="Author", value="User: {}\nID: {}".format(ctx.author, ctx.author.id), inline=False) 278 | s.add_field(name="Command", value="Prefix: {}\nCommand: {}\nArguments: {}".format(ctx.prefix, ctx.command, kwargs), inline=False) 279 | s.add_field(name="Attachments", value="\n".join(map(lambda x: x.url, ctx.message.attachments)) if ctx.message.attachments else "None", inline=False) 280 | await webhook.send(embed=s) 281 | except Exception as e: 282 | await webhook.send(e) 283 | 284 | def setup(bot, connection): 285 | bot.add_cog(owner(bot, connection)) -------------------------------------------------------------------------------- /Sx4/cogs/page.py: -------------------------------------------------------------------------------- 1 | import discord 2 | import asyncio 3 | from discord.ext import commands 4 | from utils.PagedResult import PagedResult 5 | from utils.PagedResult import PagedResultData 6 | from random import choice as randchoice 7 | import time 8 | import datetime 9 | import random 10 | from utils import checks 11 | import numbers 12 | import os 13 | from random import choice 14 | from random import randint 15 | from copy import deepcopy 16 | from collections import namedtuple, defaultdict, deque 17 | from copy import deepcopy 18 | from enum import Enum 19 | import asyncio 20 | from difflib import get_close_matches 21 | 22 | class page: 23 | def __init__(self, bot, connection): 24 | self.bot = bot 25 | self.db = connection 26 | 27 | @commands.command(no_pm=True, aliases=["sroles", "roles"]) 28 | async def serverroles(self, ctx): 29 | server = ctx.message.guild 30 | channel = ctx.message.channel 31 | author = ctx.message.author 32 | 33 | if server.id not in PagedResultData.paged_results: 34 | PagedResultData.paged_results[server.id] = dict() 35 | 36 | if channel.id not in PagedResultData.paged_results[server.id]: 37 | PagedResultData.paged_results[server.id][channel.id] = dict() 38 | 39 | paged_result = PagedResult(ctx.guild.roles[::-1], lambda role: role.mention) 40 | paged_result.list_indexes = True 41 | paged_result.selectable = False 42 | 43 | message = await channel.send(embed=paged_result.get_current_page_embed()) 44 | 45 | paged_result.message_id = message.id 46 | 47 | PagedResultData.paged_results[server.id][channel.id][author.id] = paged_result 48 | 49 | @commands.command() 50 | async def members(self, ctx): 51 | server = ctx.message.guild 52 | channel = ctx.message.channel 53 | author = ctx.message.author 54 | 55 | if server.id not in PagedResultData.paged_results: 56 | PagedResultData.paged_results[server.id] = dict() 57 | 58 | if channel.id not in PagedResultData.paged_results[server.id]: 59 | PagedResultData.paged_results[server.id][channel.id] = dict() 60 | 61 | paged_result = PagedResult(list(server.members), lambda member: member.mention) 62 | paged_result.list_indexes = True 63 | paged_result.selectable = True 64 | 65 | async def selected(event): 66 | joined_server = event.entry.joined_at.strftime("%d %b %Y %H:%M") 67 | joined_discord = event.entry.created_at.strftime("%d %b %Y %H:%M") 68 | if event.entry.status == discord.Status.online: 69 | status="Online<:online:361440486998671381>" 70 | if event.entry.status == discord.Status.idle: 71 | status="Idle<:idle:361440487233814528>" 72 | if event.entry.status == discord.Status.do_not_disturb: 73 | status="DND<:dnd:361440487179157505>" 74 | if event.entry.status == discord.Status.offline: 75 | status="Offline<:offline:361445086275567626>" 76 | description="" 77 | if not event.entry.activity: 78 | pass 79 | elif event.entry.activity: 80 | description="{} {}".format(event.entry.activity.type.name.title(), event.entry.activity.name) 81 | elif event.entry.activity.url: 82 | description="Streaming [{}]({})".format(event.entry.activity.name, event.entry.activity.url) 83 | s=discord.Embed(description=description, colour=event.entry.colour, timestamp=__import__('datetime').datetime.utcnow()) 84 | s.set_author(name=event.entry.name, icon_url=event.entry.avatar_url) 85 | s.set_thumbnail(url=event.entry.avatar_url) 86 | s.add_field(name="Joined Discord", value=joined_discord) 87 | s.add_field(name="Joined {}".format(server .name), value=joined_server) 88 | s.add_field(name="Name", value="{}".format(event.entry.name)) 89 | s.add_field(name="Nickname", value="{}".format(event.entry.nick)) 90 | s.add_field(name="Discriminator", value="#{}".format(event.entry.discriminator)) 91 | s.add_field(name="Status", value="{}".format(status)) 92 | s.add_field(name="User's Colour", value="{}".format(event.entry.colour)) 93 | s.add_field(name="User's ID", value="{}".format(event.entry.id)) 94 | s.set_footer(text="Requested by {}".format(author)) 95 | s.add_field(name="Highest Role", value=event.entry.top_role) 96 | s.add_field(name="Roles", value=len(event.entry.roles)) 97 | await channel.send(embed=s) 98 | 99 | paged_result.on_select = selected 100 | 101 | message = await channel.send(embed=paged_result.get_current_page_embed()) 102 | 103 | paged_result.message_id = message.id 104 | 105 | PagedResultData.paged_results[server.id][channel.id][author.id] = paged_result 106 | 107 | async def on_message(self, message): 108 | # Not sure how you store the other stuff but I suppose you do something like this 109 | server = message.guild 110 | channel = message.channel 111 | author = message.author 112 | 113 | paged_results = PagedResultData.paged_results 114 | 115 | paged_result = None 116 | if server.id in paged_results: 117 | if channel.id in paged_results[server.id]: 118 | if author.id in paged_results[server.id][channel.id]: 119 | paged_result = paged_results[server.id][channel.id][author.id] 120 | 121 | if paged_result is None: 122 | return 123 | 124 | page_message = None 125 | 126 | try: 127 | # Get message from paged_result.message_id and set message to it 128 | page_message = await channel.get_message(paged_result.message_id) 129 | except TypeError: 130 | pass 131 | 132 | if message.content == "next page": 133 | if paged_result.next_page(): 134 | await message.delete() 135 | if page_message == None: 136 | # Send paged_result.get_current_page_embed() and set paged_result.message_id to its id 137 | temp_message = await channel.send(embed=paged_result.get_current_page_embed()) 138 | paged_result.message_id = temp_message.id 139 | else: 140 | # Edit the message by paged_result.message_id to paged_result.get_current_page_embed() 141 | await page_message.edit(embed=paged_result.get_current_page_embed()) 142 | elif message.content == "previous page": 143 | if paged_result.previous_page(): 144 | await message.delete() 145 | if page_message == None: 146 | # Send paged_result.get_current_page_embed() and set paged_result.message_id to its id 147 | temp_message = await channel.send(embed=paged_result.get_current_page_embed()) 148 | paged_result.message_id = temp_message.id 149 | else: 150 | # Edit the message by paged_result.message_id to paged_result.get_current_page_embed() 151 | await page_message.edit(embed=paged_result.get_current_page_embed()) 152 | elif message.content.startswith("go to page "): 153 | number = None 154 | try: 155 | number = int(message.content[len("go to page "):]) 156 | except ValueError: 157 | await channel.send("Invalid page number") 158 | 159 | return 160 | 161 | if paged_result.set_page(number): 162 | await message.delete() 163 | if page_message == None: 164 | # Send paged_result.get_current_page_embed() and set paged_result.message_id to its id 165 | temp_message = await channel.send(embed=paged_result.get_current_page_embed()) 166 | paged_result.message_id = temp_message.id 167 | else: 168 | # Edit the message by paged_result.message_id to paged_result.get_current_page_embed() 169 | await page_message.edit(embed=paged_result.get_current_page_embed()) 170 | else: 171 | await channel.send("Invalid page number") 172 | return 173 | elif message.content == "cancel": 174 | if page_message != None: 175 | # Delete message by paged_result.message_id 176 | await message.delete() 177 | await page_message.delete() 178 | 179 | del paged_results[server.id][channel.id][author.id] 180 | 181 | if paged_result.selectable: 182 | number = None 183 | try: 184 | number = int(message.content) 185 | except ValueError: 186 | return 187 | 188 | if number > 0 and number <= paged_result.entries_per_page: 189 | del paged_results[server.id][channel.id][author.id] 190 | 191 | await message.delete() 192 | await page_message.delete() 193 | 194 | await paged_result.select(number) 195 | 196 | def setup(bot, connection): 197 | bot.add_cog(page(bot, connection)) -------------------------------------------------------------------------------- /Sx4/cogs/serverlog.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | from datetime import datetime 4 | import os 5 | import re 6 | import logging 7 | import asyncio 8 | import random 9 | import time 10 | from utils import dateify 11 | 12 | 13 | class serverlog: 14 | """Shows when the bot joins and leaves a server""" 15 | 16 | def __init__(self, bot, connection): 17 | self.bot = bot 18 | self.db = connection 19 | 20 | async def on_guild_join(self, guild): 21 | try: 22 | server = guild 23 | s=discord.Embed(description="I am now in {:,} servers and connected to {:,} users".format(len(self.bot.guilds), len(self.bot.users)), colour=0x5fe468, timestamp=datetime.utcnow()) 24 | s.set_author(name="Joined Server!", icon_url=self.bot.user.avatar_url) 25 | s.add_field(name="Server Name", value=server.name) 26 | s.add_field(name="Server ID", value=server.id) 27 | s.add_field(name="Server Owner", value="{}\n{}".format(server.owner, server.owner.id)) 28 | s.add_field(name="Total members", value="{} members".format(len(server.members))) 29 | channels = server.text_channels 30 | try: 31 | if len(await server.invites()) > 0: 32 | for x in await server.invites(): 33 | if x.max_age == 0: 34 | invite = x.url 35 | break 36 | else: 37 | invite = None 38 | except: 39 | invite = None 40 | try: 41 | if invite: 42 | s.add_field(name="Server Invite", value=invite) 43 | except: 44 | pass 45 | mutual = list(map(lambda x: x.name, sorted([x for x in self.bot.guilds if server.owner in x.members and x != server], key=lambda x: x.member_count, reverse=True))) 46 | if len(mutual) > 15: 47 | s.add_field(name="Mutual Servers (Owner)", value="\n".join(mutual[:15]) + "\n and {} more...".format(len(mutual)-15)) 48 | else: 49 | s.add_field(name="Mutual Servers (Owner)", value="\n".join(mutual) if len(mutual) != 0 else "None") 50 | if server.icon_url: 51 | s.set_thumbnail(url=server.icon_url) 52 | else: 53 | s.set_thumbnail(url="https://cdn.discordapp.com/attachments/344091594972069888/396285725605363712/no_server_icon.png") 54 | await self.bot.get_channel(396013262514421761).send(embed=s) 55 | if server.system_channel: 56 | try: 57 | await server.system_channel.send("Thanks for adding me (I'm now in {:,} servers, Thank you for contributing)!\nMy prefix is `s?`\nAll my info and commands can be found in `s?help`\nIf you need any help feel free to join the support server: https://discord.gg/PqJNcfB".format(len(self.bot.guilds))) 58 | return 59 | except: 60 | pass 61 | for channel in channels: 62 | try: 63 | await channel.send("Thanks for adding me (I'm now in {:,} servers, Thank you for contributing)!\nMy prefix is `s?`\nAll my info and commands can be found in `s?help`\nIf you need any help feel free to join the support server: https://discord.gg/PqJNcfB".format(len(self.bot.guilds))) 64 | break 65 | except: 66 | pass 67 | except Exception as e: 68 | await self.bot.get_channel(396013262514421761).send(e) 69 | 70 | async def on_guild_remove(self, guild): 71 | try: 72 | server = guild 73 | s=discord.Embed(description="I am now in {:,} servers and connected to {:,} users".format(len(self.bot.guilds), len(self.bot.users)), colour=0xf84b50, timestamp=datetime.utcnow()) 74 | s.set_author(name="Left Server!", icon_url=self.bot.user.avatar_url) 75 | s.add_field(name="Server Name", value=server.name) 76 | s.add_field(name="Server ID", value=server.id) 77 | s.add_field(name="Server Owner", value="{}\n{}".format(server.owner, server.owner.id)) 78 | s.add_field(name="Total members", value="{} members".format(len(server.members))) 79 | try: 80 | s.add_field(name="Stayed For", value=dateify.get((datetime.utcnow() - server.me.joined_at).total_seconds()), inline=False) 81 | except Exception as e: 82 | pass 83 | if server.icon_url: 84 | s.set_thumbnail(url=server.icon_url) 85 | else: 86 | s.set_thumbnail(url="https://cdn.discordapp.com/attachments/344091594972069888/396285725605363712/no_server_icon.png") 87 | await self.bot.get_channel(396013262514421761).send(embed=s) 88 | except Exception as e: 89 | await self.bot.get_channel(396013262514421761).send(e) 90 | 91 | 92 | def setup(bot, connection): 93 | bot.add_cog(serverlog(bot, connection)) -------------------------------------------------------------------------------- /Sx4/cogs/serverpost.py: -------------------------------------------------------------------------------- 1 | import discord 2 | import asyncio 3 | from discord.ext import commands 4 | from random import choice as randchoice 5 | import time 6 | import datetime 7 | from utils import checks 8 | from urllib.parse import urlencode 9 | from urllib.request import Request, urlopen 10 | import requests 11 | from cogs import mod 12 | from utils import Token 13 | import aiohttp 14 | import json 15 | import traceback 16 | import sys 17 | import os 18 | import subprocess 19 | 20 | dbltoken = Token.dbl() 21 | dbotspwtoken = Token.dbpw() 22 | botspacetoken = Token.botlistspace() 23 | dbpwurl = "https://discord.bots.gg/api/v1/bots/440996323156819968/stats" 24 | url = "https://discordbots.org/api/bots/440996323156819968/stats" 25 | botspaceurl = "https://api.botlist.space/v1/bots/440996323156819968/" 26 | headers = {"Authorization" : dbltoken} 27 | headersdb = {"Authorization" : dbotspwtoken, "Content-Type" : "application/json"} 28 | headersbs = {"Authorization" : botspacetoken, "Content-Type" : "application/json"} 29 | 30 | class serverpost: 31 | def __init__(self, bot, connection): 32 | self.bot = bot 33 | self.db = connection 34 | self.task = bot.loop.create_task(self.server_post()) 35 | 36 | def __unload(self): 37 | self.task.cancel() 38 | 39 | @commands.command(hidden=True) 40 | @checks.is_owner() 41 | async def post(self, ctx): 42 | dblpayloadservers = {"server_count": len(self.bot.guilds), "shard_count": self.bot.shard_count} 43 | payloadservers = {"server_count": len(self.bot.guilds), "shards": self.bot.shard_count} 44 | dbpwpayload = {"guildCount": len(self.bot.guilds), "shardCount": self.bot.shard_count} 45 | s=discord.Embed() 46 | s.set_author(name="Server Count Posting", icon_url=self.bot.user.avatar_url) 47 | try: 48 | requests.post(url, data=dblpayloadservers, headers=headers) 49 | s.add_field(name="Discord Bot List", value="Posted") 50 | except Exception as e: 51 | s.add_field(name="Discord Bot List", value=e) 52 | try: 53 | requests.post(dbpwurl, data=dbpwpayload, headers=headersdb) 54 | s.add_field(name="Discord Bots.pw", value="Posted") 55 | except Exception as e: 56 | s.add_field(name="Discord Bots.pw", value=e) 57 | try: 58 | requests.post(botspaceurl, data=json.dumps(payloadservers), headers=headersbs) 59 | s.add_field(name="BotList.Space", value="Posted") 60 | except Exception as e: 61 | s.add_field(name="BotList.Space", value=e) 62 | await ctx.send(embed=s) 63 | 64 | 65 | async def server_post(self): 66 | while not self.bot.is_closed(): 67 | dblpayloadservers = {"server_count": len(self.bot.guilds), "shard_count": self.bot.shard_count} 68 | payloadservers = {"server_count": len(self.bot.guilds), "shards": self.bot.shard_count} 69 | dbpwpayload = {"guildCount": len(self.bot.guilds), "shardCount": self.bot.shard_count} 70 | try: 71 | requests.post(url, data=dblpayloadservers, headers=headers) 72 | except: 73 | pass 74 | try: 75 | requests.post(dbpwurl, data=json.dumps(dbpwpayload), headers=headersdb) 76 | except: 77 | pass 78 | try: 79 | requests.post(botspaceurl, data=json.dumps(payloadservers), headers=headersbs) 80 | except: 81 | pass 82 | await asyncio.sleep(3600) 83 | 84 | def setup(bot, connection): 85 | bot.add_cog(serverpost(bot, connection)) -------------------------------------------------------------------------------- /Sx4/cogs/status.py: -------------------------------------------------------------------------------- 1 | import os 2 | import discord 3 | from discord.ext import commands 4 | from discord.utils import find 5 | from random import randint 6 | import asyncio 7 | 8 | class status: 9 | """Bot Status""" 10 | 11 | def __init__(self, bot, connection): 12 | self.bot = bot 13 | self.db = connection 14 | self._task = bot.loop.create_task(self.display_status()) 15 | 16 | def __unload(self): 17 | self._task.cancel() 18 | 19 | async def display_status(self): 20 | i = 0 21 | while not self.bot.is_closed(): 22 | try: 23 | statuses = [ 24 | "{:,} servers".format(len(self.bot.guilds)), 25 | "{:,} users".format(len(self.bot.users)) 26 | ] 27 | new_status = statuses[i] 28 | await self.bot.change_presence(activity=discord.Activity(name=new_status, type=discord.ActivityType.watching)) 29 | except Exception as e: 30 | await self.bot.get_channel(439745234285625355).send(e) 31 | if i == len(statuses) - 1: 32 | i = 0 33 | else: 34 | i += 1 35 | await asyncio.sleep(300) 36 | 37 | def setup(bot, connection): 38 | n = status(bot, connection) 39 | bot.add_cog(n) -------------------------------------------------------------------------------- /Sx4/cogs/welcomer.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | from utils import checks 4 | from datetime import datetime 5 | from collections import deque, defaultdict 6 | import os 7 | import re 8 | from utils import arghelp, dateify 9 | from . import owner as dev 10 | import math 11 | from io import BytesIO 12 | from urllib.request import Request, urlopen 13 | import logging 14 | import rethinkdb as r 15 | import aiohttp 16 | import urllib 17 | import requests 18 | import cogs.image as img 19 | from PIL import Image, ImageDraw, ImageFont, ImageOps 20 | import asyncio 21 | import random 22 | import time 23 | 24 | class welcomer: 25 | """Shows when a user joins and leaves a server""" 26 | 27 | def __init__(self, bot, connection): 28 | self.bot = bot 29 | self.db = connection 30 | self.avatar = None 31 | 32 | @commands.group(usage="") 33 | @checks.has_permissions("manage_messages") 34 | async def imgwelcomer(self, ctx): 35 | """Make the bot welcome people for you with an image""" 36 | if ctx.invoked_subcommand is None: 37 | await arghelp.send(self.bot, ctx) 38 | else: 39 | r.table("welcomer").insert({"id": str(ctx.guild.id), "toggle": False, "channel": None, 40 | "message": "{user.mention}, Welcome to **{server}**. Enjoy your time here! The server now has {server.members} members.", 41 | "message-leave": "**{user.name}** has just left **{server}**. Bye **{user.name}**!", "dm": False, "imgwelcomertog": False, 42 | "banner": None, "leavetoggle": True, "embed": False, "embedcolour": None}).run(self.db, durability="soft") 43 | 44 | @imgwelcomer.command(name="toggle") 45 | @checks.has_permissions("manage_messages") 46 | async def _toggle(self, ctx): 47 | "toggle image welcomer on or off" 48 | server = ctx.guild 49 | data = r.table("welcomer").get(str(server.id)) 50 | if data["imgwelcomertog"].run(self.db, durability="soft") == True: 51 | data.update({"imgwelcomertog": False}).run(self.db, durability="soft") 52 | await ctx.send("Image Welcomer has been **Disabled**") 53 | return 54 | if data["imgwelcomertog"].run(self.db, durability="soft") == False: 55 | data.update({"imgwelcomertog": True}).run(self.db, durability="soft") 56 | await ctx.send("Image Welcomer has been **Enabled**") 57 | return 58 | 59 | @imgwelcomer.command() 60 | @checks.has_permissions("manage_messages") 61 | async def banner(self, ctx, banner: str=None): 62 | """Adds a banner to the image welcomer, when added the image welcomer changes resolution to 2560 x 1440 so a banner that size would be ideal""" 63 | author = ctx.author 64 | server = ctx.guild 65 | data = r.table("welcomer").get(str(server.id)) 66 | if not banner: 67 | if ctx.message.attachments: 68 | try: 69 | banner = ctx.message.attachments[0].url 70 | data.update({"banner": banner}).run(self.db, durability="soft") 71 | return await ctx.send("Your banner for image welcomer has been set.") 72 | except: 73 | pass 74 | data.update({"banner": None}).run(self.db, durability="soft") 75 | await ctx.send("Your banner for image welcomer has been reset.") 76 | return 77 | if ".webp" in banner: 78 | return await ctx.send("WEBP files are not supported :no_entry:") 79 | try: 80 | img.getImage(banner) 81 | except: 82 | return await ctx.send("Invalid image url :no_entry:") 83 | data.update({"banner": banner}).run(self.db, durability="soft") 84 | await ctx.send("Your banner for image welcomer has been set.") 85 | 86 | 87 | @commands.group(usage="") 88 | async def welcomer(self, ctx): 89 | """Make the bot welcome people for you""" 90 | if ctx.invoked_subcommand is None: 91 | await arghelp.send(self.bot, ctx) 92 | else: 93 | r.table("welcomer").insert({"id": str(ctx.guild.id), "toggle": False, "channel": None, 94 | "message": "{user.mention}, Welcome to **{server}**. Enjoy your time here! The server now has {server.members} members.", 95 | "message-leave": "**{user.name}** has just left **{server}**. Bye **{user.name}**!", "dm": False, "imgwelcomertog": False, 96 | "banner": None, "leavetoggle": True, "embed": False, "embedcolour": None}).run(self.db, durability="soft") 97 | 98 | @welcomer.command() 99 | @checks.has_permissions("manage_messages") 100 | async def toggle(self, ctx): 101 | """Toggle welcomer on or off""" 102 | server = ctx.guild 103 | data = r.table("welcomer").get(str(server.id)) 104 | if data["toggle"].run(self.db, durability="soft") == True: 105 | data.update({"toggle": False}).run(self.db, durability="soft") 106 | await ctx.send("Welcomer has been **Disabled**") 107 | return 108 | if data["toggle"].run(self.db, durability="soft") == False: 109 | data.update({"toggle": True}).run(self.db, durability="soft") 110 | await ctx.send("Welcomer has been **Enabled**") 111 | return 112 | 113 | @welcomer.command() 114 | @checks.has_permissions("manage_messages") 115 | async def embed(self, ctx): 116 | server = ctx.guild 117 | data = r.table("welcomer").get(str(server.id)) 118 | if data["embed"].run(self.db, durability="soft") == True: 119 | data.update({"embed": False}).run(self.db, durability="soft") 120 | await ctx.send("Welcome messages will no longer be embedded.") 121 | return 122 | if data["embed"].run(self.db, durability="soft") == False: 123 | data.update({"embed": True}).run(self.db, durability="soft") 124 | await ctx.send("Welcome messages will now be embedded.") 125 | return 126 | 127 | @welcomer.command() 128 | @checks.has_permissions("manage_messages") 129 | async def embedcolour(self, ctx, colour: str): 130 | server = ctx.guild 131 | data = r.table("welcomer").get(str(server.id)) 132 | if colour.lower() in ["none", "off"]: 133 | await ctx.send("Your embed colour has been reset.") 134 | return data.update({"embedcolour": None}).run(self.db, durability="soft") 135 | if colour.startswith("#"): 136 | colour = colour[1:] 137 | try: 138 | discord.Colour(int(colour, 16)) 139 | except: 140 | return await ctx.send("Invalid hex :no_entry:") 141 | await ctx.send("Updated your embed colour to **{}**".format(str(colour))) 142 | data.update({"embedcolour": int(colour, 16)}).run(self.db, durability="soft") 143 | 144 | @welcomer.command() 145 | @checks.has_permissions("manage_messages") 146 | async def dmtoggle(self, ctx): 147 | """Toggle whether you want the bot to dm the user or not""" 148 | server = ctx.guild 149 | data = r.table("welcomer").get(str(server.id)) 150 | if data["dm"].run(self.db, durability="soft") == True: 151 | data.update({"dm": False}).run(self.db, durability="soft") 152 | await ctx.send("Welcome messages will now be sent in the welcomer channel.") 153 | return 154 | if data["dm"].run(self.db, durability="soft") == False: 155 | data.update({"dm": True}).run(self.db, durability="soft") 156 | await ctx.send("Welcome messages will now be sent in dms.") 157 | return 158 | 159 | @welcomer.command() 160 | @checks.has_permissions("manage_messages") 161 | async def leavetoggle(self, ctx): 162 | """Toggle if you want the leave message or not""" 163 | server = ctx.guild 164 | data = r.table("welcomer").get(str(server.id)) 165 | if data["leavetoggle"].run(self.db, durability="soft") == True: 166 | data.update({"leavetoggle": False}).run(self.db, durability="soft") 167 | await ctx.send("Leave messages are now disabled.") 168 | return 169 | if data["leavetoggle"].run(self.db, durability="soft") == False: 170 | data.update({"leavetoggle": True}).run(self.db, durability="soft") 171 | await ctx.send("Leave messages are now enabled.") 172 | return 173 | 174 | @welcomer.command() 175 | @checks.has_permissions("manage_messages") 176 | async def joinmessage(self, ctx, *, message: str=None): 177 | """Set the joining message""" 178 | server = ctx.guild 179 | data = r.table("welcomer").get(str(server.id)) 180 | if not message: 181 | desc = """{server} = Your server name 182 | {user.mention} = Mentions the user who joins 183 | {user.name} = The username of the person who joined 184 | {user} = The username + discriminator 185 | {server.members} = The amount of members in your server 186 | {server.members.prefix} = The amount of members plus a prefix ex 232nd 187 | {user.created.length} = How long the users account has been created for ex 1 year 2 months 3 days 188 | **Make sure you keep the {} brackets in the message** 189 | 190 | Example: `s?welcomer joinmessage {user.mention}, Welcome to **{server}**. We now have **{server.members}** members :tada:`""" 191 | s=discord.Embed(description=desc, colour=ctx.message.author.colour) 192 | s.set_author(name="Examples on setting your message", icon_url=self.bot.user.avatar_url) 193 | await ctx.send(embed=s) 194 | return 195 | data.update({"message": message}).run(self.db, durability="soft") 196 | await ctx.send("Your message has been set <:done:403285928233402378>") 197 | 198 | @welcomer.command() 199 | @checks.has_permissions("manage_messages") 200 | async def leavemessage(self, ctx, *, message: str=None): 201 | """Set the leaving message""" 202 | server = ctx.guild 203 | data = r.table("welcomer").get(str(server.id)) 204 | if not message: 205 | desc = """{server} = Your server name 206 | {user.mention} = Mentions the user who joins 207 | {user.name} = The username of the person who joined 208 | {user} = The username + discriminator 209 | {server.members} = The amount of members in your server 210 | {server.members.prefix} = The amount of members plus a prefix ex 232nd 211 | {user.created.length} = How long the users account has been created for ex 1 year 2 months 3 days 212 | **Make sure you keep the {} brackets in the message** 213 | 214 | Example: `s?welcomer leavemessage {user.mention}, Goodbye!`""" 215 | s=discord.Embed(description=desc, colour=ctx.message.author.colour) 216 | s.set_author(name="Examples on setting your message", icon_url=self.bot.user.avatar_url) 217 | await ctx.send(embed=s) 218 | return 219 | data.update({"message-leave": message}).run(self.db, durability="soft") 220 | await ctx.send("Your message has been set <:done:403285928233402378>") 221 | 222 | @welcomer.command() 223 | async def preview(self, ctx): 224 | """Look at the preview of your welcomer""" 225 | server = ctx.guild 226 | author = ctx.author 227 | data = r.table("welcomer").get(str(server.id)).run(self.db, durability="soft") 228 | message = data["message"] 229 | message = self.get_welcomer_message(server, author, message) 230 | message2 = data["message-leave"] 231 | message2 = self.get_welcomer_message(server, author, message2) 232 | s=discord.Embed(description=message, timestamp=datetime.utcnow(), colour=discord.Colour(data["embedcolour"]) if data["embedcolour"] else discord.Embed.Empty) 233 | s.set_author(name=str(author), icon_url=author.avatar_url) 234 | if data["imgwelcomertog"] and data["toggle"]: 235 | if data["embed"]: 236 | image = await self.image_welcomer(author, server) 237 | s.set_image(url="attachment://welcomer." + image.filename.split(".")[1]) 238 | try: 239 | await ctx.send(embed=s, file=image) 240 | except discord.errors.HTTPException: 241 | await ctx.send("The welcomer banner you have sent makes the file size more than 8mb therefore I'm unable to send it :no_entry:") 242 | else: 243 | image = await self.image_welcomer(author, server) 244 | await ctx.send(content=message, file=image) 245 | elif data["imgwelcomertog"] and not data["toggle"]: 246 | image = await self.image_welcomer(author, server) 247 | try: 248 | await ctx.send(file=image) 249 | except discord.errors.HTTPException: 250 | await ctx.send("The welcomer banner you have sent makes the file size more than 8mb therefore I'm unable to send it :no_entry:") 251 | elif not data["imgwelcomertog"] and data["toggle"]: 252 | if data["embed"]: 253 | await ctx.send(embed=s) 254 | else: 255 | await ctx.send(message) 256 | else: 257 | return await ctx.send("You have neither image welcomer or welcomer enabled :no_entry:") 258 | if data["leavetoggle"]: 259 | if data["embed"]: 260 | s=discord.Embed(description=message2, timestamp=datetime.utcnow(), colour=discord.Colour(data["embedcolour"]) if data["embedcolour"] else discord.Embed.Empty) 261 | s.set_author(name=str(author), icon_url=author.avatar_url) 262 | await ctx.send(embed=s) 263 | else: 264 | await ctx.send(message2) 265 | 266 | @welcomer.command() 267 | @checks.has_permissions("manage_messages") 268 | async def channel(self, ctx, channel: discord.TextChannel): 269 | """Set the channel of where you want the bot to welcome people""" 270 | server = ctx.guild 271 | data = r.table("welcomer").get(str(server.id)) 272 | data.update({"channel": str(channel.id)}).run(self.db, durability="soft") 273 | await ctx.send("<#{}> has been set as the join-leave channel".format(channel.id)) 274 | 275 | @welcomer.command() 276 | async def stats(self, ctx): 277 | """Look at the settings of your welcomer""" 278 | server = ctx.guild 279 | data = r.table("welcomer").get(str(server.id)).run(self.db, durability="soft") 280 | message = "`" + data["message"] + "`" 281 | message2 = "`" + data["message-leave"] + "`" 282 | s=discord.Embed(colour=0xfff90d) 283 | s.set_author(name="Welcomer Settings", icon_url=self.bot.user.avatar_url) 284 | if data["toggle"] == True: 285 | msg = "Enabled" 286 | if data["toggle"] == False: 287 | msg = "Disabled" 288 | if data["dm"] == True: 289 | msg2 = "Enabled" 290 | if data["dm"] == False: 291 | msg2 = "Disabled" 292 | if data["imgwelcomertog"] == True: 293 | img = "Enabled" 294 | else: 295 | img = "Disabled" 296 | if data["leavetoggle"] == False: 297 | message2 = "Disabled" 298 | s.add_field(name="Welcomer status", value=msg) 299 | if not data["channel"]: 300 | channel = "Not set" 301 | else: 302 | channel = "<#{}>".format(data["channel"]) 303 | s.add_field(name="Welcomer channel", value=channel) 304 | s.add_field(name="DM Welcomer", value=msg2) 305 | s.add_field(name="Image Welcomer", value=img) 306 | s.add_field(name="Embed", value="Message: {}\nColour: {}".format("Yes" if data["embed"] else "No", discord.Colour(data["embedcolour"]) if data["embedcolour"] else "Default")) 307 | s.add_field(name="Join message", value=message, inline=False) 308 | s.add_field(name="Leave message", value=message2, inline=False) 309 | await ctx.send(embed=s) 310 | 311 | def prefixfy(self, server): 312 | number = str(len(server.members)) 313 | num = len(number) - 2 314 | num2 = len(number) - 1 315 | if int(number[num:]) < 11 or int(number[num:]) > 13: 316 | if int(number[num2:]) == 1: 317 | prefix = "st" 318 | elif int(number[num2:]) == 2: 319 | prefix = "nd" 320 | elif int(number[num2:]) == 3: 321 | prefix = "rd" 322 | else: 323 | prefix = "th" 324 | else: 325 | prefix = "th" 326 | return "{:,}".format(int(number)) + prefix 327 | 328 | 329 | async def on_member_join(self, member): 330 | server = member.guild 331 | data = r.table("welcomer").get(str(server.id)).run(self.db, durability="soft") 332 | message = data["message"] 333 | channel = data["channel"] 334 | channel = server.get_channel(int(channel)) 335 | if not channel: 336 | if server.system_channel: 337 | channel = server.system_channel 338 | message = self.get_welcomer_message(server, member, message) 339 | s=discord.Embed(description=message, timestamp=datetime.utcnow(), colour=discord.Colour(data["embedcolour"]) if data["embedcolour"] else discord.Embed.Empty) 340 | s.set_author(name=str(member), icon_url=member.avatar_url) 341 | s.set_image(url="attachment://welcomer.png") 342 | if data["toggle"] == True and data["imgwelcomertog"] == True: 343 | if data["dm"] == True: 344 | if data["embed"]: 345 | image = await self.image_welcomer(member, server) 346 | if image: 347 | s.set_image(url="attachment://welcomer.{}".format(image.filename.split(".")[1])) 348 | await member.send(embed=s, file=image) 349 | else: 350 | await member.send(content=message, file=await self.image_welcomer(member, server)) 351 | elif data["dm"] == False: 352 | if data["embed"]: 353 | image = await self.image_welcomer(member, server) 354 | if image: 355 | s.set_image(url="attachment://welcomer.{}".format(image.filename.split(".")[1])) 356 | await self.webhook_send(channel=channel, embed=s, file=image) 357 | else: 358 | await self.webhook_send(channel=channel, content=message, file=await self.image_welcomer(member, server)) 359 | elif data["toggle"] == True and data["imgwelcomertog"] == False: 360 | if data["dm"] == True: 361 | if data["embed"]: 362 | await member.send(embed=s) 363 | else: 364 | await member.send(content=message) 365 | elif data["dm"] == False: 366 | if data["embed"]: 367 | await self.webhook_send(channel=channel, embed=s) 368 | else: 369 | await self.webhook_send(channel=channel, content=message) 370 | elif data["toggle"] == False and data["imgwelcomertog"] == True: 371 | if data["dm"] == True: 372 | await member.send(file=await self.image_welcomer(member, server)) 373 | elif data["dm"] == False: 374 | await self.webhook_send(channel=channel, file=await self.image_welcomer(member, server)) 375 | 376 | async def on_member_remove(self, member): 377 | server = member.guild 378 | data = r.table("welcomer").get(str(server.id)).run(self.db, durability="soft") 379 | if data["dm"] == True: 380 | return 381 | if data["leavetoggle"] == False: 382 | return 383 | channel = data["channel"] 384 | channel = server.get_channel(int(channel)) 385 | if not channel: 386 | if server.system_channel: 387 | channel = server.system_channel 388 | message = data["message-leave"] 389 | if data["toggle"] == True: 390 | message = self.get_welcomer_message(server, member, message) 391 | if data["embed"]: 392 | s=discord.Embed(description=message, timestamp=datetime.utcnow(), colour=discord.Colour(data["embedcolour"]) if data["embedcolour"] else discord.Embed.Empty) 393 | s.set_author(name=str(member), icon_url=member.avatar_url) 394 | await self.webhook_send(channel=channel, embed=s) 395 | else: 396 | await self.webhook_send(channel=channel, content=message) 397 | 398 | def get_welcomer_message(self, guild, member, message: str): 399 | message = message.replace("{server}", guild.name) 400 | message = message.replace("{user.mention}", member.mention) 401 | message = message.replace("{user.name}", member.name) 402 | message = message.replace("{user}", str(member)) 403 | message = message.replace("{server.members}", "{:,}".format(len(guild.members))) 404 | message = message.replace("{server.members.prefix}", self.prefixfy(guild)) 405 | message = message.replace("{user.created.length}", dateify.get((datetime.utcnow() - member.created_at).total_seconds())) 406 | return message 407 | 408 | async def image_welcomer(self, author, server): 409 | data = r.table("welcomer").get(str(server.id)).run(self.db, durability="soft") 410 | banner = "" if not data["banner"] else "&background={}".format(data["banner"]) 411 | async with aiohttp.ClientSession() as session: 412 | async with session.get("http://localhost:8443/api/welcomer?userAvatar={}&{}{}".format(author.avatar_url_as(format="png"), urllib.parse.urlencode({"userName": str(author)}), banner)) as f: 413 | return discord.File(await f.read(), "welcomer.{}".format(f.headers["Content-Type"].split("/")[1])) 414 | 415 | async def webhook_send(self, channel, content=None, file=None, embed=None): 416 | if self.avatar is None: 417 | try: 418 | with open("sx4-byellow.png", "rb") as f: 419 | self.avatar = f.read() 420 | except: 421 | pass 422 | webhook = discord.utils.get(await channel.guild.webhooks(), name="Sx4 - Welcomer") 423 | if not webhook: 424 | webhook = await channel.create_webhook(name="Sx4 - Welcomer", avatar=self.avatar) 425 | elif webhook and channel != webhook.channel: 426 | await webhook.delete() 427 | webhook = await channel.create_webhook(name="Sx4 - Welcomer", avatar=self.avatar) 428 | await webhook.send(content=content, file=file, embed=embed) 429 | 430 | def setup(bot, connection): 431 | bot.add_cog(welcomer(bot, connection)) 432 | -------------------------------------------------------------------------------- /Sx4/main.py: -------------------------------------------------------------------------------- 1 | import discord 2 | import asyncio 3 | from discord.ext import commands 4 | from random import choice as randchoice 5 | import time 6 | import datetime 7 | from utils import checks 8 | from urllib.parse import urlencode 9 | from urllib.request import Request, urlopen 10 | import requests 11 | from utils import Token 12 | import inspect 13 | import importlib 14 | import logging 15 | import aiohttp 16 | import json 17 | import rethinkdb as r 18 | from utils.database import Database 19 | import traceback 20 | import sys 21 | import os 22 | import subprocess 23 | 24 | async def prefix_function(bot, message): 25 | user = r.table("prefix").get(str(message.author.id)).run(connection) 26 | server = r.table("prefix").get(str(message.guild.id)).run(connection) 27 | if user and user["prefixes"] != []: 28 | return [x.encode().decode() for x in user["prefixes"]] + ['<@440996323156819968> ', '<@!440996323156819968> '] 29 | elif server and server["prefixes"] != []: 30 | return [x.encode().decode() for x in server["prefixes"]] + ['<@440996323156819968> ', '<@!440996323156819968> '] 31 | else: 32 | return ['s?', 'S?', 'sx4 ', '<@440996323156819968> ', '<@!440996323156819968> '] 33 | 34 | bot = commands.AutoShardedBot(command_prefix=prefix_function, case_insensitive=False) 35 | logging.basicConfig(level=logging.INFO) 36 | wrap = "```py\n{}\n```" 37 | modules = ["cogs." + x.replace(".py", "") for x in os.listdir("cogs") if ".py" in x] 38 | 39 | connection = Database.get_connection() 40 | 41 | def load_extension(self, name): 42 | if name in self.extensions: 43 | return 44 | 45 | lib = importlib.import_module(name) 46 | if not hasattr(lib, 'setup'): 47 | del lib 48 | del sys.modules[name] 49 | raise discord.ClientException('extension does not have a setup function') 50 | 51 | lib.setup(self, connection) 52 | self.extensions[name] = lib 53 | 54 | commands.AutoShardedBot.load_extension = load_extension 55 | 56 | @bot.event 57 | async def on_ready(): 58 | print('Logged in as') 59 | print(bot.user.name + '#' + str(bot.user.discriminator) + ' (' + str(bot.user.id) + ')') 60 | print('Connected to {} servers and {} users | {} shards'.format(len(bot.guilds), len(set(bot.get_all_members())), bot.shard_count)) 61 | print('------') 62 | for extension in modules: 63 | try: 64 | bot.load_extension(extension) 65 | except Exception as e: 66 | print(e) 67 | r.table("blacklist").insert({"id": "owner", "users": []}).run(connection) 68 | 69 | @bot.event 70 | async def on_shard_ready(shard_id): 71 | guild = bot.get_guild(330399610273136641) 72 | webhook = discord.utils.get(await guild.webhooks(), id=527878836055179275) 73 | s=discord.Embed(colour=0x5fe468, timestamp=datetime.datetime.utcnow()) 74 | s.set_author(name=str(bot.user), icon_url=bot.user.avatar_url) 75 | s.add_field(name="Shard", value=shard_id) 76 | s.set_footer(text="Connected") 77 | await webhook.send(embed=s) 78 | 79 | @bot.event 80 | async def on_message(message): 81 | ctx = await bot.get_context(message) 82 | serverdata = r.table("blacklist").get(str(message.guild.id)).run(connection) 83 | if not ctx.command: 84 | return 85 | elif checks.is_owner_check(ctx): 86 | return await bot.process_commands(message) 87 | elif isinstance(message.channel, discord.abc.PrivateChannel): 88 | return await message.channel.send("You can't use commands in private messages :no_entry:") 89 | elif message.author.bot: 90 | return 91 | elif str(message.author.id) in r.table("blacklist").get("owner")["users"].run(connection): 92 | return await ctx.send("You are blacklisted from using the bot, to appeal make sure to join the bots support server which can be found in `{}support`".format(ctx.prefix)) 93 | elif serverdata: 94 | if not checks.has_permissions("administrator").__closure__[0].cell_contents(ctx): 95 | commands = list(map(lambda x: x["id"], serverdata["commands"])) 96 | if ctx.command.module[5:] in commands: 97 | whitelisted = list(filter(lambda x: x["id"] == ctx.command.module[5:], serverdata["commands"]))[0]["whitelisted"] 98 | if whitelisted != []: 99 | if str(message.channel.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "channel", whitelisted)): 100 | return await bot.process_commands(message) 101 | if str(message.author.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "user", whitelisted)): 102 | return await bot.process_commands(message) 103 | for x in message.author.roles: 104 | if str(x.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "role", whitelisted)): 105 | return await bot.process_commands(message) 106 | if str(ctx.command) in commands: 107 | whitelisted = list(filter(lambda x: x["id"] == str(ctx.command), serverdata["commands"]))[0]["whitelisted"] 108 | if whitelisted != []: 109 | if str(message.channel.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "channel", whitelisted)): 110 | return await bot.process_commands(message) 111 | if str(message.author.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "user", whitelisted)): 112 | return await bot.process_commands(message) 113 | for x in message.author.roles: 114 | if str(x.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "role", whitelisted)): 115 | return await bot.process_commands(message) 116 | if ctx.command.module[5:] in commands: 117 | blacklisted = list(filter(lambda x: x["id"] == ctx.command.module[5:], serverdata["commands"]))[0]["blacklisted"] 118 | if blacklisted != []: 119 | if str(message.channel.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "channel", blacklisted)): 120 | return await ctx.send("You cannot use any commands in the module {} in this channel :no_entry:".format(ctx.command.module[5:])) 121 | if str(message.author.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "user", blacklisted)): 122 | return await ctx.send("You are blacklisted from using any commands in the module {} in this server :no_entry:".format(ctx.command.module[5:])) 123 | for x in message.author.roles: 124 | if str(x.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "role", blacklisted)): 125 | return await ctx.send("You are in the role `{}` which means you are blacklisted from using any commands in the module {} in this server :no_entry:".format(x.name, ctx.command.module[5:])) 126 | if str(ctx.command) in commands: 127 | blacklisted = list(filter(lambda x: x["id"] == str(ctx.command), serverdata["commands"]))[0]["blacklisted"] 128 | if blacklisted != []: 129 | if str(message.channel.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "channel", blacklisted)): 130 | return await ctx.send("You cannot use that command in this channel :no_entry:") 131 | if str(message.author.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "user", blacklisted)): 132 | return await ctx.send("You are blacklisted from using that command in this server :no_entry:") 133 | for x in message.author.roles: 134 | if str(x.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "role", blacklisted)): 135 | return await ctx.send("You are in the role `{}` which means you are blacklisted from using that command in this server :no_entry:".format(x.name)) 136 | if str(ctx.command) in serverdata["disabled"]: 137 | return await ctx.send("That command is disabled across the server :no_entry:") 138 | await bot.process_commands(message) 139 | 140 | @bot.event 141 | async def on_message_edit(before, after): 142 | if before.content == after.content: 143 | return 144 | ctx = await bot.get_context(after) 145 | serverdata = r.table("blacklist").get(str(after.guild.id)).run(connection) 146 | if not ctx.command: 147 | return 148 | elif checks.is_owner_check(ctx): 149 | return await bot.process_commands(after) 150 | elif isinstance(after.channel, discord.abc.PrivateChannel): 151 | return await after.channel.send("You can't use commands in private messages :no_entry:") 152 | elif after.author.bot: 153 | return 154 | elif str(after.author.id) in r.table("blacklist").get("owner")["users"].run(connection): 155 | return await ctx.send("You are blacklisted from using the bot, to appeal make sure to join the bots support server which can be found in `{}support`".format(ctx.prefix)) 156 | elif serverdata: 157 | if not checks.has_permissions("administrator").__closure__[0].cell_contents(ctx): 158 | commands = list(map(lambda x: x["id"], serverdata["commands"])) 159 | if ctx.command.module[5:] in commands: 160 | whitelisted = list(filter(lambda x: x["id"] == ctx.command.module[5:], serverdata["commands"]))[0]["whitelisted"] 161 | if whitelisted != []: 162 | if str(after.channel.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "channel", whitelisted)): 163 | return await bot.process_commands(after) 164 | if str(after.author.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "user", whitelisted)): 165 | return await bot.process_commands(after) 166 | for x in after.author.roles: 167 | if str(x.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "role", whitelisted)): 168 | return await bot.process_commands(after) 169 | if str(ctx.command) in commands: 170 | whitelisted = list(filter(lambda x: x["id"] == str(ctx.command), serverdata["commands"]))[0]["whitelisted"] 171 | if whitelisted != []: 172 | if str(after.channel.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "channel", whitelisted)): 173 | return await bot.process_commands(after) 174 | if str(after.author.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "user", whitelisted)): 175 | return await bot.process_commands(after) 176 | for x in after.author.roles: 177 | if str(x.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "role", whitelisted)): 178 | return await bot.process_commands(after) 179 | if ctx.command.module[5:] in commands: 180 | blacklisted = list(filter(lambda x: x["id"] == ctx.command.module[5:], serverdata["commands"]))[0]["blacklisted"] 181 | if blacklisted != []: 182 | if str(after.channel.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "channel", blacklisted)): 183 | return await ctx.send("You cannot use any commands in the module {} in this channel :no_entry:".format(ctx.command.module[5:])) 184 | if str(after.author.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "user", blacklisted)): 185 | return await ctx.send("You are blacklisted from using any commands in the module {} in this server :no_entry:".format(ctx.command.module[5:])) 186 | for x in after.author.roles: 187 | if str(x.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "role", blacklisted)): 188 | return await ctx.send("You are in the role `{}` which means you are blacklisted from using any commands in the module {} in this server :no_entry:".format(x.name, ctx.command.module[5:])) 189 | if str(ctx.command) in commands: 190 | blacklisted = list(filter(lambda x: x["id"] == str(ctx.command), serverdata["commands"]))[0]["blacklisted"] 191 | if blacklisted != []: 192 | if str(after.channel.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "channel", blacklisted)): 193 | return await ctx.send("You cannot use that command in this channel :no_entry:") 194 | if str(after.author.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "user", blacklisted)): 195 | return await ctx.send("You are blacklisted from using that command in this server :no_entry:") 196 | for x in after.author.roles: 197 | if str(x.id) in map(lambda x: x["id"], filter(lambda x: x["type"] == "role", blacklisted)): 198 | return await ctx.send("You are in the role `{}` which means you are blacklisted from using that command in this server :no_entry:".format(x.name)) 199 | if str(ctx.command) in serverdata["disabled"]: 200 | return await ctx.send("That command is disabled across the server :no_entry:") 201 | await bot.process_commands(after) 202 | 203 | @bot.event 204 | async def on_command_error(ctx, error, *args, **kwargs): 205 | channel = ctx.channel 206 | author = ctx.author 207 | if isinstance(error, commands.CheckFailure): 208 | perms = ctx.command.checks[0] 209 | if ctx.command.checks[0].__name__ == "is_owner_check": 210 | try: 211 | ctx.command.reset_cooldown(ctx) 212 | except: 213 | pass 214 | return await channel.send("You do not have permission to use this command, Required permissions: Bot Owner :no_entry:") 215 | elif str(perms).split(" ")[1].split(".")[0] == "is_main_owner": 216 | try: 217 | ctx.command.reset_cooldown(ctx) 218 | except: 219 | pass 220 | return await channel.send("You do not have permission to use this command, Required permissions: Bot Owner :no_entry:") 221 | else: 222 | try: 223 | ctx.command.reset_cooldown(ctx) 224 | except: 225 | pass 226 | return await channel.send("You do not have permission to use this command, Required permissions: {} :no_entry:".format(", ".join(inspect.getclosurevars(ctx.command.checks[0]).nonlocals["perms"]))) 227 | elif isinstance(error, commands.NoPrivateMessage): 228 | try: 229 | ctx.command.reset_cooldown(ctx) 230 | except: 231 | pass 232 | return await channel.send("This command cannot be used in DMs!") 233 | elif isinstance(error, commands.DisabledCommand): 234 | try: 235 | ctx.command.reset_cooldown(ctx) 236 | except: 237 | pass 238 | if not checks.is_owner_check(ctx): 239 | return await channel.send("The command `{}` has been disabled :no_entry:".format(ctx.command)) 240 | elif isinstance(error, commands.CommandOnCooldown): 241 | m, s = divmod(error.retry_after, 60) 242 | h, m = divmod(m, 60) 243 | if h == 0: 244 | time = "%d minutes %d seconds" % (m, s) 245 | elif h == 0 and m == 0: 246 | time = "%d seconds" % (s) 247 | else: 248 | time = "%d hours %d minutes %d seconds" % (h, m, s) 249 | return await channel.send("This command is on cooldown! Try again in {}".format(time)) 250 | elif isinstance(error, commands.MissingRequiredArgument): 251 | try: 252 | perms = ctx.command.checks[0] 253 | except: 254 | perms = None 255 | msg = "" 256 | if not ctx.command.usage: 257 | for x in ctx.command.params: 258 | if x != "ctx": 259 | if x != "self": 260 | if "=" in str(ctx.command.params[x]): 261 | msg += "[{}] ".format(x) 262 | else: 263 | msg += "<{}> ".format(x) 264 | else: 265 | msg += ctx.command.usage 266 | if not ctx.command.aliases: 267 | aliases = "None" 268 | else: 269 | aliases = ", ".join([x for x in ctx.command.aliases]) 270 | if not perms: 271 | msg = "Usage: {}{} {}\nCommand aliases: {}\nRequired permissions: None\nCommand description: {}".format(ctx.prefix, ctx.command, msg, aliases, ctx.command.help) 272 | else: 273 | msg = "Usage: {}{} {}\nCommand aliases: {}\nRequired permissions: {}\nCommand description: {}".format(ctx.prefix, ctx.command, msg, aliases, 274 | ", ".join(inspect.getclosurevars(perms).nonlocals["perms"]) if perms.__name__ != "is_owner_check" and str(perms).split(" ")[1].split(".")[0] != "is_main_owner" else "Bot Owner", ctx.command.help) 275 | try: 276 | msg += "\n\nSub commands: {}".format(", ".join([x for x in ctx.command.all_commands if x not in ctx.command.all_commands[x].aliases])) 277 | except: 278 | pass 279 | s=discord.Embed(description=msg) 280 | s.set_author(name=ctx.command, icon_url=bot.user.avatar_url) 281 | await channel.send(embed=s) 282 | try: 283 | ctx.command.reset_cooldown(ctx) 284 | except: 285 | pass 286 | return 287 | elif isinstance(error, commands.CommandNotFound): 288 | pass 289 | elif isinstance(error, commands.BadArgument): 290 | try: 291 | perms = ctx.command.checks[0] 292 | except: 293 | perms = None 294 | msg = "" 295 | for x in ctx.command.params: 296 | if x != "ctx": 297 | if x != "self": 298 | if "=" in str(ctx.command.params[x]): 299 | msg += "[{}] ".format(x) 300 | else: 301 | msg += "<{}> ".format(x) 302 | if not ctx.command.aliases: 303 | aliases = "None" 304 | else: 305 | aliases = ", ".join([x for x in ctx.command.aliases]) 306 | if not perms: 307 | msg = "Usage: {}{} {}\nCommand aliases: {}\nRequired permissions: None\nCommand description: {}".format(ctx.prefix, ctx.command, msg, aliases, ctx.command.help) 308 | else: 309 | msg = "Usage: {}{} {}\nCommand aliases: {}\nRequired permissions: {}\nCommand description: {}".format(ctx.prefix, ctx.command, msg, aliases, 310 | ", ".join(inspect.getclosurevars(perms).nonlocals["perms"]) if perms.__name__ != "is_owner_check" and str(perms).split(" ")[1].split(".")[0] != "is_main_owner" else "Bot Owner", ctx.command.help) 311 | try: 312 | msg += "\n\nSub commands: {}".format(", ".join([x for x in ctx.command.all_commands if x not in ctx.command.all_commands[x].aliases])) 313 | except: 314 | pass 315 | s=discord.Embed(description=msg) 316 | s.set_author(name=ctx.command, icon_url=bot.user.avatar_url) 317 | await channel.send(embed=s) 318 | try: 319 | ctx.command.reset_cooldown(ctx) 320 | except: 321 | pass 322 | return 323 | else: 324 | s=discord.Embed(title="Error", description="You have came across an error! [Support Server](https://discord.gg/PqJNcfB)\n{}".format(str(error)).replace("Command raised an exception: ", "")) 325 | await channel.send(embed=s) 326 | print("".join(traceback.format_exception(type(error), error, error.__traceback__))) 327 | await bot.get_channel(439745234285625355).send("```py\nServer: {}\nTime: {}\nCommand: {}\nAuthor: {}\n\n{}```".format(ctx.message.guild, datetime.datetime.utcnow().strftime("%d/%m/%Y %H:%M:%S"), ctx.command, ctx.message.author, "".join(traceback.format_exception(type(error), error, error.__traceback__, 1000)))) 328 | 329 | 330 | class Main: 331 | def __init__(self, bot): 332 | self.bot = bot 333 | 334 | @bot.command(hidden=True) 335 | @checks.is_owner() 336 | async def load(ctx, *, module: str): 337 | """loads a part of the bot.""" 338 | m = "cogs." + module 339 | try: 340 | if m in modules: 341 | bot.load_extension(m) 342 | await ctx.send("The module `{}` has been loaded <:done:403285928233402378>".format(module)) 343 | else: 344 | await ctx.send("I cannot find the module you want me to load <:crossmark:410105895528300554>") 345 | except Exception as e: 346 | e=discord.Embed(description="Error:" + wrap.format(type(e).name + ': ' + str(e)), colour=discord.Colour.red()) 347 | await ctx.send(embed=e) 348 | 349 | @bot.command(hidden=True) 350 | @checks.is_owner() 351 | async def unload(ctx, *, module: str): 352 | """unloads a part of the bot.""" 353 | m = "cogs." + module 354 | try: 355 | if m in modules: 356 | bot.unload_extension(m) 357 | await ctx.send("The module `{}` has been unloaded <:done:403285928233402378>".format(module)) 358 | else: 359 | await ctx.send("I cannot find the module you want me to unload <:crossmark:410105895528300554>") 360 | except Exception as e: 361 | e=discord.Embed(description="Error:" + wrap.format(type(e).name + ': ' + str(e)), colour=discord.Colour.red()) 362 | await ctx.send(embed=e) 363 | 364 | @bot.command(hidden=True) 365 | @checks.is_owner() 366 | async def reload(ctx, *, module: str): 367 | """Reloads a part of the bot.""" 368 | if module.lower() == "all": 369 | i = 0 370 | for m in modules: 371 | try: 372 | bot.unload_extension(m) 373 | bot.load_extension(m) 374 | except: 375 | i += 1 376 | await ctx.send("I was not able to load the module `{}` <:crossmark:410105895528300554>".format(str(m)[4:])) 377 | if i == 0: 378 | await ctx.send("All modules have been reloaded <:done:403285928233402378>") 379 | else: 380 | await ctx.send("{} modules have been reloaded <:done:403285928233402378>".format(len(modules)-i)) 381 | return 382 | m = "cogs." + module 383 | try: 384 | if m in modules: 385 | bot.unload_extension(m) 386 | bot.load_extension(m) 387 | await ctx.send("The module `{}` has been reloaded <:done:403285928233402378>".format(module)) 388 | else: 389 | await ctx.send("I cannot find the module you want me to reload <:crossmark:410105895528300554>") 390 | except Exception as e: 391 | e=discord.Embed(description="Error:" + wrap.format(type(e).name + ': ' + str(e)), colour=discord.Colour.red()) 392 | await ctx.send(embed=e) 393 | 394 | async def on_error(self, event_method, *args, **kwargs): 395 | pass 396 | 397 | bot.on_error = on_error 398 | 399 | setattr(bot, "uptime", datetime.datetime.utcnow().timestamp()) 400 | 401 | bot.add_cog(Main(bot)) 402 | 403 | bot.run(Token.bot(), reconnect=True) 404 | 405 | -------------------------------------------------------------------------------- /Sx4/utils/PagedResult.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import discord 3 | import math 4 | from discord.ext import commands 5 | import discord.utils 6 | 7 | class PagedResultData: 8 | paged_results = dict() 9 | 10 | class SelectedEvent: 11 | pass 12 | 13 | class PagedResult: 14 | __page = 1 15 | entries_per_page = 10 16 | 17 | list_indexes = True 18 | selectable = True 19 | cancelable = True 20 | 21 | on_select = lambda s: s 22 | 23 | message_id = None 24 | 25 | def __init__(self, entries, display_function): 26 | if not isinstance(entries, collections.Iterable): 27 | raise ValueError("Incorrect type, entries is not an instance of list") 28 | 29 | if len(entries) <= 0: 30 | raise ValueError("List has no entries") 31 | 32 | self.entries = entries 33 | 34 | self.display_function = display_function 35 | 36 | self.__max_pages = self.determine_max_pages() 37 | 38 | self.embed = discord.Embed(colour=0xfff90d) 39 | 40 | def get_current_page(self): 41 | return self.__page 42 | 43 | def get_max_pages(self): 44 | return self.__max_pages 45 | 46 | def get_current_page_entries(self): 47 | start = (self.__page - 1) * self.entries_per_page 48 | 49 | if self.__page == self.__max_pages: 50 | end = len(self.entries) - start 51 | else: 52 | end = self.entries_per_page 53 | 54 | return self.entries[start:(start + end)] 55 | 56 | def get_current_page_embed(self): 57 | entries = self.get_current_page_entries() 58 | description = "Page **" + str(self.__page) + "**/**" + str(self.__max_pages) + "**\n" 59 | 60 | i = 1 61 | for e in entries: 62 | description = description + "\n" + (str(i) + " - " if self.list_indexes else "") + str(self.display_function(e)) 63 | 64 | i = i + 1 65 | 66 | footer = "" 67 | if self.__page + 1 <= self.__max_pages: 68 | footer = footer + "next page | " 69 | 70 | if self.__page - 1 > 0: 71 | footer = footer + "previous page | " 72 | 73 | if self.__max_pages > 2: 74 | footer = footer + "go to page | " 75 | 76 | if self.cancelable: 77 | footer = footer + "cancel" 78 | else: 79 | footer = footer[:-3] 80 | 81 | self.embed.description = description 82 | self.embed.set_footer(text=footer) 83 | 84 | return self.embed 85 | 86 | def determine_max_pages(self): 87 | return math.ceil(len(self.entries)/self.entries_per_page) 88 | 89 | async def select(self, index): 90 | event = SelectedEvent() 91 | event.page = self.__page 92 | event.index = index 93 | event.actual_index = (self.__page - 1) * self.entries_per_page + (index - 1) 94 | event.entry = self.entries[event.actual_index] 95 | 96 | await self.on_select(event) 97 | 98 | 99 | def set_page(self, page): 100 | if page > self.__max_pages: 101 | return False 102 | 103 | if page < 1: 104 | return False 105 | 106 | self.__page = page 107 | 108 | return True 109 | 110 | def next_page(self): 111 | if self.__page + 1 > self.__max_pages: 112 | return False 113 | 114 | self.__page = self.__page + 1 115 | 116 | return True 117 | 118 | def previous_page(self): 119 | if self.__page - 1 < 1: 120 | return False 121 | 122 | self.__page = self.__page - 1 123 | 124 | return True -------------------------------------------------------------------------------- /Sx4/utils/arg.py: -------------------------------------------------------------------------------- 1 | import discord 2 | import re 3 | 4 | regex_mention = re.compile("<@(?:!|)(\d+)>") 5 | regex_namediscrim = re.compile("(.{2,32})#(\d{4})") 6 | regex_id = re.compile("(^\d+$)") 7 | regex_name = re.compile("(.{2,32})") 8 | role_mention = re.compile("<@&(\d+)>") 9 | channel_mention = re.compile("<#(\d+)>") 10 | 11 | async def get_member_info(ctx, user_arg): 12 | bot = ctx.bot 13 | match_mention = regex_mention.match(user_arg) 14 | match_namediscrim = regex_namediscrim.match(user_arg) 15 | match_id = regex_id.match(user_arg) 16 | match_name = regex_name.match(user_arg) 17 | if match_mention: 18 | id = int(match_mention.group(1)) 19 | user = ctx.guild.get_member(id) 20 | if not user: 21 | try: 22 | user = {x.id: x for x in bot.get_all_members()}[id] 23 | except KeyError: 24 | try: 25 | user = await bot.get_user_info(id) 26 | except: 27 | return None 28 | elif match_namediscrim: 29 | name = match_namediscrim.group(1) 30 | discrim = match_namediscrim.group(2) 31 | try: 32 | user = [x for x in ctx.guild.members if x.name.lower() == name.lower() and x.discriminator == discrim][0] 33 | except IndexError: 34 | try: 35 | user = [x for x in bot.get_all_members() if x.name.lower() == name.lower() and x.discriminator == discrim][0] 36 | except IndexError: 37 | return None 38 | elif match_id: 39 | id = int(match_id.group(1)) 40 | user = ctx.guild.get_member(id) 41 | if not user: 42 | try: 43 | user = {x.id: x for x in bot.get_all_members()}[id] 44 | except KeyError: 45 | try: 46 | user = await bot.get_user_info(id) 47 | except: 48 | return None 49 | elif match_name: 50 | name2 = match_name.group(1) 51 | try: 52 | user = [x for x in ctx.guild.members if x.display_name.lower() == name2.lower()][0] 53 | except IndexError: 54 | try: 55 | user = [x for x in ctx.guild.members if x.name.lower() == name2.lower()][0] 56 | except IndexError: 57 | try: 58 | user = [x for x in bot.get_all_members() if x.name.lower() == name2.lower()][0] 59 | except IndexError: 60 | return None 61 | else: 62 | return None 63 | return user 64 | 65 | async def get_member(ctx, user_arg): 66 | bot = ctx.bot 67 | match_mention = regex_mention.match(user_arg) 68 | match_namediscrim = regex_namediscrim.match(user_arg) 69 | match_id = regex_id.match(user_arg) 70 | match_name = regex_name.match(user_arg) 71 | if match_mention: 72 | id = int(match_mention.group(1)) 73 | user = ctx.guild.get_member(id) 74 | if not user: 75 | user = bot.get_user(id) 76 | if not user: 77 | try: 78 | user = await bot.get_user_info(id) 79 | except: 80 | return None 81 | elif match_namediscrim: 82 | name = match_namediscrim.group(1) 83 | discrim = match_namediscrim.group(2) 84 | try: 85 | user = [x for x in ctx.guild.members if x.name.lower() == name.lower() and x.discriminator == discrim][0] 86 | except IndexError: 87 | try: 88 | user = [x for x in bot.users if x.name.lower() == name.lower() and x.discriminator == discrim][0] 89 | except IndexError: 90 | return None 91 | elif match_id: 92 | id = int(match_id.group(1)) 93 | user = ctx.guild.get_member(id) 94 | if not user: 95 | user = bot.get_user(id) 96 | if not user: 97 | try: 98 | user = await bot.get_user_info(id) 99 | except: 100 | return None 101 | elif match_name: 102 | name2 = match_name.group(1) 103 | try: 104 | user = [x for x in ctx.guild.members if x.display_name.lower() == name2.lower()][0] 105 | except IndexError: 106 | try: 107 | user = [x for x in ctx.guild.members if x.name.lower() == name2.lower()][0] 108 | except IndexError: 109 | try: 110 | user = [x for x in bot.users if x.name.lower() == name2.lower()][0] 111 | except IndexError: 112 | return None 113 | else: 114 | return None 115 | return user 116 | 117 | def get_role(ctx, role): 118 | if role_mention.match(role): 119 | role = ctx.guild.get_role(int(role_mention.match(role).group(1))) 120 | elif regex_id.match(role): 121 | role = ctx.guild.get_role(int(regex_id.match(role).group(1))) 122 | else: 123 | try: 124 | role = list(filter(lambda x: x.name.lower() == role.lower(), ctx.guild.roles))[0] 125 | except IndexError: 126 | try: 127 | role = list(filter(lambda x: x.name.lower().startswith(role.lower()), ctx.guild.roles))[0] 128 | except IndexError: 129 | try: 130 | role = list(filter(lambda x: role.lower() in x.name.lower(), ctx.guild.roles))[0] 131 | except IndexError: 132 | return None 133 | return role 134 | 135 | def get_server_member(ctx, user): 136 | match_mention = regex_mention.match(user) 137 | match_namediscrim = regex_namediscrim.match(user) 138 | match_id = regex_id.match(user) 139 | match_name = regex_name.match(user) 140 | if match_mention: 141 | id = int(match_mention.group(1)) 142 | user = ctx.guild.get_member(id) 143 | if not user: 144 | return None 145 | elif match_namediscrim: 146 | name = match_namediscrim.group(1) 147 | discrim = match_namediscrim.group(2) 148 | try: 149 | user = [x for x in ctx.guild.members if x.name.lower() == name.lower() and x.discriminator == discrim][0] 150 | except IndexError: 151 | return None 152 | elif match_id: 153 | id = int(match_id.group(1)) 154 | user = ctx.guild.get_member(id) 155 | if not user: 156 | return None 157 | elif match_name: 158 | name2 = match_name.group(1) 159 | try: 160 | user = [x for x in ctx.guild.members if x.display_name.lower() == name2.lower()][0] 161 | except IndexError: 162 | try: 163 | user = [x for x in ctx.guild.members if x.name.lower() == name2.lower()][0] 164 | except IndexError: 165 | try: 166 | user = [x for x in ctx.guild.members if name2.lower() in x.display_name.lower()][0] 167 | except IndexError: 168 | try: 169 | user = [x for x in ctx.guild.members if name2.lower() in x.name.lower()][0] 170 | except IndexError: 171 | return None 172 | else: 173 | return None 174 | return user 175 | 176 | def get_text_channel(ctx, channel): 177 | if channel_mention.match(channel): 178 | channel = discord.utils.get(ctx.guild.text_channels, id=int(channel_mention.match(channel).group(1))) 179 | elif regex_id.match(channel): 180 | channel = discord.utils.get(ctx.guild.text_channels, id=int(regex_id.match(channel).group(1))) 181 | else: 182 | try: 183 | channel = list(filter(lambda x: x.name.lower() == channel.lower(), ctx.guild.text_channels))[0] 184 | except IndexError: 185 | try: 186 | channel = list(filter(lambda x: x.name.lower().startswith(channel.lower()), ctx.guild.text_channels))[0] 187 | except IndexError: 188 | try: 189 | channel = list(filter(lambda x: channel.lower() in x.name.lower(), ctx.guild.text_channels))[0] 190 | except IndexError: 191 | return None 192 | return channel 193 | 194 | def get_voice_channel(ctx, channel): 195 | if regex_id.match(channel): 196 | channel = discord.utils.get(ctx.guild.voice_channels, id=int(regex_id.match(channel).group(1))) 197 | else: 198 | try: 199 | channel = list(filter(lambda x: x.name.lower() == channel.lower(), ctx.guild.voice_channels))[0] 200 | except IndexError: 201 | try: 202 | channel = list(filter(lambda x: x.name.lower().startswith(channel.lower()), ctx.guild.voice_channels))[0] 203 | except IndexError: 204 | try: 205 | channel = list(filter(lambda x: channel.lower() in x.name.lower(), ctx.guild.voice_channels))[0] 206 | except IndexError: 207 | return None 208 | return channel 209 | 210 | def get_category(ctx, category): 211 | if regex_id.match(category): 212 | channel = discord.utils.get(ctx.guild.categories, id=int(regex_id.match(category).group(1))) 213 | else: 214 | try: 215 | channel = list(filter(lambda x: x.name.lower() == category.lower(), ctx.guild.categories))[0] 216 | except IndexError: 217 | try: 218 | channel = list(filter(lambda x: x.name.lower().startswith(category.lower()), ctx.guild.categories))[0] 219 | except IndexError: 220 | try: 221 | channel = list(filter(lambda x: category.lower() in x.name.lower(), ctx.guild.categories))[0] 222 | except IndexError: 223 | return None 224 | return channel -------------------------------------------------------------------------------- /Sx4/utils/arghelp.py: -------------------------------------------------------------------------------- 1 | from discord.ext import commands 2 | import discord 3 | import discord.utils 4 | import json 5 | import inspect 6 | 7 | async def send(bot, ctx): 8 | msg = "" 9 | try: 10 | perms = ctx.command.checks[0] 11 | except: 12 | perms = None 13 | if not ctx.command.usage: 14 | for x in ctx.command.params: 15 | if x != "ctx": 16 | if x != "self": 17 | if "=" in str(ctx.command.params[x]): 18 | msg += "[{}] ".format(x) 19 | else: 20 | msg += "<{}> ".format(x) 21 | else: 22 | msg += ctx.command.usage 23 | if not ctx.command.aliases: 24 | aliases = "None" 25 | else: 26 | aliases = ", ".join([x for x in ctx.command.aliases]) 27 | if not perms: 28 | msg = "Usage: {}{} {}\nCommand aliases: {}\nRequired permissions: None\nCommand description: {}".format(ctx.prefix, ctx.command, msg, aliases, ctx.command.help) 29 | else: 30 | msg = "Usage: {}{} {}\nCommand aliases: {}\nRequired permissions: {}\nCommand description: {}".format(ctx.prefix, ctx.command, msg, aliases, 31 | ", ".join(inspect.getclosurevars(perms).nonlocals["perms"]) if perms.__name__ != "is_owner_check" and str(perms).split(" ")[1].split(".")[0] != "is_main_owner" else "Bot Owner", ctx.command.help) 32 | try: 33 | msg += "\n\nSub commands: {}".format(", ".join([x for x in ctx.command.all_commands if x not in ctx.command.all_commands[x].aliases])) 34 | except: 35 | pass 36 | s=discord.Embed(description=msg) 37 | s.set_author(name=ctx.command, icon_url=bot.user.avatar_url) 38 | return await ctx.channel.send(embed=s) 39 | -------------------------------------------------------------------------------- /Sx4/utils/checks.py: -------------------------------------------------------------------------------- 1 | from discord.ext import commands 2 | import discord 3 | import discord.utils 4 | import json 5 | import rethinkdb as r 6 | from utils.database import Database 7 | 8 | connection = Database.get_connection() 9 | 10 | def is_owner_check(ctx): 11 | if ctx.author.id in [153286414212005888, 51766611097944064, 402557516728369153, 190551803669118976, 388424304678666240]: 12 | return True 13 | else: 14 | return False 15 | 16 | def is_main_owner(): 17 | def predicate(ctx): 18 | if ctx.author.id in [402557516728369153, 190551803669118976]: 19 | return True 20 | return commands.check(predicate) 21 | 22 | def is_owner(): 23 | return commands.check(is_owner_check) 24 | 25 | def is_owner_c(author): 26 | if author.id in [153286414212005888, 51766611097944064, 402557516728369153, 190551803669118976, 388424304678666240]: 27 | return True 28 | 29 | def has_permissions(*perms): 30 | def predicate(ctx): 31 | serverdata = r.table("fakeperms").get(str(ctx.guild.id)) 32 | role_perms = 0 33 | user_perms = 0 34 | if is_owner_check(ctx): 35 | return True 36 | elif ctx.author == ctx.guild.owner: 37 | return True 38 | elif serverdata.run(connection): 39 | user = serverdata["users"].filter(lambda x: x["id"] == str(ctx.author.id)) 40 | roles = serverdata["roles"] 41 | if user.run(connection): 42 | user_perms = user[0]["perms"].run(connection) 43 | for x in ctx.author.roles: 44 | if str(x.id) in roles.map(lambda x: x["id"]).run(connection): 45 | role_perms |= roles.filter(lambda y: y["id"] == str(x.id))[0]["perms"].run(connection) 46 | perm_total = ctx.author.guild_permissions.value | user_perms | role_perms 47 | if discord.Permissions(perm_total).administrator: 48 | return True 49 | else: 50 | return all(getattr(discord.Permissions(perm_total), perm, None) for perm in perms) 51 | else: 52 | if ctx.author.guild_permissions.administrator: 53 | return True 54 | else: 55 | return all(getattr(ctx.author.guild_permissions, perm, None) for perm in perms) 56 | return commands.check(predicate) 57 | -------------------------------------------------------------------------------- /Sx4/utils/ctime.py: -------------------------------------------------------------------------------- 1 | import discord 2 | 3 | def convert(time: str): 4 | times = time.split(" ") 5 | seconds = 0 6 | for x in times: 7 | if x.lower().endswith("s"): 8 | seconds += int(x[:-1]) 9 | elif x.lower().endswith("m"): 10 | seconds += int(x[:-1]) * 60 11 | elif x.lower().endswith("h"): 12 | seconds += int(x[:-1]) * 3600 13 | elif x.lower().endswith("d"): 14 | seconds += int(x[:-1]) * 86400 15 | elif x.isdigit(): 16 | seconds += int(x) 17 | else: 18 | pass 19 | return seconds 20 | -------------------------------------------------------------------------------- /Sx4/utils/data.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | class FileAlreadyExists(Exception): 5 | pass 6 | 7 | def read_json(file): 8 | with open(file, "r") as f: 9 | return json.loads(f.read()) 10 | 11 | def write_json(file, data: dict): 12 | with open(file, "w") as f: 13 | f.write(json.dumps(data)) 14 | 15 | def file_exists(file): 16 | return os.path.isfile(file) 17 | 18 | def create_file(file, data: dict={}): 19 | if file_exists(file): 20 | raise FileAlreadyExists("That file already exists, use write_json to update the file") 21 | else: 22 | with open(file, "w") as f: 23 | f.write(json.dumps(data)) 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Sx4/utils/database.py: -------------------------------------------------------------------------------- 1 | import rethinkdb as r 2 | 3 | connection = r.connect(db="sx4") 4 | 5 | class Database: 6 | def get_connection(): 7 | return connection -------------------------------------------------------------------------------- /Sx4/utils/dateify.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from datetime import datetime, timedelta 3 | 4 | def get(timestamp): 5 | m, s = divmod(timestamp, 60) 6 | h, m = divmod(m, 60) 7 | d, h = divmod(h, 24) 8 | w, d = divmod(d, 7) 9 | M, w = divmod(w, 4.345238095238096) 10 | y, M = divmod(M, 12) 11 | time_str = "" 12 | if y: 13 | time_str += "%d year%s " % (y, "" if y == 1 else "s") 14 | if M: 15 | time_str += "%d month%s " % (M, "" if M == 1 else "s") 16 | if w >= 1: 17 | time_str += "%d week%s " % (w, "" if w == 1 else "s") 18 | if d: 19 | time_str += "%d day%s " % (d, "" if d == 1 else "s") 20 | if h: 21 | time_str += "%d hour%s " % (h, "" if h == 1 else "s") 22 | if m: 23 | time_str += "%d minute%s " % (m, "" if m == 1 else "s") 24 | if s: 25 | time_str += "%d second%s " % (s, "" if s >= 1 and s < 2 else "s") 26 | return time_str[:-1] 27 | -------------------------------------------------------------------------------- /Sx4/utils/paged.py: -------------------------------------------------------------------------------- 1 | import re 2 | import asyncio 3 | import math 4 | import discord 5 | 6 | previous_aliases = ["previous", "p", "previous page"] 7 | next_aliases = ["next", "n", "next page"] 8 | cancel_aliases = ["stop", "cancel", "c"] 9 | page_locations = ["title", "footer"] 10 | all_aliases = previous_aliases + next_aliases + cancel_aliases 11 | confirmed = ["y", "yes", "accept"] 12 | 13 | async def page(ctx, array: list, selectable: bool=False, per_page: int=10, function: callable=None, timeout: int=60, auto_select: bool=False, indexed: bool=True, page_location: str="title", title: str="", colour: int=None, author: dict={"name": "", "icon_url": discord.Embed.Empty, "url": ""}): 14 | bot = ctx.bot 15 | page_location = page_location.lower() 16 | current_page = 1 17 | max_page = math.ceil(len(array)/per_page) 18 | last_page_entries = len(array) % per_page if len(array) % per_page != 0 else per_page 19 | if selectable and len(array) == 1 and auto_select: 20 | page = current_page 21 | index = 0 22 | index_on_page = 1 23 | object = array[index] 24 | return {"object": object, "user_index": index_on_page, "index": index, "page": page} 25 | re_page = re.compile("go to ([0-9]+)") 26 | s=discord.Embed(title="Page {}/{}".format(current_page, max_page) + (" | " + title if title else "") if page_location == "title" else title, 27 | description="\n".join([("{}. ".format(i) if indexed else "") + "{}".format(function(x) if function else x) for i, x in enumerate(array[per_page*current_page-per_page:current_page*per_page], start=1)]), 28 | colour=discord.Colour(colour) if colour else discord.Embed.Empty) 29 | s.set_author(name=author["name"] if "name" in author else "", icon_url=author["icon_url"] if "icon_url" in author else discord.Embed.Empty, url=author["url"] if "url" in author else "") 30 | s.set_footer(text="next | previous | go to | cancel{}".format(" | Page {}/{}".format(current_page, max_page) if page_location == "footer" else "")) 31 | message = await ctx.send(embed=s) 32 | def check(m): 33 | regex = re_page.match(m.content.lower()) 34 | if ctx.channel == m.channel and ctx.author == m.author: 35 | if regex: 36 | return int(regex.group(1)) <= max_page and int(regex.group(1)) > 0 37 | if not selectable: 38 | return m.content.lower() in all_aliases 39 | else: 40 | if m.content.lower() in all_aliases: 41 | return True 42 | elif m.content.isdigit(): 43 | return int(m.content) > 0 and int(m.content) <= (per_page if current_page != max_page else last_page_entries) 44 | else: 45 | return False 46 | def update_page(current_page: int): 47 | embed = message.embeds[0] 48 | embed.description = "\n".join([("{}. ".format(i) if indexed else "") + "{}".format(function(x) if function else x) for i, x in enumerate(array[per_page*current_page-per_page:current_page*per_page], start=1)]) 49 | embed.title = "Page {}/{}".format(current_page, max_page) + (" | " + title if title else "") if page_location == "title" else title 50 | if page_location == "footer": 51 | embed.set_footer(text="next | previous | go to | cancel | Page {}/{}".format(current_page, max_page)) 52 | return embed 53 | while True: 54 | try: 55 | response = await bot.wait_for("message", check=check, timeout=timeout) 56 | regex_page = re_page.match(response.content.lower()) 57 | if response.content.lower() in cancel_aliases: 58 | try: 59 | await message.delete() 60 | except: 61 | pass 62 | try: 63 | await response.delete() 64 | except: 65 | pass 66 | return None 67 | elif response.content.lower() in next_aliases: 68 | if current_page == max_page: 69 | current_page = 1 70 | else: 71 | current_page += 1 72 | try: 73 | await response.delete() 74 | except: 75 | pass 76 | await message.edit(embed=update_page(current_page)) 77 | elif response.content.lower() in previous_aliases: 78 | if current_page == 1: 79 | current_page = max_page 80 | else: 81 | current_page -= 1 82 | try: 83 | await response.delete() 84 | except: 85 | pass 86 | await message.edit(embed=update_page(current_page)) 87 | elif regex_page: 88 | current_page = int(regex_page.group(1)) 89 | try: 90 | await response.delete() 91 | except: 92 | pass 93 | await message.edit(embed=update_page(current_page)) 94 | elif response.content.isdigit(): 95 | try: 96 | await message.delete() 97 | except: 98 | pass 99 | try: 100 | await response.delete() 101 | except: 102 | pass 103 | page = current_page 104 | index = ((current_page * per_page) - per_page) + (int(response.content) - 1) 105 | index_on_page = int(response.content) 106 | object = array[index] 107 | return {"object": object, "user_index": index_on_page, "index": index, "page": page} 108 | except asyncio.TimeoutError: 109 | try: 110 | await message.delete() 111 | except: 112 | pass 113 | try: 114 | await response.delete() 115 | except: 116 | pass 117 | return None 118 | 119 | async def confirm(ctx, timeout: int=60, message: discord.Message=None): 120 | bot = ctx.bot 121 | try: 122 | response = await bot.wait_for("message", check=lambda m: ctx.author == m.author and ctx.channel == m.channel, timeout=timeout) 123 | if response.content.lower() in confirmed: 124 | return True 125 | else: 126 | try: 127 | if message: 128 | await message.delete() 129 | except: 130 | pass 131 | try: 132 | await response.delete() 133 | except: 134 | pass 135 | return False 136 | except asyncio.TimeoutError: 137 | try: 138 | if message: 139 | await message.delete() 140 | except: 141 | pass 142 | try: 143 | await response.delete() 144 | except: 145 | pass 146 | --------------------------------------------------------------------------------