You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
6.6 KiB

  1. import os
  2. import asyncio
  3. import sys
  4. import logging
  5. import logging.handlers
  6. import traceback
  7. import aiohttp
  8. import config
  9. import discord
  10. from discord.ext import commands
  11. script_name = os.path.basename(__file__).split('.')[0]
  12. log_file_name = f"{script_name}.log"
  13. # Limit of discord (non-nitro) is 8MB (not MiB)
  14. max_file_size = 1000 * 1000 * 8
  15. backup_count = 3
  16. file_handler = logging.handlers.RotatingFileHandler(
  17. filename=log_file_name, maxBytes=max_file_size, backupCount=backup_count)
  18. stdout_handler = logging.StreamHandler(sys.stdout)
  19. log_format = logging.Formatter(
  20. '[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s')
  21. file_handler.setFormatter(log_format)
  22. stdout_handler.setFormatter(log_format)
  23. log = logging.getLogger('discord')
  24. log.setLevel(logging.INFO)
  25. log.addHandler(file_handler)
  26. log.addHandler(stdout_handler)
  27. def get_prefix(bot, message):
  28. prefixes = config.prefixes
  29. return commands.when_mentioned_or(*prefixes)(bot, message)
  30. wanted_jsons = ["data/restrictions.json",
  31. "data/robocronptab.json",
  32. "data/userlog.json"]
  33. initial_extensions = ['cogs.common',
  34. 'cogs.admin',
  35. 'cogs.mod',
  36. 'cogs.mod_note',
  37. 'cogs.mod_reacts',
  38. 'cogs.mod_userlog',
  39. 'cogs.mod_timed',
  40. 'cogs.basic',
  41. 'cogs.logs',
  42. 'cogs.err',
  43. 'cogs.lockdown',
  44. 'cogs.legacy',
  45. 'cogs.links',
  46. 'cogs.robocronp',
  47. 'cogs.meme']
  48. bot = commands.Bot(command_prefix=get_prefix,
  49. description=config.bot_description, pm_help=True)
  50. bot.log = log
  51. bot.loop = asyncio.get_event_loop()
  52. bot.config = config
  53. bot.script_name = script_name
  54. bot.wanted_jsons = wanted_jsons
  55. if __name__ == '__main__':
  56. for extension in initial_extensions:
  57. try:
  58. bot.load_extension(extension)
  59. except Exception as e:
  60. log.error(f'Failed to load extension {extension}.')
  61. log.error(traceback.print_exc())
  62. @bot.event
  63. async def on_ready():
  64. aioh = {"User-Agent": f"{script_name}/1.0'"}
  65. bot.aiosession = aiohttp.ClientSession(headers=aioh)
  66. bot.app_info = await bot.application_info()
  67. log.info(f'\nLogged in as: {bot.user.name} - '
  68. f'{bot.user.id}\ndpy version: {discord.__version__}\n')
  69. game_name = f"{config.prefixes[0]}help"
  70. # Send "Robocop has started! x has y members!"
  71. log_channel = bot.get_channel(config.log_channel)
  72. guild = log_channel.guild
  73. msg = f"{bot.user.name} has started! "\
  74. f"{guild.name} has {guild.member_count} members!"
  75. data_files = [discord.File(fpath) for fpath in wanted_jsons]
  76. await log_channel.send(msg, files=data_files)
  77. await bot.change_presence(activity=discord.Game(name=game_name))
  78. @bot.event
  79. async def on_command(ctx):
  80. log_text = f"{ctx.message.author} ({ctx.message.author.id}): "\
  81. f"\"{ctx.message.content}\" "
  82. if ctx.guild: # was too long for tertiary if
  83. log_text += f"on \"{ctx.channel.name}\" ({ctx.channel.id}) "\
  84. f"at \"{ctx.guild.name}\" ({ctx.guild.id})"
  85. else:
  86. log_text += f"on DMs ({ctx.channel.id})"
  87. log.info(log_text)
  88. @bot.event
  89. async def on_error(event_method, *args, **kwargs):
  90. log.error(f"Error on {event_method}: {sys.exc_info()}")
  91. @bot.event
  92. async def on_command_error(ctx, error):
  93. error_text = str(error)
  94. log.error(f"Error with \"{ctx.message.content}\" from "
  95. f"\"{ctx.message.author} ({ctx.message.author.id}) "
  96. f"of type {type(error)}: {error_text}")
  97. if isinstance(error, commands.NoPrivateMessage):
  98. return await ctx.send("This command doesn't work on DMs.")
  99. elif isinstance(error, commands.MissingPermissions):
  100. roles_needed = '\n- '.join(error.missing_perms)
  101. return await ctx.send(f"{ctx.author.mention}: You don't have the right"
  102. " permissions to run this command. You need: "
  103. f"```- {roles_needed}```")
  104. elif isinstance(error, commands.BotMissingPermissions):
  105. roles_needed = '\n-'.join(error.missing_perms)
  106. return await ctx.send(f"{ctx.author.mention}: Bot doesn't have "
  107. "the right permissions to run this command. "
  108. "Please add the following roles: "
  109. f"```- {roles_needed}```")
  110. elif isinstance(error, commands.CommandOnCooldown):
  111. return await ctx.send(f"{ctx.author.mention}: You're being "
  112. "ratelimited. Try in "
  113. f"{error.retry_after:.1f} seconds.")
  114. elif isinstance(error, commands.CheckFailure):
  115. return await ctx.send(f"{ctx.author.mention}: Check failed. "
  116. "You might not have the right permissions "
  117. "to run this command.")
  118. elif isinstance(error, commands.CommandInvokeError) and\
  119. ("Cannot send messages to this user" in error_text):
  120. return await ctx.send(f"{ctx.author.mention}: I can't DM you.\n"
  121. "You might have me blocked or have DMs "
  122. f"blocked globally or for {ctx.guild.name}.\n"
  123. "Please resolve that, then "
  124. "run the command again.")
  125. elif isinstance(error, commands.CommandNotFound):
  126. # Nothing to do when command is not found.
  127. return
  128. help_text = f"Usage of this command is: ```{ctx.prefix}"\
  129. f"{ctx.command.signature}```\nPlease see `{ctx.prefix}help "\
  130. f"{ctx.command.name}` for more info about this command."
  131. if isinstance(error, commands.BadArgument):
  132. return await ctx.send(f"{ctx.author.mention}: You gave incorrect "
  133. f"arguments. {help_text}")
  134. elif isinstance(error, commands.MissingRequiredArgument):
  135. return await ctx.send(f"{ctx.author.mention}: You gave incomplete "
  136. f"arguments. {help_text}")
  137. @bot.event
  138. async def on_message(message):
  139. if message.author.bot:
  140. return
  141. if (message.guild) and (message.guild.id not in config.guild_whitelist):
  142. return
  143. ctx = await bot.get_context(message)
  144. await bot.invoke(ctx)
  145. if not os.path.exists("data"):
  146. os.makedirs("data")
  147. for wanted_json in wanted_jsons:
  148. if not os.path.exists(wanted_json):
  149. with open(wanted_json, "w") as f:
  150. f.write("{}")
  151. bot.run(config.token, bot=True, reconnect=True, loop=bot.loop)