1
0

commands.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import discord
  2. import urllib
  3. import datetime
  4. from typing import List, Tuple
  5. import myanimebot.utils as utils
  6. import myanimebot.globals as globals
  7. import myanimebot.anilist as anilist
  8. def build_info_cmd_message(users, server, channels, filters : List[utils.Service]) -> str:
  9. ''' Build the corresponding message for the info command '''
  10. registered_channel = globals.client.get_channel(int(channels[0]["channel"]))
  11. # Store users
  12. mal_users = []
  13. anilist_users = []
  14. for user in users:
  15. # If user is part of the server, add it to the message
  16. if str(server.id) in user['servers'].split(','):
  17. try:
  18. user_service = utils.Service.from_str(user["service"])
  19. if user_service == utils.Service.MAL:
  20. mal_users.append(user[globals.DB_USER_NAME])
  21. elif user_service == utils.Service.ANILIST:
  22. anilist_users.append(user[globals.DB_USER_NAME])
  23. except NotImplementedError:
  24. pass # Nothing to do here
  25. if not mal_users and not anilist_users:
  26. return "No users registered on this server. Try to add one."
  27. else:
  28. message = 'Registered user(s) on **{}**\n\n'.format(server)
  29. if mal_users: # If not empty
  30. # Don't print if there is filters and MAL is not in them
  31. if not filters or (filters and utils.Service.MAL in filters):
  32. message += '**MyAnimeList** users:\n'
  33. message += '```{}```\n'.format(', '.join(mal_users))
  34. if anilist_users: # If not empty
  35. # Don't print if there is filters and MAL is not in them
  36. if not filters or (filters and utils.Service.ANILIST in filters):
  37. message += '**AniList** users:\n'
  38. message += '```{}```\n'.format(', '.join(anilist_users))
  39. message += 'Assigned channel : **{}**'.format(registered_channel)
  40. return message
  41. def get_service_filters_list(filters : str) -> List[utils.Service]:
  42. ''' Creates and returns a service filter list from a comma-separated string '''
  43. filters_list = []
  44. for filter in filters.split(','):
  45. try:
  46. filters_list.append(utils.Service.from_str(filter))
  47. except NotImplementedError:
  48. pass # Ignore incorrect filter
  49. return filters_list
  50. def check_user_name_validity(user_name: str, service : utils.Service) -> Tuple[bool, str]:
  51. """ Check if user_name exists on a specific service.
  52. Returns:
  53. - bool: True if user_name exists
  54. - str: Error string if the user does not exist
  55. """
  56. if service == utils.Service.MAL:
  57. try:
  58. # Ping user profile to check validity
  59. urllib.request.urlopen('{}{}'.format(globals.MAL_PROFILE_URL, user_name))
  60. except urllib.error.HTTPError as e:
  61. if (e.code == 404): # URL profile not found
  62. return False, "User **{}** doesn't exist on MyAnimeList!".format(user_name)
  63. else:
  64. globals.logger.warning("HTTP Code {} while trying to add user '{}' and checking its validity.".format(e.code, user_name))
  65. return False, "An error occured when we checked this username on MyAnimeList, maybe the website is down?"
  66. elif service == utils.Service.ANILIST:
  67. is_user_valid = anilist.check_username_validity(user_name)
  68. if is_user_valid == False:
  69. globals.logger.warning("No results returned while trying to add user '{}' and checking its validity.".format(user_name))
  70. return False, "User **{}** doesn't exist on AniList!".format(user_name)
  71. return True, None
  72. async def add_user_cmd(words, message):
  73. ''' Processes the command "add" and add a user to fetch the data for '''
  74. # Check if command is valid
  75. if len(words) != 4:
  76. if (len(words) < 4):
  77. return await message.channel.send("Usage: {} add **{}**/**{}** **username**".format(globals.prefix, globals.SERVICE_MAL, globals.SERVICE_ANILIST))
  78. return await message.channel.send("Too many arguments! You have to specify only one username.")
  79. try:
  80. service = utils.Service.from_str(words[2])
  81. except NotImplementedError:
  82. return await message.channel.send('Incorrect service. Use **"{}"** or **"{}"** for example'.format(globals.SERVICE_MAL, globals.SERVICE_ANILIST))
  83. user = words[3]
  84. server_id = str(message.guild.id)
  85. if(len(user) > 14):
  86. return await message.channel.send("Username too long!")
  87. try:
  88. # Check user validity
  89. is_valid, error_string = check_user_name_validity(user, service)
  90. if is_valid == False:
  91. return await message.channel.send(error_string)
  92. # Get user's servers
  93. user_servers = utils.get_user_servers(user, service)
  94. # User not present in database
  95. if user_servers is None:
  96. utils.insert_user_into_db(user, service, server_id)
  97. return await message.channel.send("**{}** added to the database for the server **{}**.".format(user, str(message.guild)))
  98. else: # User present in database
  99. is_server_present = server_id in user_servers.split(',')
  100. if is_server_present == True: # The user already has registered this server
  101. return await message.channel.send("User **{}** is already registered in our database for this server!".format(user))
  102. else:
  103. new_servers = '{},{}'.format(user_servers, server_id)
  104. utils.update_user_servers_db(user, service, new_servers)
  105. return await message.channel.send("**{}** added to the database for the server **{}**.".format(user, str(message.guild)))
  106. except Exception as e:
  107. globals.logger.warning("Error while adding user '{}' on server '{}': {}".format(user, message.guild, str(e)))
  108. return await message.channel.send("An unknown error occured while addind this user, the error has been logged.")
  109. async def delete_user_cmd(words, message):
  110. ''' Processes the command "delete" and remove a registered user '''
  111. # Check if command is valid
  112. if len(words) != 4:
  113. if (len(words) < 4):
  114. return await message.channel.send("Usage: {} delete **{}**/**{}** **username**".format(globals.prefix, globals.SERVICE_MAL, globals.SERVICE_ANILIST))
  115. return await message.channel.send("Too many arguments! You have to specify only one username.")
  116. try:
  117. service = utils.Service.from_str(words[2])
  118. except NotImplementedError:
  119. return await message.channel.send('Incorrect service. Use **"{}"** or **"{}"** for example'.format(globals.SERVICE_MAL, globals.SERVICE_ANILIST))
  120. user = words[3]
  121. server_id = str(message.guild.id)
  122. user_servers = utils.get_user_servers(user, service)
  123. # If user is not present in the database
  124. if user_servers is None:
  125. return await message.channel.send("The user **" + user + "** is not in our database for this server!")
  126. # Else if present, update the servers for this user
  127. srv_string = utils.remove_server_from_servers(server_id, user_servers)
  128. if srv_string is None: # Server not present in the user's servers
  129. return await message.channel.send("The user **" + user + "** is not in our database for this server!")
  130. if srv_string == "":
  131. utils.delete_user_from_db(user, service)
  132. else:
  133. utils.update_user_servers_db(user, service, srv_string)
  134. return await message.channel.send("**" + user + "** deleted from the database for this server.")
  135. async def info_cmd(message, words):
  136. ''' Processes the command "info" and sends a message '''
  137. # Get filters if available
  138. filters = []
  139. if (len(words) >= 3): # If filters are specified
  140. filters = get_service_filters_list(words[2])
  141. server = message.guild
  142. if utils.is_server_in_db(server.id) == False:
  143. await message.channel.send("The server **{}** is not in our database.".format(server))
  144. else:
  145. users = utils.get_users()
  146. channels = utils.get_channels(server.id)
  147. if channels is None:
  148. await message.channel.send("No channel assigned for this bot on this server.")
  149. else:
  150. await message.channel.send(build_info_cmd_message(users, server, channels, filters))
  151. async def ping_cmd(message, channel):
  152. ''' Responds to ping command '''
  153. messageTimestamp = message.created_at
  154. currentTimestamp = datetime.datetime.utcnow()
  155. delta = round((currentTimestamp - messageTimestamp).total_seconds() * 1000)
  156. await channel.send("pong (" + str(delta) + "ms)")
  157. async def about_cmd(channel):
  158. ''' Responds to about command with a brief description of this bot '''
  159. embed = discord.Embed(title="***MyAnimeBot Commands***", colour=0xEED000)
  160. embed.title = "MyAnimeBot version {} by Penta & lulu".format(globals.VERSION)
  161. embed.colour = 0xEED000
  162. embed.description = """MyAnimeBot checks MyAnimeList and Anilist profiles for specified users, and send a message for every new activities found.
  163. More help with the **{} help** command.
  164. Check our GitHub page for more informations: https://github.com/Penta/MyAnimeBot
  165. """.format(globals.prefix)
  166. embed.set_thumbnail(url=globals.iconBot)
  167. await channel.send(embed=embed)
  168. async def help_cmd(channel):
  169. ''' Responds to help command '''
  170. embed = discord.Embed(title="***MyAnimeBot Commands***", colour=0xEED000)
  171. embed.add_field(name="`here`", value="Register this channel. The bot will send new activities on registered channels.")
  172. embed.add_field(name="`stop`", value="Un-register this channel. The bot will now stop sending new activities for this channel.")
  173. embed.add_field(name="`info [mal|ani]`", value="Get the registered users for this server. Users can be filtered by specifying a service.")
  174. embed.add_field(name="`add {mal|ani} <user>`", value="Register a user for a specific service.\nEx: `add mal MyUser`")
  175. embed.add_field(name="`delete {mal|ani} <user>`", value="Remove a user for a specific service.\nEx: `delete ani MyUser`")
  176. embed.add_field(name="`role <@discord_role>`", value="Specify a role that is able to manage the bot.\nEx: `role @Moderator`, `role @everyone`")
  177. embed.add_field(name="`top`", value="Show statistics for this server.")
  178. embed.add_field(name="`ping`", value="Ping the bot.")
  179. embed.add_field(name="`about`", value="Get some information about this bot")
  180. await channel.send(embed=embed)