├── LICENSE ├── Procfile ├── README.md ├── Tabitha.ttf ├── arial.ttf ├── cogs ├── anim.py ├── misc.py ├── mod.py ├── noble.py ├── skid.py ├── source.py ├── textemotes.py └── utils.py ├── data ├── config.json └── langs.json ├── ext ├── colours.py ├── context.py ├── embedtobox.py ├── formatter.py ├── helpformatter.py ├── stringview.py └── utility.py ├── requirements.txt ├── runtime.txt ├── selfbot.py └── start_bot.bat /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2017 kwugfighter 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the 8 | Software is furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 12 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 16 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 17 | DEALINGS IN THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: python selfbot.py 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Selfbot for Discord written in python 2 | 3 | ### this selfbot was made for educational purposes, a selfbot may get you banned from discord, use at your own risk 4 | -------------------------------------------------------------------------------- /Tabitha.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EC-discord/self-bot/c2ff8813afe819184776da68d4fa00ba16d38c21/Tabitha.ttf -------------------------------------------------------------------------------- /arial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EC-discord/self-bot/c2ff8813afe819184776da68d4fa00ba16d38c21/arial.ttf -------------------------------------------------------------------------------- /cogs/anim.py: -------------------------------------------------------------------------------- 1 | import discord 2 | import asyncio 3 | from discord.ext import commands 4 | 5 | 6 | class anim(commands.Cog): 7 | """animated messages""" 8 | 9 | def __init__(self, bot): 10 | self.bot = bot 11 | 12 | @commands.command() 13 | async def cathi(self, ctx, *, text: str = "Hi..."): 14 | lst = ("""ຸ    _____ 15 |   / /  /|" 16 |   | ̄ ̄ ̄ ̄| | 17 |   |    |/ 18 |    ̄ ̄ ̄ ̄""", f"""ຸ    {text} 19 |     ∧_∧__ 20 |   /(´・ω・`) /\ 21 |  /| ̄ ̄ ̄ ̄|\/ 22 |   |    |/ 23 |    ̄ ̄ ̄ ̄""") 24 | for i in range(3): 25 | for cat in lst: 26 | await ctx.message.edit(content=cat) 27 | await asyncio.sleep(1) 28 | 29 | @commands.command() 30 | async def flop(self, ctx): 31 | lst = ("( ° - °) (' - ' )", 32 | "(\\\° - °)\ (' - ' )", 33 | "(—°□°)— (' - ' )", 34 | "(╯°□°)╯(' - ' )", 35 | "(╯°□°)╯︵(\\\ .o.)\\") 36 | for i in lst: 37 | await ctx.message.edit(content=i) 38 | await asyncio.sleep(1) 39 | 40 | @commands.command() 41 | async def poof(self, ctx): 42 | """poofness""" 43 | lst = ("( ' - ')", 44 | "' - ')", 45 | "- ')", 46 | "')", 47 | ")", 48 | "*poofness*") 49 | for i in lst: 50 | await ctx.message.edit(content=i) 51 | await asyncio.sleep(1) 52 | 53 | @commands.command() 54 | async def virus(self, ctx, user: discord.Member = None, *, virus: str = "trojan"): 55 | user = user or ctx.author 56 | lst = (f"``[▓▓▓ ] / {virus}-virus.exe Packing files.``", 57 | f"``[▓▓▓▓▓▓▓ ] - {virus}-virus.exe Packing files..``", 58 | f"``[▓▓▓▓▓▓▓▓▓▓▓▓ ] \ {virus}-virus.exe Packing files..``", 59 | f"``[▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ] | {virus}-virus.exe Packing files..``", 60 | f"``[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ] / {virus}-virus.exe Packing files..``", 61 | f"``[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ] - {virus}-virus.exe Packing files..``", 62 | f"``[▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ] \ {virus}-virus.exe Packing files..``", 63 | f"``Successfully downloaded {virus}-virus.exe``", 64 | "``Injecting virus. |``", 65 | "``Injecting virus.. /``", 66 | "``Injecting virus... -``", 67 | f"``Successfully Injected {virus}-virus.exe into {user.name}``") 68 | for i in lst: 69 | await ctx.message.edit(content=i) 70 | await asyncio.sleep(1) 71 | 72 | @commands.command() 73 | async def boom(self, ctx): 74 | lst = ("```THIS MESSAGE WILL SELFDESTRUCT IN 5```", 75 | "```THIS MESSAGE WILL SELFDESTRUCT IN 4```", 76 | "```THIS MESSAGE WILL SELFDESTRUCT IN 3```", 77 | "```THIS MESSAGE WILL SELFDESTRUCT IN 2```", 78 | "```THIS MESSAGE WILL SELFDESTRUCT IN 1```", 79 | "```THIS MESSAGE WILL SELFDESTRUCT IN 0```", 80 | "💣", 81 | "💥") 82 | for i in lst: 83 | await ctx.message.edit(content=i) 84 | await asyncio.sleep(1) 85 | 86 | @commands.command() 87 | async def table(self, ctx): 88 | lst = ("`(\°-°)\ ┬─┬`", 89 | "`(\°□°)\ ┬─┬`", 90 | "`(-°□°)- ┬─┬`", 91 | "`(╯°□°)╯ ]`", 92 | "`(╯°□°)╯ ┻━┻`", 93 | "`(╯°□°)╯ [`", 94 | "`(╯°□°)╯ ┬─┬`", 95 | "`(╯°□°)╯ ]`", 96 | "`(╯°□°)╯ ┻━┻`", 97 | "`(╯°□°)╯ [`", 98 | "`(\°-°)\ ┬─┬`") 99 | for i in lst: 100 | await ctx.message.edit(content=i) 101 | await asyncio.sleep(1) 102 | 103 | @commands.command() 104 | async def warning(self, ctx): 105 | lst = ("`LOAD !! WARNING !! SYSTEM OVER`", 106 | "`OAD !! WARNING !! SYSTEM OVERL`", 107 | "`AD !! WARNING !! SYSTEM OVERLO`", 108 | "`D !! WARNING !! SYSTEM OVERLOA`", 109 | "`! WARNING !! SYSTEM OVERLOAD !`", 110 | "`WARNING !! SYSTEM OVERLOAD !!`", 111 | "`ARNING !! SYSTEM OVERLOAD !! W`", 112 | "`RNING !! SYSTEM OVERLOAD !! WA`", 113 | "`NING !! SYSTEM OVERLOAD !! WAR`", 114 | "`ING !! SYSTEM OVERLOAD !! WARN`", 115 | "`NG !! SYSTEM OVERLOAD !! WARNI`", 116 | "`G !! SYSTEM OVERLOAD !! WARNIN`", 117 | "`!! SYSTEM OVERLOAD !! WARNING`", 118 | "`! SYSTEM OVERLOAD !! WARNING !`", 119 | "`SYSTEM OVERLOAD !! WARNING !!`", 120 | "`IMMINENT SHUT-DOWN IN 0.5 SEC!`", 121 | "`WARNING !! SYSTEM OVERLOAD !!`", 122 | "`IMMINENT SHUT-DOWN IN 0.2 SEC!`", 123 | "`SYSTEM OVERLOAD !! WARNING !!`", 124 | "`IMMINENT SHUT-DOWN IN 0.01 SEC!`", 125 | "`SHUT-DOWN EXIT ERROR ¯\\(。・益・)/¯", 126 | "`CTRL + R FOR MANUAL OVERRIDE..`") 127 | for i in lst: 128 | await ctx.message.edit(content=i) 129 | await asyncio.sleep(1) 130 | 131 | 132 | def setup(bot): 133 | bot.add_cog(anim(bot)) 134 | -------------------------------------------------------------------------------- /cogs/misc.py: -------------------------------------------------------------------------------- 1 | import discord 2 | import asyncio 3 | import random 4 | import emoji 5 | from discord.ext import commands 6 | from PIL import Image 7 | import io 8 | import typing 9 | import aiohttp 10 | 11 | 12 | class misc(commands.Cog): 13 | def __init__(self, bot): 14 | self.bot = bot 15 | self.emoji_converter = commands.EmojiConverter() 16 | self.emoji_list = [] 17 | 18 | @commands.group() 19 | async def snipe(self, ctx): 20 | await ctx.send( 21 | f'''> {self.bot.snipes[ctx.message.channel.id]["content"]}\nauthor: {self.bot.snipes[ctx.message.channel.id]["author"]}''') 22 | 23 | @commands.command(aliases=["tt"]) 24 | async def triggertyping(self, ctx, duration: int, channel: discord.TextChannel = None): 25 | """sends a typing indicator for a specified amount of time 26 | Parameters 27 | • duration - how long to keep the typing indicator running 28 | • channel - which channel to send the typing indicator in, defaults to the current channel 29 | """ 30 | channel = channel or ctx.channel 31 | async with channel.typing(): 32 | await asyncio.sleep(duration) 33 | 34 | @commands.command() 35 | async def hexcode(self, ctx, *, role: discord.Role): 36 | """returns the hexcode of a role's color 37 | Parameters 38 | • role - the role to display the color of 39 | """ 40 | await ctx.send(f"{role.name} : {role.color}") 41 | 42 | @commands.command(aliases=["em"]) 43 | async def embed(self, ctx, color: typing.Optional[discord.Color] = None, *, text): 44 | '''embed text 45 | Parameters 46 | • text - the text to embed 47 | • color - the color of the embed, a random color is used if left empty 48 | ''' 49 | em = discord.Embed(color=color or random.randint(0, 0xFFFFFF)) 50 | em.description = text 51 | await ctx.send(embed=em) 52 | await ctx.message.delete() 53 | 54 | @commands.command(aliases=["rr"]) 55 | async def randomreact(self, ctx, message_no: typing.Optional[int] = 1, no_of_reactions: typing.Optional[int] = 20, *, 56 | server: str = None): 57 | """react to a message with random emojis 58 | Parameters 59 | • message_no - the index of the message to react to 60 | • no_of_reactions - amount of random emojis to react with, defaults to 20 61 | • server - the server from which to choose the emojis to react with, defaults to global emojis 62 | """ 63 | message_no -= 1 64 | server = server.lower() if server else server 65 | self.emoji_list = [] 66 | await ctx.message.delete() 67 | if server is None: 68 | self.emoji_list = [emoji for emoji in ctx.message.guild.emojis if not emoji.animated] 69 | elif server: 70 | s = discord.utils.find(lambda s: server in s.name.lower(), self.bot.guilds) 71 | self.emoji_list = [emoji for emoji in s.emojis if not emoji.animated] 72 | for index, message in enumerate(await ctx.channel.history(limit=30).flatten()): 73 | if index != message_no: 74 | continue 75 | for i in range(no_of_reactions): 76 | emoji = self.emoji_list.pop(self.emoji_list.index(random.choice(self.emoji_list))) 77 | await message.add_reaction(emoji) 78 | await asyncio.sleep(0.1) 79 | break 80 | 81 | @commands.command() 82 | async def react(self, ctx, message_no: typing.Optional[int] = 1, *emojis): 83 | '''react to a specified message with emojis 84 | Parameters 85 | • message_no - the index of the message to react to 86 | • emojis - the emojis to react with 87 | ''' 88 | history = await ctx.channel.history(limit=30).flatten() 89 | message = history[message_no] 90 | async for emoji in self.validate_emojis(ctx, *emojis): 91 | await message.add_reaction(emoji) 92 | await ctx.message.delete() 93 | 94 | async def validate_emojis(self, ctx, *reactions): 95 | ''' 96 | Checks if an emoji is valid otherwise, 97 | tries to convert it into a custom emoji 98 | ''' 99 | for emote in reactions: 100 | if emote in emoji.UNICODE_EMOJI: 101 | yield emote 102 | else: 103 | try: 104 | yield await self.emoji_converter.convert(ctx, emote) 105 | except commands.BadArgument: 106 | pass 107 | 108 | @commands.command(aliases=['color', 'colour', 'sc']) 109 | async def getcolor(self, ctx, color: discord.Colour, width: int = 200, height: int = 90, show_hexcode=True): 110 | '''displays a color from its name or hex value 111 | Parameters 112 | • color - the name or hexcode of the color to display 113 | • width - width of the image to display, defaults to 200 114 | • height - height of the image to display, defaults to 90 115 | • show_hexcode - whether to display the hexcode of the color, defaults to True 116 | ''' 117 | file = io.BytesIO() 118 | Image.new('RGB', (width, height), color.to_rgb()).save(file, format='PNG') 119 | file.seek(0) 120 | if show_hexcode: 121 | em = discord.Embed(color=color, title=f'Showing Color: {str(color)}') 122 | elif show_hexcode == False or "false": 123 | em = discord.Embed(color=color) 124 | em.set_image(url='attachment://color.png') 125 | await ctx.send(file=discord.File(file, 'color.png'), embed=em) 126 | 127 | @commands.command(name='emoji', aliases=['e']) 128 | async def _emoji(self, ctx, emoji: discord.Emoji, size: int = None): 129 | '''displays an enlarged pic of the emoji 130 | Parameters 131 | • size - the size of the image to display 132 | • emoji - The name(case sensitive) or id of the emoji 133 | ''' 134 | async with aiohttp.ClientSession() as session: 135 | async with session.get(f"{emoji.url}" + f"?size={size if size else ' '}") as resp: 136 | image = await resp.read() 137 | if emoji.animated: 138 | with io.BytesIO(image) as file: 139 | await ctx.send(file=discord.File(file, f"{emoji.name}.gif")) 140 | else: 141 | with io.BytesIO(image) as file: 142 | await ctx.send(file=discord.File(file, f"{emoji.name}.png")) 143 | await ctx.message.delete() 144 | 145 | @commands.command() 146 | async def textreact(self, ctx, messageNo: typing.Optional[int] = 1, *, text): 147 | """reacts to a message with emojis corresponding to the text 148 | Parameter 149 | • messageNo - the number of the message to react to 150 | • text - the text to react with 151 | """ 152 | text = (c for c in text.lower()) 153 | emotes = {"a": "🇦", "b": "🇧", "c": "🇨", "d": "🇩", "e": "🇪", "f": "🇫", "g": "🇬", "h": "🇭", 154 | "i": "🇮", "j": "🇯", "k": "🇰", "l": "🇱", "m": "🇲", "n": "🇳", "o": "🇴", "p": "🇵", 155 | "q": "🇶", "r": "🇷", "s": "🇸", "t": "🇹", "u": "🇺", "v": "🇻", "w": "🇼", "x": "🇽", 156 | "y": "🇾", "z": "🇿"} 157 | for i, m in enumerate(await ctx.channel.history(limit=100).flatten()): 158 | if messageNo == i: 159 | for c in text: 160 | await m.add_reaction(f"{emotes[c]}") 161 | break 162 | await ctx.message.delete() 163 | 164 | 165 | def setup(bot): 166 | bot.add_cog(misc(bot)) 167 | -------------------------------------------------------------------------------- /cogs/mod.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | import typing 4 | 5 | 6 | class mod(commands.Cog): 7 | """useful commands for moderation""" 8 | 9 | def __init__(self, bot): 10 | self.bot = bot 11 | self.saved_roles = {} 12 | 13 | async def format_mod_embed(self, ctx, user, success, method, duration=None, location=None): 14 | """Helper func to format an embed to prevent extra code""" 15 | if type(user) == int: 16 | user = await self.bot.fetch_user(user) 17 | emb = discord.Embed() 18 | emb.set_author(name=method.title(), icon_url=user.avatar_url_as(static_format="png")) 19 | emb.color = await ctx.get_dominant_color(user.avatar_url) 20 | emb.set_footer(text=f'User ID: {user.id}') 21 | if success: 22 | if method == 'ban' or method == 'hackban': 23 | emb.description = f'{user} was just {method}ned.' 24 | else: 25 | emb.description = f'{user} was just {method}ed.' 26 | else: 27 | emb.description = f"You do not have the permissions to {method} {user.name}." 28 | return emb 29 | 30 | @commands.command() 31 | async def savestate(self, ctx, user: discord.Member): 32 | self.saved_roles[user.id] = user.roles[1:] 33 | 34 | @commands.command() 35 | async def loadstate(self, ctx, user: discord.Member): 36 | await user.add_roles(*self.saved_roles[user.id]) 37 | 38 | @commands.command(aliases=["cr"]) 39 | async def clearreaction(self, ctx, message: typing.Optional[int] = 1, emoji: discord.Emoji = None): 40 | """clear a specific reaction from the message 41 | Parameters 42 | • message - the message number from which to remove the reaction 43 | • emoji - the reaction to remove from the message 44 | """ 45 | for i, m in enumerate(await ctx.channel.history().flatten()): 46 | if i == message: 47 | await m.clear_reaction(emoji) 48 | 49 | @commands.command(aliases=["crs"]) 50 | async def clearreactions(self, ctx, message: int): 51 | """clears all reactions on a message 52 | Parameters 53 | • message - the number of the message from which to remove the reactions 54 | """ 55 | for i, m in enumerate(await ctx.channel.history().flatten()): 56 | if i == message: 57 | await m.clear_reactions() 58 | 59 | @commands.command() 60 | async def kick(self, ctx, member: discord.Member, *, reason='No reason given'): 61 | """kick someone 62 | Parameters 63 | • member - the member to kick 64 | • reason - reason why the member was kicked 65 | """ 66 | self.saved_roles[member.id] = member.roles[1:] 67 | try: 68 | await ctx.guild.kick(member, reason=reason) 69 | except: 70 | success = False 71 | else: 72 | success = True 73 | 74 | emb = await self.format_mod_embed(ctx, member, success, 'kick') 75 | 76 | await ctx.send(embed=emb) 77 | 78 | @commands.command() 79 | async def ban(self, ctx, member: typing.Union[discord.Member, int], *, reason='No reason given'): 80 | """ban someone, can also be used to ban someone not in the guild using their id 81 | Parameters 82 | • member - the member to ban 83 | • reason - reason why the member was banned 84 | """ 85 | if member.isdigit() and len(member) == 18: 86 | user = await self.bot.fetch_user(member) 87 | self.saved_roles[user.id] = user.roles[1:] 88 | if type(member) == discord.Member: 89 | await ctx.guild.ban(member, reason=reason, delete_message_days=0) 90 | else: 91 | await ctx.guild.ban(discord.Object(member), reason=reason, delete_message_days=0) 92 | emb = await self.format_mod_embed(ctx, member, True, 'ban') 93 | await ctx.send(embed=emb) 94 | 95 | @commands.command() 96 | async def unban(self, ctx, name_or_id, *, reason=None): 97 | """unban someone 98 | Parameters 99 | • name_or_id - name or id of the banned user 100 | • reason - reason why the user was unbanned 101 | """ 102 | ban = await ctx.get_ban(name_or_id) 103 | 104 | try: 105 | await ctx.guild.unban(ban.user, reason=reason) 106 | except: 107 | success = False 108 | else: 109 | success = True 110 | 111 | emb = await self.format_mod_embed(ctx, ban.user, success, 'unban') 112 | 113 | await ctx.send(embed=emb) 114 | 115 | @commands.command(aliases=['prune']) 116 | async def purge(self, ctx, amount: int = 10, *, ignore_pins=True): 117 | """purge a number of messages 118 | Parameters 119 | • amount - the amount of messages to purge 120 | • ignore_pins - pass a truthy value to ignore pinned messages, defaults to True 121 | """ 122 | if ignore_pins: 123 | await ctx.purge(limit=amount + 1, check=lambda m: m.pinned == False) 124 | else: 125 | await ctx.purge(limit=amount + 1) 126 | 127 | def message_author(self, message, member): 128 | message.author.id == member.id 129 | 130 | @commands.group(aliases=["c"], invoke_without_command=True) 131 | async def clean(self, ctx, amount: typing.Optional[int] = 10, member: discord.Member = None): 132 | """delete a number of your own or another users messages 133 | Parameters 134 | • amount - the amount of messages to delete 135 | • member - the member whose messages are to be deleted, deletes your own messages by default 136 | """ 137 | deleted = 0 138 | await ctx.message.delete() 139 | user = member or ctx.message.author 140 | async for m in ctx.channel.history(limit=100): 141 | if m.author.id == user.id: 142 | await m.delete() 143 | deleted += 1 144 | if deleted == amount: 145 | break 146 | 147 | @clean.command(aliases=["i"]) 148 | async def images(self, ctx, images_to_delete: int = 10): 149 | """deletes messages containing images 150 | Parameters 151 | • images_to_delete - number of images to delete 152 | """ 153 | deleted = 0 154 | async for m in ctx.channel.history(limit=200): 155 | if m.attachments: 156 | await m.delete() 157 | deleted += 1 158 | if images_to_delete == deleted: 159 | break 160 | await ctx.message.delete() 161 | 162 | @clean.command(aliases=["b"]) 163 | async def bots(self, ctx, messages_to_delete: int = 15): 164 | """deletes messages sent by bots 165 | Parameters 166 | • messages_to_delete - number of messages to delete 167 | """ 168 | deleted = 0 169 | async for m in ctx.channel.history(limit=200): 170 | if m.author.bot: 171 | await m.delete() 172 | deleted += 1 173 | if deleted == messages_to_delete: 174 | break 175 | await ctx.message.delete() 176 | 177 | @clean.command(aliases=["w"]) 178 | async def word(self, ctx, messages_to_delete: typing.Optional[int] = 10, *, words: str): 179 | """deletes messages containing the specified words 180 | Parameters 181 | • words - the words to search for 182 | • messages_to_delete - number of messages to delete 183 | """ 184 | deleted = 0 185 | async for m in ctx.channel.history(limit=200): 186 | if words in m.content.lower(): 187 | await m.delete() 188 | deleted += 1 189 | if deleted == messages_to_delete + 1: 190 | break 191 | await ctx.message.delete() 192 | 193 | @commands.command() 194 | async def addroles(self, ctx, member: discord.Member, *roles: discord.Role): 195 | """Add roles to a user 196 | Parameter 197 | • member - the name or id of the member 198 | • roles - the name or id of the role""" 199 | output = "" 200 | await member.add_roles(*roles) 201 | for role in roles: 202 | output += f'Added: `{role.name}`\n' 203 | await ctx.send(output, delete_after=2) 204 | 205 | @commands.command() 206 | @commands.has_permissions(manage_roles=True) 207 | async def removerole(self, ctx, member: discord.Member, *, role: discord.Role): 208 | """Remove a role from someone else 209 | Parameter 210 | • member - the name or id of the member 211 | • role - the name or id of the role""" 212 | await member.remove_roles(role) 213 | await ctx.send(f'Removed: `{role.name}`') 214 | 215 | 216 | def setup(bot): 217 | bot.add_cog(mod(bot)) 218 | -------------------------------------------------------------------------------- /cogs/noble.py: -------------------------------------------------------------------------------- 1 | import discord 2 | import base64 3 | import os 4 | import glob 5 | import moviepy.editor as mpy 6 | from discord.ext import commands 7 | from PIL import Image, ImageDraw, ImageFont 8 | import codecs 9 | 10 | 11 | class noble(commands.Cog): 12 | def __init__(self, bot): 13 | self.bot = bot 14 | 15 | @commands.command() 16 | async def textgif(self, ctx, *, args): 17 | """Turn TEXT to GIF""" 18 | img = Image.new('RGB', (500, 45), "black") 19 | d = ImageDraw.Draw(img) 20 | c = 0 21 | font = ImageFont.truetype('./Tabitha.ttf', 27) 22 | for m in range(len(args)): 23 | x = 9 24 | d.text((x + c, 5), args[m], fill=(255, 255, 255), font=font) 25 | img.save(f'{m}.png') 26 | c += 13 27 | file_list = glob.glob('*.png') 28 | list.sort(file_list) 29 | clip = mpy.ImageSequenceClip(file_list, fps=10) 30 | clip.write_gif('content.gif', fps=10) 31 | await ctx.send(file=discord.File('content.gif')) 32 | await ctx.message.delete() 33 | for f in glob.glob("*.png"): 34 | os.remove(f) 35 | 36 | @commands.command() 37 | async def pictext(self, ctx, *, args): 38 | """Turn Text to PIC""" 39 | font = ImageFont.truetype('./Tabitha.ttf', 21) 40 | xoff, yoff = (10, 5) 41 | img = Image.new('RGB', (500, 45), 'black') 42 | d = ImageDraw.Draw(img) 43 | d.text((9, 5), args, fill="white", font=font) 44 | img.save('content.jpeg') 45 | await ctx.message.delete() 46 | await ctx.send(file=discord.File('content.jpeg')) 47 | 48 | @commands.command() 49 | async def encode(self, ctx, *, args): 50 | """Encode ascii Text to base64""" 51 | decoded_stuff = base64.b64encode('{}'.format(args).encode('ascii')) 52 | encoded_stuff = str(decoded_stuff) 53 | encoded_stuff = encoded_stuff[2:len(encoded_stuff) - 1] 54 | await ctx.message.delete() 55 | await ctx.send(content="{}".format(encoded_stuff)) 56 | 57 | @commands.command() 58 | async def decode(self, ctx, *, args: str): 59 | """Decode to ascii""" 60 | strOne = (args).encode("ascii") 61 | pad = len(strOne) % 4 62 | strOne += b"=" * pad 63 | encoded_stuff = codecs.decode(strOne.strip(), 'base64') 64 | decoded_stuff = str(encoded_stuff) 65 | decoded_stuff = decoded_stuff[2:len(decoded_stuff) - 1] 66 | await ctx.message.delete() 67 | await ctx.send(content="{}".format(decoded_stuff)) 68 | 69 | 70 | def setup(bot): 71 | bot.add_cog(noble(bot)) 72 | -------------------------------------------------------------------------------- /cogs/skid.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | from contextlib import redirect_stdout 4 | from PIL import Image 5 | import traceback 6 | import textwrap 7 | import asyncio 8 | import io 9 | import random 10 | import colorsys 11 | import inspect 12 | 13 | 14 | class skid(commands.Cog): 15 | def __init__(self, bot): 16 | self.bot = bot 17 | self._last_result = None 18 | self.text_flip = {} 19 | self.char_list = "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}" 20 | self.alt_char_list = "{|}zʎxʍʌnʇsɹbdouɯlʞɾᴉɥƃɟǝpɔqɐ,‾^[\]Z⅄XMΛ∩┴SɹQԀONW˥ʞſIHפℲƎpƆq∀@¿<=>;:68ㄥ9ϛㄣƐᄅƖ0/˙-'+*(),⅋%$#¡"[ 21 | ::-1] 22 | for idx, char in enumerate(self.char_list): 23 | self.text_flip[char] = self.alt_char_list[idx] 24 | self.text_flip[self.alt_char_list[idx]] = char 25 | 26 | @commands.command() 27 | async def eml(self, ctx, no_of_lines: int = 4): 28 | """displays colorful lines in embeds 29 | Parameters 30 | • no_of_lines - how many lines to display, defaults to 4 31 | """ 32 | for _ in range(no_of_lines): 33 | await ctx.invoke(self.bot.get_command("rc"), 200, 5, False) 34 | 35 | @commands.command() 36 | async def textflip(self, ctx, *, message): 37 | result = " " 38 | for char in message: 39 | if char in self.text_flip: 40 | result += self.text_flip[char] 41 | else: 42 | result += char 43 | await ctx.message.edit(content=result[::-1]) 44 | 45 | @commands.command() 46 | async def spam(self, ctx, text: str, spam_frequency: int, *spam_delay: int): 47 | await ctx.message.delete() 48 | for i in range(spam_frequency): 49 | await ctx.send(text) 50 | await asyncio.sleep(random.choice(spam_delay)) 51 | 52 | @commands.command(pass_context=True, hidden=True, name='eval') 53 | async def _eval(self, ctx, *, body: str): 54 | """Evaluates python code""" 55 | env = { 56 | 'bot': self.bot, 57 | 'ctx': ctx, 58 | 'channel': ctx.channel, 59 | 'author': ctx.author, 60 | 'guild': ctx.guild, 61 | 'message': ctx.message, 62 | '_': self._last_result, 63 | 'source': inspect.getsource 64 | } 65 | 66 | env.update(globals()) 67 | 68 | body = self.cleanup_code(body) 69 | stdout = io.StringIO() 70 | err = out = None 71 | 72 | to_compile = f'async def func():\n{textwrap.indent(body, " ")}' 73 | 74 | try: 75 | exec(to_compile, env) 76 | except Exception as e: 77 | err = await ctx.send(f'```py\n{e.__class__.__name__}: {e}\n```') 78 | return await err.add_reaction('❌') 79 | 80 | func = env['func'] 81 | try: 82 | with redirect_stdout(stdout): 83 | ret = await func() 84 | except Exception as e: 85 | value = stdout.getvalue() 86 | err = await ctx.send(f'```py\n{value}{traceback.format_exc()}\n```') 87 | else: 88 | value = stdout.getvalue() 89 | if ret is None: 90 | if value: 91 | try: 92 | out = await ctx.send(f'```py\n{value}\n```') 93 | except: 94 | paginated_text = ctx.paginate(value) 95 | for page in paginated_text: 96 | if page == paginated_text[-1]: 97 | out = await ctx.send(f'```py\n{page}\n```') 98 | break 99 | await ctx.send(f'```py\n{page}\n```') 100 | else: 101 | self._last_result = ret 102 | try: 103 | out = await ctx.send(f'```py\n{value}{ret}\n```') 104 | except: 105 | paginated_text = ctx.paginate(f"{value}{ret}") 106 | for page in paginated_text: 107 | if page == paginated_text[-1]: 108 | out = await ctx.send(f'```py\n{page}\n```') 109 | break 110 | await ctx.send(f'```py\n{page}\n```') 111 | 112 | if out: 113 | await out.add_reaction('✔') 114 | if err: 115 | await err.add_reaction('❌') 116 | 117 | def cleanup_code(self, content): 118 | """Automatically removes code blocks from the code.""" 119 | if content.startswith('```') and content.endswith('```'): 120 | return '\n'.join(content.split('\n')[1:-1]) 121 | return content.strip('` \n') 122 | 123 | def get_syntax_error(self, e): 124 | if e.text is None: 125 | return f'```py\n{e.__class__.__name__}: {e}\n```' 126 | return f'```py\n{e.text}{"^":>{e.offset}}\n{e.__class__.__name__}: {e}```' 127 | 128 | def getColor(self, colorHex): 129 | colorHex = str(colorHex) 130 | return discord.Colour(int(f'0x{colorHex[1:]}', 16)) 131 | 132 | def randomcolor(self): 133 | values = [int(x * 255) for x in colorsys.hsv_to_rgb(random.random(), 1, 1)] 134 | color = discord.Color.from_rgb(*values) 135 | return self.getColor(color) 136 | 137 | @commands.command() 138 | async def rc(self, ctx, width=200, height=90, show_hexcode=True): 139 | """Generates a random color""" 140 | file = io.BytesIO() 141 | color = self.randomcolor() 142 | Image.new('RGB', (width, height), color.to_rgb()).save(file, format='PNG') 143 | file.seek(0) 144 | em = discord.Embed(color=color) 145 | if show_hexcode: 146 | em.title = f'Showing Color: {str(color)}' 147 | em.set_image(url='attachment://color.png') 148 | await ctx.send(file=discord.File(file, 'color.png'), embed=em) 149 | 150 | 151 | def setup(bot): 152 | bot.add_cog(skid(bot)) 153 | -------------------------------------------------------------------------------- /cogs/source.py: -------------------------------------------------------------------------------- 1 | from discord.ext import commands 2 | import inspect 3 | 4 | 5 | class source(commands.Cog): 6 | def __init__(self, bot): 7 | self.bot = bot 8 | 9 | @commands.command() 10 | async def source(self, ctx, *, command: str): 11 | """shows source code of a command 12 | Parameters 13 | • command - the name of the command 14 | """ 15 | a = '`' * 3 16 | src = inspect.getsource(self.bot.get_command(command).callback) 17 | await ctx.send(f"{a}py\n{src}{a}") 18 | 19 | 20 | def setup(bot): 21 | bot.add_cog(source(bot)) 22 | -------------------------------------------------------------------------------- /cogs/textemotes.py: -------------------------------------------------------------------------------- 1 | from discord.ext import commands 2 | 3 | 4 | class textemotes(commands.Cog): 5 | def __init__(self, bot): 6 | self.bot = bot 7 | 8 | @commands.command() 9 | async def thumbs(self, ctx): 10 | """(👍' - ')👍""" 11 | await ctx.message.edit(content="(👍' - ')👍") 12 | 13 | @commands.command() 14 | async def cookie(self, ctx): 15 | """( ' - ')-🍪""" 16 | await ctx.message.edit(content="( ' - ')-🍪") 17 | 18 | @commands.command() 19 | async def cat(self, ctx): 20 | await ctx.message.edit(content=r"""{ \ / } 21 | ( ^ - ^ ) 22 | ( u u )~""") 23 | 24 | @commands.command() 25 | async def pew(self, ctx): 26 | """( ' - ')>---------- pew pew""" 27 | await ctx.message.edit(content="( ' - ')>---------- pew pew") 28 | 29 | @commands.command() 30 | async def lpew(self, ctx): 31 | """pew pew ----------<(' - ' )""" 32 | await ctx.message.edit(content="pew pew ----------<(' - ' )") 33 | 34 | 35 | def setup(bot): 36 | bot.add_cog(textemotes(bot)) 37 | -------------------------------------------------------------------------------- /cogs/utils.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | from ext.utility import load_json 4 | from mtranslate import translate 5 | import random 6 | import io 7 | import re 8 | import aiohttp 9 | 10 | 11 | class utility(commands.Cog): 12 | def __init__(self, bot): 13 | self.bot = bot 14 | self.lang_conv = load_json('data/langs.json') 15 | 16 | @commands.command() 17 | async def setbanner(self, ctx, *, banner=None): 18 | """sets the guilds banner 19 | Parameters 20 | • banner - the attachment or url of the image to use as a banner 21 | """ 22 | if ctx.message.attachments: 23 | image = await ctx.message.attachments[0].read() 24 | elif banner: 25 | async with aiohttp.ClientSession() as session: 26 | async with session.get(banner) as resp: 27 | image = await resp.read() 28 | await ctx.guild.edit(banner=image) 29 | await ctx.send("Banner updated") 30 | 31 | @commands.command() 32 | async def setsplash(self, ctx, *, splash=None): 33 | """sets the guilds invite splash 34 | Parameters 35 | • splash - the attachment or url of the image to use as the invite splash 36 | """ 37 | if ctx.message.attachments: 38 | image = await ctx.message.attachments[0].read() 39 | elif splash: 40 | async with aiohttp.ClientSession() as session: 41 | async with session.get(splash) as resp: 42 | image = await resp.read() 43 | await ctx.guild.edit(splash=image) 44 | await ctx.send("Invite Splash updated") 45 | 46 | @commands.command() 47 | async def splash(self, ctx, *, guild=None): 48 | """gets a guild's invite splash(invite background) 49 | Parameters 50 | • guild - the name or id of the guild 51 | """ 52 | if guild is None: 53 | guild = ctx.guild 54 | elif guild.isdigit() and len(guild) == 18: 55 | guild = discord.utils.get(self.bot.guilds, id=int(guild)) 56 | elif type(guild) == str: 57 | guild = discord.utils.get(self.bot.guilds, name=guild) 58 | splash = await guild.splash_url_as(format="png").read() 59 | with io.BytesIO(splash) as f: 60 | await ctx.send(file=discord.File(f, "splash.png")) 61 | 62 | @commands.command() 63 | async def banner(self, ctx, *, guild=None): 64 | """gets a guild's banner image 65 | Parameters 66 | • guild - the name or id of the guild 67 | """ 68 | if guild is None: 69 | guild = ctx.guild 70 | elif guild.isdigit() and len(guild) == 18: 71 | guild = discord.utils.get(self.bot.guilds, id=int(guild)) 72 | elif type(guild) == str: 73 | guild = discord.utils.get(self.bot.guilds, name=guild) 74 | banner = await guild.banner_url_as(format="png").read() 75 | with io.BytesIO(banner) as f: 76 | await ctx.send(file=discord.File(f, "banner.png")) 77 | 78 | @commands.command() 79 | async def translate(self, ctx, language, *, text): 80 | """translates the string into a given language 81 | Parameters 82 | • language - the language to translate to 83 | • text - the text to be translated 84 | """ 85 | await ctx.send(translate(text, language)) 86 | 87 | @commands.command() 88 | async def addemoji(self, ctx, emoji_name, emoji_url=None): 89 | """adds an emoji to a server 90 | Parameters 91 | • emoji_name – the name of the emoji 92 | • emoji_url – the url or attachment of an image to turn into an emoji 93 | """ 94 | if ctx.message.attachments: 95 | image = await ctx.message.attachments[0].read() 96 | elif emoji_url: 97 | async with aiohttp.ClientSession() as session: 98 | async with session.get(emoji_url) as resp: 99 | image = await resp.read() 100 | emoji = await ctx.guild.create_custom_emoji(name=emoji_name, image=image) 101 | await ctx.send(f"Emoji {emoji.name} created!") 102 | 103 | @commands.command() 104 | async def delemoji(self, ctx, emoji: discord.Emoji): 105 | """deletes an emoji 106 | Parameters 107 | • emoji - the name or id of the emoji 108 | """ 109 | name = emoji.name 110 | await emoji.delete() 111 | await ctx.send(content=f"Deleted emoji: {name}", delete_after=2) 112 | 113 | @commands.command() 114 | async def editemoji(self, ctx, emoji: discord.Emoji, new_name): 115 | """edits the name of an emoji 116 | Parameters 117 | • emoji - the name or id of the emoji 118 | • new_name - the new name to use for the emoji 119 | """ 120 | emoji_name = emoji.name 121 | await emoji.edit(name=new_name) 122 | await ctx.send(content=f"Edited emoji {emoji_name} to {new_name}", delete_after=2) 123 | 124 | @commands.command(name='logout') 125 | async def _logout(self, ctx): 126 | """ 127 | restart the bot 128 | """ 129 | await ctx.send('`Selfbot Logging out`') 130 | await self.bot.logout() 131 | 132 | @commands.command() 133 | async def nick(self, ctx, user: discord.Member, *, nickname: str = None): 134 | """change a user's nickname 135 | Parameter 136 | • user - the name or id of the user 137 | • nickname - the nickname to change to 138 | """ 139 | prevnick = user.nick or user.name 140 | await user.edit(nick=nickname) 141 | newnick = nickname or user.name 142 | await ctx.send(f"Changed {prevnick}'s nickname to {newnick}") 143 | 144 | @commands.command(aliases=["ca", "cactivity"]) 145 | async def customactivity(self, ctx, Type: str = "playing", *, text: str = None): 146 | """sets a custom activity 147 | Parameters 148 | • Type - "playing", "streaming", "listeningto" or "watching", defaults to playing 149 | • text - The text to display as presence 150 | """ 151 | types = {"playing": "Playing", "streaming": "Streaming", "listeningto": "Listening to", "watching": 152 | "Watching"} 153 | if text is None: 154 | await self.bot.change_presence(activity=text, afk=True) 155 | else: 156 | if Type == "playing": 157 | await self.bot.change_presence(activity=discord.Game(name=text), afk=True) 158 | elif Type == "streaming": 159 | await self.bot.change_presence(activity=discord.Streaming(name=text, url=f'https://twitch.tv/{text}'), 160 | afk=True) 161 | elif Type == "listeningto": 162 | await self.bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, 163 | name=text), afk=True) 164 | elif Type == "watching": 165 | await self.bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name=text), 166 | afk=True) 167 | em = discord.Embed(color=0xffd500, title="Presence") 168 | em.description = f"Presence : {types[Type]} {text}" 169 | if ctx.author.guild_permissions.embed_links: 170 | await ctx.send(embed=em) 171 | else: 172 | await ctx.send(f"Presence : {types[Type]} {text}") 173 | 174 | @commands.command() 175 | async def choose(self, ctx, *, choices: commands.clean_content): 176 | """choose! use , in between 177 | Parameters 178 | • choices - the choices to choose from separated using ,""" 179 | choices = choices.split(',') 180 | choices[0] = ' ' + choices[0] 181 | await ctx.send(str(random.choice(choices))[1:]) 182 | 183 | def get_user_from_global_cache(self, user): 184 | for u in self.bot.users: 185 | if user == u.name: 186 | return user 187 | 188 | @commands.command(aliases=["a", "pic"]) 189 | async def avatar(self, ctx, *, user=None): 190 | """gets the display picture of a user 191 | Parameters 192 | • user – The tag, name or id of the user 193 | """ 194 | user = user or ctx.author 195 | if type(user) != discord.Member: 196 | user = str(user) 197 | r = re.compile(r"@(.*#\d{4})|(\d{18})") 198 | r = r.search(user) 199 | if r: 200 | if r.group(2): 201 | user = int(r.group(2)) 202 | elif r.group(1): 203 | user = r.group(1) 204 | if type(user) == str: 205 | user = ctx.guild.get_member_named(user) 206 | if user is None: 207 | user = self.get_user_from_global_cache(user) 208 | elif str(user).isdigit() and len(str(user)) == 18: 209 | user = await self.bot.fetch_user(user) 210 | if user.is_avatar_animated(): 211 | format = "gif" 212 | else: 213 | format = "png" 214 | avatar = await user.avatar_url_as(format=format).read() 215 | with io.BytesIO(avatar) as file: 216 | await ctx.send(file=discord.File(file, f"DP.{format}")) 217 | await ctx.delete() 218 | 219 | @commands.command(aliases=["gi"]) 220 | async def guildicon(self, ctx, *, guild=None): 221 | """gets a guild's icon 222 | Parameters 223 | • guild - The name(case sensitive) or id of the guild/server""" 224 | guild = guild or ctx.guild 225 | format = "png" 226 | if guild.isdigit() and len(guild) == 18: 227 | guild = discord.utils.get(self.bot.guilds, id=int(guild)) 228 | elif type(guild) == str: 229 | guild = discord.utils.get(self.bot.guilds, name=guild) 230 | if guild.is_icon_animated(): 231 | format = "gif" 232 | icon = await guild.icon_url_as(format=format).read() 233 | with io.BytesIO(icon) as file: 234 | await ctx.send(file=discord.File(file, f"icon.{format}")) 235 | 236 | 237 | def setup(bot): 238 | bot.add_cog(utility(bot)) 239 | -------------------------------------------------------------------------------- /data/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "PREFIX": "-", 3 | "TOKEN": "your_token_here" 4 | } 5 | -------------------------------------------------------------------------------- /data/langs.json: -------------------------------------------------------------------------------- 1 | { 2 | "ab": "Abkhaz", 3 | "aa": "Afar", 4 | "af": "Afrikaans", 5 | "ak": "Akan", 6 | "sq": "Albanian", 7 | "am": "Amharic", 8 | "ar": "Arabic", 9 | "an": "Aragonese", 10 | "hy": "Armenian", 11 | "as": "Assamese", 12 | "av": "Avaric", 13 | "ae": "Avestan", 14 | "ay": "Aymara", 15 | "az": "Azerbaijani", 16 | "bm": "Bambara", 17 | "ba": "Bashkir", 18 | "eu": "Basque", 19 | "be": "Belarusian", 20 | "bn": "Bengali", 21 | "bh": "Bihari", 22 | "bi": "Bislama", 23 | "bs": "Bosnian", 24 | "br": "Breton", 25 | "bg": "Bulgarian", 26 | "my": "Burmese", 27 | "ca": "Catalan", 28 | "ch": "Chamorro", 29 | "ce": "Chechen", 30 | "ny": "Nyanja", 31 | "zh": "Chinese", 32 | "cv": "Chuvash", 33 | "kw": "Cornish", 34 | "co": "Corsican", 35 | "cr": "Cree", 36 | "hr": "Croatian", 37 | "cs": "Czech", 38 | "da": "Danish", 39 | "dv": "Divehi", 40 | "nl": "Dutch", 41 | "dz": "Dzongkha", 42 | "en": "English", 43 | "eo": "Esperanto", 44 | "et": "Estonian", 45 | "ee": "Ewe", 46 | "fo": "Faroese", 47 | "fj": "Fijian", 48 | "fi": "Finnish", 49 | "fr": "French", 50 | "ff": "Fula", 51 | "gl": "Galician", 52 | "ka": "Georgian", 53 | "de": "German", 54 | "el": "Greek", 55 | "gn": "Guarani", 56 | "gu": "Gujarati", 57 | "ht": "Haitian", 58 | "ha": "Hausa", 59 | "he": "Hebrew", 60 | "hz": "Herero", 61 | "hi": "Hindi", 62 | "ho": "Hiri-Motu", 63 | "hu": "Hungarian", 64 | "ia": "Interlingua", 65 | "id": "Indonesian", 66 | "ie": "Interlingue", 67 | "ga": "Irish", 68 | "ig": "Igbo", 69 | "ik": "Inupiaq", 70 | "io": "Ido", 71 | "is": "Icelandic", 72 | "it": "Italian", 73 | "iu": "Inuktitut", 74 | "ja": "Japanese", 75 | "jv": "Javanese", 76 | "kl": "Kalaallisut", 77 | "kn": "Kannada", 78 | "kr": "Kanuri", 79 | "ks": "Kashmiri", 80 | "kk": "Kazakh", 81 | "km": "Khmer", 82 | "ki": "Kikuyu", 83 | "rw": "Kinyarwanda", 84 | "ky": "Kyrgyz", 85 | "kv": "Komi", 86 | "kg": "Kongo", 87 | "ko": "Korean", 88 | "ku": "Kurdish", 89 | "kj": "Kwanyama", 90 | "la": "Latin", 91 | "lb": "Luxembourgish", 92 | "lg": "Luganda", 93 | "li": "Limburgish", 94 | "ln": "Lingala", 95 | "lo": "Lao", 96 | "lt": "Lithuanian", 97 | "lu": "Luba-Katanga", 98 | "lv": "Latvian", 99 | "gv": "Manx", 100 | "mk": "Macedonian", 101 | "mg": "Malagasy", 102 | "ms": "Malay", 103 | "ml": "Malayalam", 104 | "mt": "Maltese", 105 | "mi": "M\u0101ori", 106 | "mr": "Marathi", 107 | "mh": "Marshallese", 108 | "mn": "Mongolian", 109 | "na": "Nauru", 110 | "nv": "Navajo", 111 | "nb": "Norwegian Bokm\u00e5l", 112 | "nd": "North-Ndebele", 113 | "ne": "Nepali", 114 | "ng": "Ndonga", 115 | "nn": "Norwegian-Nynorsk", 116 | "no": "Norwegian", 117 | "ii": "Nuosu", 118 | "nr": "South-Ndebele", 119 | "oc": "Occitan", 120 | "oj": "Ojibwe", 121 | "cu": "Old-Church-Slavonic", 122 | "om": "Oromo", 123 | "or": "Oriya", 124 | "os": "Ossetian", 125 | "pa": "Panjabi", 126 | "pi": "P\u0101li", 127 | "fa": "Persian", 128 | "pl": "Polish", 129 | "ps": "Pashto", 130 | "pt": "Portuguese", 131 | "qu": "Quechua", 132 | "rm": "Romansh", 133 | "rn": "Kirundi", 134 | "ro": "Romanian", 135 | "ru": "Russian", 136 | "sa": "Sanskrit", 137 | "sc": "Sardinian", 138 | "sd": "Sindhi", 139 | "se": "Northern-Sami", 140 | "sm": "Samoan", 141 | "sg": "Sango", 142 | "sr": "Serbian", 143 | "gd": "Scottish-Gaelic", 144 | "sn": "Shona", 145 | "si": "Sinhala", 146 | "sk": "Slovak", 147 | "sl": "Slovene", 148 | "so": "Somali", 149 | "st": "Southern-Sotho", 150 | "es": "Spanish", 151 | "su": "Sundanese", 152 | "sw": "Swahili", 153 | "ss": "Swati", 154 | "sv": "Swedish", 155 | "ta": "Tamil", 156 | "te": "Telugu", 157 | "tg": "Tajik", 158 | "th": "Thai", 159 | "ti": "Tigrinya", 160 | "bo": "Tibetan", 161 | "tk": "Turkmen", 162 | "tl": "Tagalog", 163 | "tn": "Tswana", 164 | "to": "Tonga", 165 | "tr": "Turkish", 166 | "ts": "Tsonga", 167 | "tt": "Tatar", 168 | "tw": "Twi", 169 | "ty": "Tahitian", 170 | "ug": "Uighur", 171 | "uk": "Ukrainian", 172 | "ur": "Urdu", 173 | "uz": "Uzbek", 174 | "ve": "Venda", 175 | "vi": "Vietnamese", 176 | "vo": "Volapuk", 177 | "wa": "Walloon", 178 | "cy": "Welsh", 179 | "wo": "Wolof", 180 | "fy": "Western-Frisian", 181 | "xh": "Xhosa", 182 | "yi": "Yiddish", 183 | "yo": "Yoruba", 184 | "za": "Zhuang", 185 | "zu": "Zulu" 186 | } 187 | -------------------------------------------------------------------------------- /ext/colours.py: -------------------------------------------------------------------------------- 1 | class ColorNames: 2 | WebColorMap = {} 3 | WebColorMap["Alice Blue"] = "#F0F8FF" 4 | WebColorMap["Antique White"] = "#FAEBD7" 5 | WebColorMap["Aqua"] = "#00FFFF" 6 | WebColorMap["Aquamarine"] = "#7FFFD4" 7 | WebColorMap["Azure"] = "#F0FFFF" 8 | WebColorMap["Beige"] = "#F5F5DC" 9 | WebColorMap["Bisque"] = "#FFE4C4" 10 | WebColorMap["Black"] = "#000000" 11 | WebColorMap["Blanched Almond"] = "#FFEBCD" 12 | WebColorMap["Blue"] = "#0000FF" 13 | WebColorMap["Blue Violet"] = "#8A2BE2" 14 | WebColorMap["Brown"] = "#A52A2A" 15 | WebColorMap["Burly Wood"] = "#DEB887" 16 | WebColorMap["Cadet Blue"] = "#5F9EA0" 17 | WebColorMap["Chartreuse"] = "#7FFF00" 18 | WebColorMap["Chocolate"] = "#D2691E" 19 | WebColorMap["Coral"] = "#FF7F50" 20 | WebColorMap["Cornflower Blue"] = "#6495ED" 21 | WebColorMap["Cornsilk"] = "#FFF8DC" 22 | WebColorMap["Crimson"] = "#DC143C" 23 | WebColorMap["Cyan"] = "#00FFFF" 24 | WebColorMap["Dark Blue"] = "#00008B" 25 | WebColorMap["Dark Cyan"] = "#008B8B" 26 | WebColorMap["Dark Golden Rod"] = "#B8860B" 27 | WebColorMap["Dark Gray"] = "#A9A9A9" 28 | WebColorMap["Dark Grey"] = "#A9A9A9" 29 | WebColorMap["Dark Green"] = "#006400" 30 | WebColorMap["Dark Khaki"] = "#BDB76B" 31 | WebColorMap["Dark Magenta"] = "#8B008B" 32 | WebColorMap["Dark Olive Green"] = "#556B2F" 33 | WebColorMap["Dark Orange"] = "#FF8C00" 34 | WebColorMap["Dark Orchid"] = "#9932CC" 35 | WebColorMap["Dark Red"] = "#8B0000" 36 | WebColorMap["Dark Salmon"] = "#E9967A" 37 | WebColorMap["Dark Sea Green"] = "#8FBC8F" 38 | WebColorMap["Dark Slate Blue"] = "#483D8B" 39 | WebColorMap["Dark Slate Gray"] = "#2F4F4F" 40 | WebColorMap["Dark Slate Grey"] = "#2F4F4F" 41 | WebColorMap["Dark Turquoise"] = "#00CED1" 42 | WebColorMap["Dark Violet"] = "#9400D3" 43 | WebColorMap["Deep Pink"] = "#FF1493" 44 | WebColorMap["Deep Sky Blue"] = "#00BFFF" 45 | WebColorMap["Dim Gray"] = "#696969" 46 | WebColorMap["Dodger Blue"] = "#1E90FF" 47 | WebColorMap["Fire Brick"] = "#B22222" 48 | WebColorMap["Floral White"] = "#FFFAF0" 49 | WebColorMap["Forest Green"] = "#228B22" 50 | WebColorMap["Fuchsia"] = "#FF00FF" 51 | WebColorMap["Gainsboro"] = "#DCDCDC" 52 | WebColorMap["Ghost White"] = "#F8F8FF" 53 | WebColorMap["Gold"] = "#FFD700" 54 | WebColorMap["Golden Rod"] = "#DAA520" 55 | WebColorMap["Gray"] = "#808080" 56 | WebColorMap["Grey"] = "#808080" 57 | WebColorMap["Green"] = "#008000" 58 | WebColorMap["Green Yellow"] = "#ADFF2F" 59 | WebColorMap["Honey Dew"] = "#F0FFF0" 60 | WebColorMap["Hot Pink"] = "#FF69B4" 61 | WebColorMap["Indian Red"] = "#CD5C5C" 62 | WebColorMap["Indigo"] = "#4B0082" 63 | WebColorMap["Ivory"] = "#FFFFF0" 64 | WebColorMap["Khaki"] = "#F0E68C" 65 | WebColorMap["Lavender"] = "#E6E6FA" 66 | WebColorMap["Lavender Blush"] = "#FFF0F5" 67 | WebColorMap["Lawn Green"] = "#7CFC00" 68 | WebColorMap["Lemon Chiffon"] = "#FFFACD" 69 | WebColorMap["Light Blue"] = "#ADD8E6" 70 | WebColorMap["Light Coral"] = "#F08080" 71 | WebColorMap["Light Cyan"] = "#E0FFFF" 72 | WebColorMap["Light GoldenRodYellow"] = "#FAFAD2" 73 | WebColorMap["Light Gray"] = "#D3D3D3" 74 | WebColorMap["Light Grey"] = "#D3D3D3" 75 | WebColorMap["Light Green"] = "#90EE90" 76 | WebColorMap["Light Pink"] = "#FFB6C1" 77 | WebColorMap["Light Salmon"] = "#FFA07A" 78 | WebColorMap["Light Sea Green"] = "#20B2AA" 79 | WebColorMap["Light Sky Blue"] = "#87CEFA" 80 | WebColorMap["Light Slate Gray"] = "#778899" 81 | WebColorMap["Light Slate Grey"] = "#778899" 82 | WebColorMap["Light Steel Blue"] = "#B0C4DE" 83 | WebColorMap["Light Yellow"] = "#FFFFE0" 84 | WebColorMap["Lime"] = "#00FF00" 85 | WebColorMap["Lime Green"] = "#32CD32" 86 | WebColorMap["Linen"] = "#FAF0E6" 87 | WebColorMap["Magenta"] = "#FF00FF" 88 | WebColorMap["Maroon"] = "#800000" 89 | WebColorMap["Medium Aqua Marine"] = "#66CDAA" 90 | WebColorMap["Medium Blue"] = "#0000CD" 91 | WebColorMap["Medium Orchid"] = "#BA55D3" 92 | WebColorMap["Medium Purple"] = "#9370D8" 93 | WebColorMap["Medium Sea Green"] = "#3CB371" 94 | WebColorMap["Medium Slate Blue"] = "#7B68EE" 95 | WebColorMap["Medium Spring Green"] = "#00FA9A" 96 | WebColorMap["Medium Turquoise"] = "#48D1CC" 97 | WebColorMap["Medium VioletRed"] = "#C71585" 98 | WebColorMap["Midnight Blue"] = "#191970" 99 | WebColorMap["Mint Cream"] = "#F5FFFA" 100 | WebColorMap["Misty Rose"] = "#FFE4E1" 101 | WebColorMap["Moccasin"] = "#FFE4B5" 102 | WebColorMap["Navajo White"] = "#FFDEAD" 103 | WebColorMap["Navy"] = "#000080" 104 | WebColorMap["Old Lace"] = "#FDF5E6" 105 | WebColorMap["Olive"] = "#808000" 106 | WebColorMap["Olive Drab"] = "#6B8E23" 107 | WebColorMap["Orange"] = "#FFA500" 108 | WebColorMap["Orange Red"] = "#FF4500" 109 | WebColorMap["Orchid"] = "#DA70D6" 110 | WebColorMap["Pale Golden Rod"] = "#EEE8AA" 111 | WebColorMap["Pale Green"] = "#98FB98" 112 | WebColorMap["Pale Turquoise"] = "#AFEEEE" 113 | WebColorMap["Pale Violet Red"] = "#D87093" 114 | WebColorMap["Papaya Whip"] = "#FFEFD5" 115 | WebColorMap["Peach Puff"] = "#FFDAB9" 116 | WebColorMap["Peru"] = "#CD853F" 117 | WebColorMap["Pink"] = "#FFC0CB" 118 | WebColorMap["Plum"] = "#DDA0DD" 119 | WebColorMap["Powder Blue"] = "#B0E0E6" 120 | WebColorMap["Purple"] = "#800080" 121 | WebColorMap["Red"] = "#FF0000" 122 | WebColorMap["Rosy Brown"] = "#BC8F8F" 123 | WebColorMap["Royal Blue"] = "#4169E1" 124 | WebColorMap["Saddle Brown"] = "#8B4513" 125 | WebColorMap["Salmon"] = "#FA8072" 126 | WebColorMap["Sandy Brown"] = "#F4A460" 127 | WebColorMap["Sea Green"] = "#2E8B57" 128 | WebColorMap["Sea Shell"] = "#FFF5EE" 129 | WebColorMap["Sienna"] = "#A0522D" 130 | WebColorMap["Silver"] = "#C0C0C0" 131 | WebColorMap["Sky Blue"] = "#87CEEB" 132 | WebColorMap["Slate Blue"] = "#6A5ACD" 133 | WebColorMap["Slate Gray"] = "#708090" 134 | WebColorMap["Slate Grey"] = "#708090" 135 | WebColorMap["Snow"] = "#FFFAFA" 136 | WebColorMap["Spring Green"] = "#00FF7F" 137 | WebColorMap["Steel Blue"] = "#4682B4" 138 | WebColorMap["Tan"] = "#D2B48C" 139 | WebColorMap["Teal"] = "#008080" 140 | WebColorMap["Thistle"] = "#D8BFD8" 141 | WebColorMap["Tomato"] = "#FF6347" 142 | WebColorMap["Turquoise"] = "#40E0D0" 143 | WebColorMap["Violet"] = "#EE82EE" 144 | WebColorMap["Wheat"] = "#F5DEB3" 145 | WebColorMap["White"] = "#FFFFFF" 146 | WebColorMap["White Smoke"] = "#F5F5F5" 147 | WebColorMap["Yellow"] = "#FFFF00" 148 | WebColorMap["Yellow Green"] = "#9ACD32" 149 | 150 | @staticmethod 151 | def rgbFromStr(s): 152 | # s starts with a #. 153 | r, g, b = int(s[1:3],16), int(s[3:5], 16),int(s[5:7], 16) 154 | return r, g, b 155 | 156 | @staticmethod 157 | def color_name(s): 158 | r, g, b = int(s[1:3],16), int(s[3:5], 16),int(s[5:7], 16) 159 | return ColorNames.findNearestWebColorName(r, g, b) 160 | 161 | @staticmethod 162 | def findNearestWebColorName(R,G,B): 163 | return ColorNames.findNearestColorName(R,G,B,ColorNames.WebColorMap) 164 | 165 | @staticmethod 166 | def findNearestColorName(R,G,B,Map): 167 | mindiff = None 168 | for d in Map: 169 | r, g, b = ColorNames.rgbFromStr(Map[d]) 170 | diff = abs(R -r)*256 + abs(G-g)* 256 + abs(B- b)* 256 171 | if mindiff is None or diff < mindiff: 172 | mindiff = diff 173 | mincolorname = d 174 | return mincolorname 175 | 176 | 177 | -------------------------------------------------------------------------------- /ext/context.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | import asyncio 4 | from colorthief import ColorThief 5 | import io 6 | import os 7 | 8 | class CustomContext(commands.Context): 9 | '''Custom Context class to provide utility.''' 10 | def __init__(self, **kwargs): 11 | super().__init__(**kwargs) 12 | 13 | def delete(self): 14 | '''shortcut''' 15 | return self.message.delete() 16 | 17 | async def get_ban(self, name_or_id): 18 | '''Helper function to retrieve a banned user''' 19 | for ban in await self.guild.bans(): 20 | if name_or_id.isdigit(): 21 | if ban.user.id == int(name_or_id): 22 | return ban 23 | if name_or_id.lower() in str(ban.user).lower(): 24 | return ban 25 | 26 | async def purge(self, *args, **kwargs): 27 | '''Shortcut to channel.purge, preset for selfbots.''' 28 | kwargs.setdefault('bulk', False) 29 | await self.channel.purge(*args, **kwargs) 30 | 31 | async def get_dominant_color(self, url=None, quality=10): 32 | '''Returns the dominant color of an image from a url''' 33 | maybe_col = os.environ.get('COLOR') 34 | 35 | url = url or self.author.avatar_url 36 | 37 | if maybe_col: 38 | raw = int(maybe_col.strip('#'), 16) 39 | return discord.Color(value=raw) 40 | try: 41 | async with aiohttp.ClientSession() as session: 42 | async with session.get(url) as resp: 43 | image = await resp.read() 44 | except: 45 | return discord.Color.default() 46 | 47 | with io.BytesIO(image) as f: 48 | try: 49 | color = ColorThief(f).get_color(quality=quality) 50 | except: 51 | return discord.Color.dark_grey() 52 | 53 | return discord.Color.from_rgb(*color) 54 | 55 | async def success(self, msg=None, delete=False): 56 | if delete: 57 | await ctx.message.delete() 58 | if msg: 59 | await self.send(msg) 60 | else: 61 | await self.message.add_reaction('✔') 62 | 63 | async def failure(self, msg=None): 64 | if msg: 65 | await self.send(msg) 66 | else: 67 | await self.message.add_reaction('❌') 68 | 69 | @staticmethod 70 | def paginate(text: str): 71 | '''Simple generator that paginates text.''' 72 | last = 0 73 | pages = [] 74 | for curr in range(0, len(text)): 75 | if curr % 1980 == 0: 76 | pages.append(text[last:curr]) 77 | last = curr 78 | appd_index = curr 79 | if appd_index != len(text)-1: 80 | pages.append(text[last:curr]) 81 | return list(filter(lambda a: a != '', pages)) 82 | -------------------------------------------------------------------------------- /ext/embedtobox.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | Copyright (c) 2017 kwugfighter 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 13 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 | DEALINGS IN THE SOFTWARE. 19 | """ 20 | 21 | import discord 22 | 23 | async def etb(emb): 24 | emb_str = "```md\n" 25 | emb_list = [] 26 | if emb.author: 27 | emb_str += f"<{emb.author.name}>\n\n" 28 | if emb.title: 29 | emb_str += f"<{emb.title}>\n" 30 | if emb.description: 31 | if len(f"{emb_str}{emb.description}\n```")>2000: 32 | emb_str += "```" 33 | emb_list.append(emb_str) 34 | emb_str = "```md\n" 35 | emb_str += f"{emb.description}\n" 36 | if emb.fields: 37 | for field in emb.fields: 38 | if len(f"{emb_str}#{field.name}\n{field.value}\n```")>2000: 39 | emb_str += "```" 40 | emb_list.append(emb_str) 41 | emb_str = "```md\n" 42 | emb_str += f"#{field.name}\n{field.value}\n" 43 | if emb.footer: 44 | if len(f"{emb_str}\n{emb.footer.text}\n```")>2000: 45 | emb_str += "```" 46 | emb_list.append(emb_str) 47 | emb_str = "```md\n" 48 | emb_str += f"\n{emb.footer.text}\n" 49 | if emb.timestamp: 50 | if len("{}\n{}\n```".format(emb_str, str(emb.timestamp)))>2000: 51 | emb_str += "```" 52 | emb_list.append(emb_str) 53 | emb_str = "```md\n" 54 | emb_str += "\n{}".format(str(emb.timestamp)) 55 | emb_str += "```" 56 | if emb_str != "```md\n```": 57 | emb_list.append(emb_str) 58 | return emb_list 59 | -------------------------------------------------------------------------------- /ext/formatter.py: -------------------------------------------------------------------------------- 1 | 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | The MIT License (MIT) 6 | Copyright (c) 2015-2017 Rapptz 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | """ 23 | 24 | import discord 25 | 26 | class Paginator: 27 | """A class that aids in paginating embeds for Discord messages. 28 | Attributes 29 | ----------- 30 | max_size: int 31 | The maximum amount of codepoints allowed in a page. 32 | """ 33 | def __init__(self, max_size=1995): 34 | self.max_size = max_size 35 | self._current_embed = discord.Embed() 36 | self._current_field = [] 37 | self._count = 0 38 | self._embeds = [] 39 | self.last_cog = None 40 | 41 | def add_line(self, line='', *, empty=False): 42 | """Adds a line to the current embed page. 43 | If the line exceeds the :attr:`max_size` then an exception 44 | is raised. 45 | Parameters 46 | ----------- 47 | line: str 48 | The line to add. 49 | empty: bool 50 | Indicates if another empty line should be added. 51 | Raises 52 | ------ 53 | RuntimeError 54 | The line was too big for the current :attr:`max_size`. 55 | """ 56 | if len(line) > self.max_size - 2: 57 | raise RuntimeError('Line exceeds maximum page size %s' % (self.max_size - 2)) 58 | 59 | if self._count + len(line) + 1 > self.max_size: 60 | self.close_page() 61 | 62 | self._count += len(line) + 1 63 | self._current_field.append(line) 64 | 65 | if empty: 66 | self._current_field.append('') 67 | 68 | def close_page(self): 69 | """Prematurely terminate a page.""" 70 | name = value = '' 71 | while self._current_field: 72 | curr = self._current_field.pop(0) # goes through each line 73 | if curr.strip().endswith(':'): # this means its a CogName: 74 | if name: 75 | if value: 76 | self._current_embed.add_field(name=name, value=value) 77 | name, value = curr, '' # keeps track of the last cog sent, 78 | self.last_cog = curr # so the next embed can have a `continued` thing 79 | else: 80 | if value: 81 | if self.last_cog: 82 | self._current_embed.add_field(name=f'{self.last_cog} (continued)', value=value) 83 | value = '' 84 | name = curr 85 | self.last_cog = curr 86 | else: 87 | value += curr + '\n' 88 | 89 | # adds the last parts not done in the while loop 90 | print(self.last_cog) 91 | if self.last_cog and value: 92 | self._current_embed.add_field(name=self.last_cog, value=value) 93 | value = '' 94 | 95 | # this means that there was no `Cog:` title thingys, that means that its a command help 96 | if value and not self.last_cog: 97 | fmt = list(filter(None, value.split('\n'))) 98 | self._current_embed.title = f'``{fmt[0]}``' # command signiture 99 | self._current_embed.description = '\n'.join(fmt[1:]) # command desc 100 | 101 | self._embeds.append(self._current_embed) 102 | self._current_embed = discord.Embed() 103 | self._current_field = [] 104 | self._count = 1 105 | 106 | @property 107 | def pages(self): 108 | """Returns the rendered list of pages.""" 109 | # we have more than just the prefix in our current page 110 | if len(self._current_field) > 1: 111 | self.close_page() 112 | return self._embeds 113 | 114 | def __repr__(self): 115 | fmt = '' 116 | return fmt.format(self) 117 | -------------------------------------------------------------------------------- /ext/helpformatter.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext.commands import DefaultHelpCommand 3 | 4 | class helpformatter(DefaultHelpCommand): 5 | def get_ending_note(self): 6 | return f"A bot made by Kaen#6390" 7 | -------------------------------------------------------------------------------- /ext/stringview.py: -------------------------------------------------------------------------------- 1 | def paginate(text: str, maxlen: int): 2 | '''Simple generator that paginates text.''' 3 | last = 0 4 | for curr in range(0, len(text)+maxlen, maxlen): 5 | if last == curr: 6 | continue 7 | else: 8 | yield text[last:curr] 9 | last = curr 10 | 11 | 12 | def shlex_split(body): 13 | '''Function that splits on spaces while retaining quoted peices of text''' 14 | 15 | curr = '' 16 | is_quoted = False 17 | is_first = False 18 | args = [] 19 | 20 | for index, char in enumerate(body): 21 | 22 | if char == '"': 23 | if body[index-1] != '\\': # escapes 24 | is_quoted = True 25 | is_first = False if is_first else True 26 | 27 | if is_quoted: 28 | curr += char 29 | if not is_first: 30 | args.append(curr) 31 | curr = '' 32 | is_quoted = False 33 | else: 34 | if char.isspace(): 35 | args.append(curr) 36 | curr = '' 37 | else: 38 | curr += char 39 | 40 | if index+1 == len(body): 41 | if is_first: 42 | curr = curr.split() 43 | args.extend(curr) 44 | else: 45 | args.append(curr) 46 | 47 | args = list(filter(lambda x: x.strip(), args)) # takes out spaces 48 | 49 | for i, arg in enumerate(args): 50 | arg = arg.replace('\\"', '"') # escapes 51 | if arg.count(' '): 52 | arg = arg.strip('"') # removes the quotes 53 | args[i] = arg 54 | 55 | return args 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /ext/utility.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | def load_json(path): 4 | try: 5 | with open(path) as f: 6 | return json.load(f) 7 | except: 8 | return {} -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | discord.py 2 | mtranslate~=1.8 3 | colorthief~=0.2.1 4 | moviepy~=1.0.3 5 | requests 6 | emoji~=1.2.0 7 | 8 | aiohttp~=3.7.4.post0 9 | Pillow~=8.2.0 -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.8.5 2 | -------------------------------------------------------------------------------- /selfbot.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | from ext.context import CustomContext 4 | from ext.helpformatter import helpformatter 5 | import json 6 | import os 7 | import re 8 | import traceback 9 | import sys 10 | 11 | 12 | class Selfbot(commands.Bot): 13 | def __init__(self, **attrs): 14 | super().__init__(command_prefix=self.get_pre, self_bot=True, help_command=helpformatter()) 15 | self.load_extensions() 16 | self.snipes = {} 17 | 18 | def load_extensions(self): 19 | for extension in os.listdir("./cogs"): 20 | try: 21 | if extension.endswith(".py"): 22 | self.load_extension(f"cogs.{extension[:-3]}") 23 | print(f'Loaded extension: {extension}') 24 | except: 25 | print(f'LoadError: {extension}\n' 26 | f'{traceback.print_exc()}') 27 | 28 | @property 29 | def token(self): 30 | '''Returns your token wherever it is''' 31 | with open('data/config.json') as f: 32 | config = json.load(f) 33 | if config.get('TOKEN') == "your_token_here": 34 | if not os.environ.get('TOKEN'): 35 | self.run_wizard() 36 | else: 37 | token = config.get('TOKEN').strip('\"') 38 | return os.environ.get('TOKEN') or token 39 | 40 | @staticmethod 41 | async def get_pre(bot, message): 42 | '''Returns the prefix.''' 43 | with open('data/config.json') as f: 44 | prefix = json.load(f).get('PREFIX') 45 | return os.environ.get('PREFIX') or prefix or 'r.' 46 | 47 | def restart(self): 48 | os.execv(sys.executable, ['python'] + sys.argv) 49 | 50 | @staticmethod 51 | def run_wizard(): 52 | '''Wizard for first start''' 53 | print('------------------------------------------') 54 | token = input('Enter your token:\n> ') 55 | print('------------------------------------------') 56 | prefix = input('Enter a prefix for your selfbot:\n> ') 57 | data = { 58 | "TOKEN": token, 59 | "PREFIX": prefix, 60 | } 61 | with open('data/config.json', 'w') as f: 62 | f.write(json.dumps(data, indent=4)) 63 | print('------------------------------------------') 64 | print('Restarting...') 65 | print('------------------------------------------') 66 | os.execv(sys.executable, ['python'] + sys.argv) 67 | 68 | @classmethod 69 | def init(bot, token=None): 70 | '''Starts the actual bot''' 71 | selfbot = bot() 72 | safe_token = token or selfbot.token.strip('\"') 73 | try: 74 | selfbot.run(safe_token, bot=False, reconnect=True) 75 | except Exception as e: 76 | print(e) 77 | 78 | async def on_connect(self): 79 | print('connected') 80 | 81 | async def on_ready(self): 82 | '''Bot startup''' 83 | print('Logged in!') 84 | await self.change_presence(status=discord.Status.online, afk=True) 85 | 86 | async def process_commands(self, message): 87 | '''Utilises the CustomContext subclass of discord.Context''' 88 | ctx = await self.get_context(message, cls=CustomContext) 89 | self.ctx = await self.get_context(message, cls=CustomContext) 90 | if ctx.command is None: 91 | return 92 | await self.invoke(ctx) 93 | 94 | @classmethod 95 | def black(cls): 96 | return cls(0x000000) 97 | 98 | discord.Color.black = black 99 | 100 | async def on_message_delete(self, message): 101 | if len(message.content) != 1: 102 | self.snipes[message.channel.id] = {"content": message.content, "author": message.author} 103 | 104 | async def on_message_edit(self, before, after): 105 | await self.process_commands(after) 106 | 107 | async def on_message(self, message): 108 | r = re.compile(r">(#[0-9a-fA-F]{6}) (.*)") 109 | r = r.match(message.content) 110 | if r and (self.user == message.author): 111 | await message.delete() 112 | await message.channel.send( 113 | embed=discord.Embed(color=discord.Color(int("0x" + f"{r.group(1)[1:]}", 16)), 114 | description=r.group(2))) 115 | await self.process_commands(message) 116 | 117 | 118 | if __name__ == '__main__': 119 | Selfbot.init() 120 | -------------------------------------------------------------------------------- /start_bot.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | chcp 65001 3 | echo. 4 | pushd %~dp0 5 | 6 | ::Attempts to start py launcher without relying on PATH 7 | %SYSTEMROOT%\py.exe --version > NUL 2>&1 8 | IF %ERRORLEVEL% NEQ 0 GOTO attempt 9 | %SYSTEMROOT%\py.exe -3 selfbot.py 10 | PAUSE 11 | GOTO end 12 | 13 | ::Attempts to start py launcher by relying on PATH 14 | :attempt 15 | py.exe --version > NUL 2>&1 16 | IF %ERRORLEVEL% NEQ 0 GOTO lastattempt 17 | py.exe -3 selfbot.py 18 | PAUSE 19 | GOTO end 20 | 21 | ::As a last resort, attempts to start whatever Python there is 22 | :lastattempt 23 | python.exe --version > NUL 2>&1 24 | IF %ERRORLEVEL% NEQ 0 GOTO message 25 | python.exe selfbot.py 26 | PAUSE 27 | GOTO end 28 | 29 | :message 30 | echo Couldn't find a valid Python ^>3.5 installation. Python needs to be installed and available in the PATH environment 31 | echo variable. 32 | PAUSE 33 | 34 | :end 35 | --------------------------------------------------------------------------------