|
| 1 | +### Modules ### |
| 2 | +import os |
| 3 | +import time |
| 4 | +import os.path |
| 5 | +import discord |
| 6 | +import datetime |
| 7 | +from keep_alive import keep_alive |
| 8 | +import requests |
| 9 | +import json |
| 10 | +from discord.ext import commands |
| 11 | +from discord.ext.commands import * |
| 12 | +from discord.ext import tasks |
| 13 | +### Modules end ### |
| 14 | + |
| 15 | +### Startup/variables ### |
| 16 | +ids = [ |
| 17 | + 816941773032390676, |
| 18 | + 738290097170153472, |
| 19 | + 705462972415213588, |
| 20 | + 706697300872921088 |
| 21 | +] |
| 22 | +console = False |
| 23 | +log = True |
| 24 | +if os.name == 'nt': |
| 25 | + os.system('cls') |
| 26 | +else: |
| 27 | + os.system('clear') |
| 28 | +print('Checking for rate limit errors...') |
| 29 | +r = requests.head(url="https://discord.com/api/v1") |
| 30 | +try: |
| 31 | + print(f"Rate limit error found: {int(r.headers['Retry-After']) / 60} minutes left") |
| 32 | + raise(SystemExit) |
| 33 | +except: |
| 34 | + print("No rate limit found.") |
| 35 | +time.sleep(1) |
| 36 | +intents = discord.Intents.all() |
| 37 | +errHandlerVer = 'v2.4' |
| 38 | +botVer = 'v1.0' |
| 39 | +if os.name == 'nt': |
| 40 | + os.system('cls') |
| 41 | +else: |
| 42 | + os.system('clear') |
| 43 | +owner = '@notsniped' |
| 44 | +homedir = os.path.expanduser("~") |
| 45 | +client = commands.Bot(command_prefix="+", intents=intents) |
| 46 | +global startTime |
| 47 | +startTime = time.time() |
| 48 | +client.remove_command('help') |
| 49 | +### Startup\\variables end ### |
| 50 | + |
| 51 | +### Command variables ### |
| 52 | +theme_color = 0xffbd59 |
| 53 | +color_success = 0x77b255 |
| 54 | +color_fail = 0xc92424 |
| 55 | +rootdir = 'C://Users//dhruvbhat//OneDrive//Desktop//increment.io' |
| 56 | +loggerHandler_path = f'botLog/log.txt' |
| 57 | +errorHandler_path = f'botLog/errors.txt' |
| 58 | +### Functions and classes ### |
| 59 | + |
| 60 | +correctnumber = {} |
| 61 | + |
| 62 | +class colors: |
| 63 | + cyan = '\033[96m' |
| 64 | + red = '\033[91m' |
| 65 | + green = '\033[92m' |
| 66 | + end = '\033[0m' |
| 67 | + |
| 68 | +with open(f'database/count.json', 'r') as f: |
| 69 | + global count |
| 70 | + count = json.load(f) |
| 71 | +with open(f'database/configuration/countchannel.json', 'r') as f: |
| 72 | + global countchannel |
| 73 | + countchannel = json.load(f) |
| 74 | +with open(f'database/configuration/warning.json', 'r') as f: |
| 75 | + global warnmsg |
| 76 | + warnmsg = json.load(f) |
| 77 | +with open(f'database/configuration/autoreactions.json', 'r') as f: |
| 78 | + global autoreactions |
| 79 | + autoreactions = json.load(f) |
| 80 | + |
| 81 | +def savedata(): |
| 82 | + with open(f'database/count.json', 'w+') as f: |
| 83 | + json.dump(count, f) |
| 84 | + with open(f'database/configuration/countchannel.json', 'w+') as f: |
| 85 | + json.dump(countchannel, f) |
| 86 | + with open(f'database/configuration/autoreactions.json', 'w+') as f: |
| 87 | + json.dump(autoreactions, f) |
| 88 | + |
| 89 | +def get_time(): |
| 90 | + now = datetime.datetime.now() |
| 91 | + return now.strftime("%H:%M:%S") |
| 92 | + |
| 93 | +### Functions and classes end ### |
| 94 | + |
| 95 | +## Events ### |
| 96 | +@client.event |
| 97 | +async def on_ready(): |
| 98 | + if os.name == 'nt': |
| 99 | + os.system('cls') |
| 100 | + else: |
| 101 | + os.system('clear') |
| 102 | + await client.change_presence(activity=discord.Activity(type=discord.ActivityType.playing, name=f"the epic comeback. (+help) | {str(len(client.guilds))} guilds")) |
| 103 | + print('Bot is online') |
| 104 | + print('==================') |
| 105 | + print('------------------') |
| 106 | + print('Bot Info') |
| 107 | + print(f'Bot version: {colors.cyan}{botVer}{colors.end}') |
| 108 | + print(f'Error handler version: {colors.cyan}{errHandlerVer}{colors.end}') |
| 109 | + print(f'Username: {colors.green}{client.user.name}{colors.end}\nId: {colors.green}{client.user.id}{colors.end}\nDeveloper name: {colors.green}{owner}{colors.end}') |
| 110 | + print('==================') |
| 111 | + print('Bot config:') |
| 112 | + print('------------------') |
| 113 | + print(f'Ping: {round(client.latency * 1000)}') |
| 114 | + print('------------------') |
| 115 | + boot = str(datetime.timedelta(seconds=int(round(time.time()-startTime)))) |
| 116 | + print(f'Startup time: {boot}') |
| 117 | + print('------------------') |
| 118 | + print(f'Server count: {str(len(client.guilds))}') |
| 119 | + print('------------------') |
| 120 | + if bool(log) == True: |
| 121 | + print(f'Logging: {colors.green}{log}{colors.end}') |
| 122 | + print('==================') |
| 123 | + else: |
| 124 | + print(f'Logging: {colors.red}{log}{colors.end}') |
| 125 | + print('==================') |
| 126 | + pass |
| 127 | + print('Bot admins') |
| 128 | + print('------------------') |
| 129 | + print(colors.cyan) |
| 130 | + for id in ids: |
| 131 | + print(id) |
| 132 | + print(colors.end) |
| 133 | + print('==================') |
| 134 | + print('System info') |
| 135 | + print('Running as: ' + str(os.system("whoami"))) |
| 136 | + print('------------------') |
| 137 | + print('Os name: ' + str(os.name)) |
| 138 | + print('------------------') |
| 139 | + print('Current working dir: ' + str(os.getcwd())) |
| 140 | + print(f'System directory: {homedir}') |
| 141 | + print('------------------') |
| 142 | + try: |
| 143 | + botpath = 'main.py' |
| 144 | + botsize = os.path.getsize(botpath) |
| 145 | + print(f'Bot file size: {botsize}b') |
| 146 | + print('------------------') |
| 147 | + except FileNotFoundError: |
| 148 | + if os.name == 'posix': |
| 149 | + try: |
| 150 | + print('Bot file size: ' + os.path.getsize('main.py')) |
| 151 | + print('------------------') |
| 152 | + except FileNotFoundError: |
| 153 | + print('Bot file size: ' + os.path.getsize(str(os.getcwd() + '\\main.py'))) |
| 154 | + print('------------------') |
| 155 | + |
| 156 | +# Error handler # |
| 157 | +@client.event |
| 158 | +async def on_command_error(ctx, error): |
| 159 | + now = datetime.datetime.now() |
| 160 | + current_time = now.strftime("%H:%M:%S") |
| 161 | + if isinstance(error, discord.ext.commands.CommandNotFound): |
| 162 | + if os.name == 'nt': |
| 163 | + with open(errorHandler_path, 'a') as f: |
| 164 | + f.write(f'[{current_time}/WARN] Ignoring exception at CommandNotFound. Details: This command does not exist.\n') |
| 165 | + f.close() |
| 166 | + print(f'{colors.red}[{current_time}/WARN] Ignoring exception at CommandNotFound. Details: This command does not exist.{colors.end}') |
| 167 | + else: |
| 168 | + pass |
| 169 | + if isinstance(error, discord.ext.commands.CommandOnCooldown): |
| 170 | + await ctx.send(f':warning: This command is currently on cooldown, try after **{str(datetime.timedelta(seconds=int(round(error.retry_after))))}**', delete_after=5) |
| 171 | + if os.name == 'nt': |
| 172 | + with open(errorHandler_path, 'a') as f: |
| 173 | + f.write(f'[{current_time}/WARN] Ignoring exception at CommandOnCooldown. Details: This command is currently on cooldown.\n') |
| 174 | + f.close() |
| 175 | + print(f'{colors.red}[{current_time}/WARN] Ignoring exception at CommandOnCooldown. Details: This command is currently on cooldown.{colors.end}') |
| 176 | + else: |
| 177 | + pass |
| 178 | + if isinstance(error, discord.ext.commands.MissingRequiredArgument): |
| 179 | + await ctx.send(':x: Your command has missing required argument(s).', delete_after=3) |
| 180 | + if os.name == 'nt': |
| 181 | + with open(errorHandler_path, 'a') as f: |
| 182 | + f.write(f'[{current_time}/WARN] Ignoring exception at MissingRequiredArgument. Details: The command can\'t be executed because required arguments are missing.\n') |
| 183 | + f.close() |
| 184 | + print(f'{colors.red}[{current_time}/WARN] Ignoring exception at MissingRequiredArgument. Details: The command can\'t be executed because required arguments are missing.{colors.end}') |
| 185 | + else: |
| 186 | + pass |
| 187 | + if isinstance(error, discord.ext.commands.MissingPermissions): |
| 188 | + await ctx.send(':x: You don\'t have permissions to use this command.', delete_after=3) |
| 189 | + if os.name == 'nt': |
| 190 | + with open(errorHandler_path, 'a') as f: |
| 191 | + f.write(f'[{current_time}/WARN] Ignoring exception at MissingPermissions. Details: The user doesn\'t have the required permissions.\n') |
| 192 | + f.close() |
| 193 | + print(f'{colors.red}[{current_time}/WARN] Ignoring exception at MissingPermissions. Details: The user doesn\'t have the required permissions.{colors.end}') |
| 194 | + else: |
| 195 | + pass |
| 196 | + if isinstance(error, discord.ext.commands.BadArgument): |
| 197 | + await ctx.send(':x: Invalid argument.', delete_after=3) |
| 198 | + if os.name == 'nt': |
| 199 | + with open(errorHandler_path, 'a') as f: |
| 200 | + f.write(f'[{current_time}/WARN] Ignoring exception at BadArgument.\n') |
| 201 | + f.close() |
| 202 | + print(f'{colors.red}[{current_time}/WARN] Ignoring exception at BadArgument.{colors.end}') |
| 203 | + else: |
| 204 | + pass |
| 205 | + if isinstance(error, discord.ext.commands.BotMissingPermissions): |
| 206 | + await ctx.send(':x: I don\'t have permissions to do this. Kindly manage my role permissions to get this feature working.') |
| 207 | + if os.name == 'nt': |
| 208 | + with open(errorHandler_path, 'a') as f: |
| 209 | + f.write(f'[{current_time}/WARN] Ignoring exception at BotMissingPermissions.\n Details: The bot doesn\'t have the required permissions.\n') |
| 210 | + f.close() |
| 211 | + print(f'{colors.red}[{current_time}/WARN] Ignoring exception at BotMissingPremissions. Details: The bot doesn\'t have the required permissions.{colors.end}') |
| 212 | + else: |
| 213 | + pass |
| 214 | +# Error handler end # |
| 215 | + |
| 216 | +snipe_message_author = {} |
| 217 | +snipe_message_content = {} |
| 218 | + |
| 219 | +@client.event |
| 220 | +async def on_message(message): |
| 221 | + global count |
| 222 | + if str(message.channel.id) in count: pass |
| 223 | + else: |
| 224 | + count[str(message.channel.id)] = 1 |
| 225 | + savedata() |
| 226 | + if str(message.guild.id) in countchannel: pass |
| 227 | + else: |
| 228 | + countchannel[str(message.guild.id)] = 0 |
| 229 | + savedata() |
| 230 | + if str(message.guild.id) in warnmsg: pass |
| 231 | + else: |
| 232 | + warnmsg[str(message.guild.id)] = 0 |
| 233 | + savedata() |
| 234 | + if str(message.guild.id) in autoreactions: pass |
| 235 | + else: |
| 236 | + autoreactions[str(message.guild.id)] = 1 |
| 237 | + savedata() |
| 238 | + if not message.author.bot: |
| 239 | + if message.channel.id == countchannel[str(message.guild.id)]: |
| 240 | + try: |
| 241 | + if int(message.content) == count[str(message.channel.id)]: |
| 242 | + count[str(message.channel.id)] += 1 |
| 243 | + if autoreactions[str(message.guild.id)] == 1: await message.add_reaction('☑') |
| 244 | + else: pass |
| 245 | + savedata() |
| 246 | + else: |
| 247 | + if autoreactions[str(message.guild.id)] == 1: await message.add_reaction('❌') |
| 248 | + else: pass |
| 249 | + await message.reply(f'**Wrong!** The next number is `{count[str(message.channel.id)]}`', mention_author = False, delete_after = 3) |
| 250 | + except: |
| 251 | + if autoreactions[str(message.guild.id)] == 1: await message.add_reaction('⚠') |
| 252 | + else: pass |
| 253 | + else: pass |
| 254 | + else: pass |
| 255 | + await client.process_commands(message) |
| 256 | + |
| 257 | +### Events end ### |
| 258 | + |
| 259 | +### Commands ### |
| 260 | + |
| 261 | +@client.command() |
| 262 | +async def uptime(ctx): |
| 263 | + uptime = str(datetime.timedelta(seconds=int(round(time.time()-startTime)))) |
| 264 | + await ctx.send(f'This session has been running for **{uptime}**') |
| 265 | + |
| 266 | +@client.command(aliases=['commands']) |
| 267 | +async def help(ctx): |
| 268 | + emb = discord.Embed(title=f'increment.io Commands', description=f'I am a counting bot who looks for numbers and makes sure that the count doesn\'t get messed up. If you want help on commands or want a more organized view, check https://notsniped.github.io/increment.io/commands\n :warning: This bot is still WIP. Some commands/features may not work as expected.\n\n**Prefix:** ```Main Prefix: +```\n**Information:** ```+help, +ping, +stats, +serverstats,+credits```\n**Counting:** ```+setchannel, +numberonly [on/off], +reactions [on/off], +setnumber [number], +resetcount```', color=theme_color) |
| 269 | + await ctx.send(embed = emb) |
| 270 | + |
| 271 | +@client.command(aliases=['pong']) |
| 272 | +async def ping(ctx): |
| 273 | + await ctx.send(f':ping_pong: Pong! In **{round(client.latency * 1000)}ms**.') |
| 274 | + |
| 275 | +@client.command() |
| 276 | +async def credits(ctx): |
| 277 | + emb = discord.Embed(title='Bot Credits', description='Owner: <@!738290097170153472>\nHelpers: <@!706697300872921088>, <@!705462972415213588>',color=theme_color) |
| 278 | + emb.set_footer(text='increment.io >> https://notsniped.github.io/increment.io') |
| 279 | + await ctx.send(embed=emb) |
| 280 | + |
| 281 | +@client.command() |
| 282 | +async def serverstats(ctx): |
| 283 | + servericon = ctx.guild.icon_url |
| 284 | + setchannelstats = countchannel[str(ctx.guild.id)] |
| 285 | + setchannelmaxcount = count[setchannelstats] |
| 286 | + emb12 = discord.Embed(title='This Server\'s Stats', color=theme_color) |
| 287 | + emb12.add_field(name='Count Channel', value=f'<#{setchannelstats}>') |
| 288 | + emb12.add_field(name='Current Count', value=setchannelmaxcount) |
| 289 | + emb12.set_thumbnail(url=servericon) |
| 290 | + await ctx.send(embed = emb12) |
| 291 | + |
| 292 | +## Moderation Commands End ## |
| 293 | + |
| 294 | +## Count Commands ## |
| 295 | + |
| 296 | +@client.command() |
| 297 | +@commands.has_permissions(administrator = True) |
| 298 | +async def setchannel(ctx): |
| 299 | + channel_to_set = ctx.channel.id |
| 300 | + try: |
| 301 | + countchannel[str(ctx.guild.id)] = channel_to_set |
| 302 | + savedata() |
| 303 | + await ctx.send(f':white_check_mark: <#{channel_to_set}> set as counting channel.') |
| 304 | + except: await ctx.send(':x: Unable to set count channel. Try again later.') |
| 305 | + |
| 306 | +@client.command() |
| 307 | +@commands.has_permissions(administrator = True) |
| 308 | +async def reactions(ctx, setting:str): |
| 309 | + if setting == 'on': |
| 310 | + if autoreactions[str(ctx.guild.id)] == 1: await ctx.send(f':warning: This feature is already enabled.') |
| 311 | + else: |
| 312 | + autoreactions[str(ctx.guild.id)] = 1 |
| 313 | + savedata() |
| 314 | + await ctx.send(f':white_check_mark: Turned **on** count reactions.') |
| 315 | + elif setting == 'off': |
| 316 | + if autoreactions[str(ctx.guild.id)] == 0: await ctx.send(f':warning: This feature is already disabled') |
| 317 | + else: |
| 318 | + autoreactions[str(ctx.guild.id)] = 0 |
| 319 | + savedata() |
| 320 | + await ctx.send(f':white_check_mark: Turned **off** count reactions.') |
| 321 | + else: await ctx.send(f'\'{setting}\' is not a valid option. You can choose between `on` and `off`') |
| 322 | + |
| 323 | +@client.command(aliases=['setnum']) |
| 324 | +async def setnumber(ctx, arg1:int): |
| 325 | + if arg1 < 1: raise(discord.ext.commands.BadArgument) |
| 326 | + else: |
| 327 | + count[str(ctx.channel.id)] = arg1 |
| 328 | + savedata() |
| 329 | + await ctx.reply(f':white_check_mark: Count set to `{count[str(ctx.channel.id)]}`') |
| 330 | + |
| 331 | +@client.command(aliases=['resetnumber', 'reset', 'resetnum']) |
| 332 | +async def resetcount(ctx): |
| 333 | + count[str(ctx.channel.id)] = 1 |
| 334 | + savedata() |
| 335 | + await ctx.reply(':white_check_mark: Count successfully reset back to `1`') |
| 336 | + |
| 337 | +## Count Commands End ## |
| 338 | + |
| 339 | +### Commands end ### |
| 340 | +keep_alive() |
| 341 | +client.run('') # Insert your bot token here |
0 commit comments