async def on_guild_join(guild): #Creates new settings entry for guild Sudo.server_settings_check(hex(guild.id), bot) Sudo.save_configs(bot) owner = await bot.fetch_user(guild.owner_id) dm = await owner.create_dm() try: embed = Embed( title=f"Search.io was added to your server: '{guild.name}'.", description=f""" Search.io is a bot that searches through multiple search engines/APIs. The activation command is `&`, and a list of various commands can be found using `&help`. • A list of admin commands can be found by using `&help sudo`. These commands may need ID numbers, which requires Developer Mode. • To turn on Developer Mode, go to Settings > Appearances > Advanced > Developer Mode. Then right click on users, roles, channels, or guilds to copy their ID. • Guild-specific settings can be accessed with `&config` • As a start, it is suggested to designate an administrator role that can use Search.io's sudo commands. Do `&config adminrole [roleID]` to designate an admin role. • You can change the command prefix with `&config prefix [character]` • You can also block or unblock specific commands with `&config [command]` • It is also suggested to turn on Safe Search, if needed. Do `&config safesearch on`. • If you need to block a specific user from using Search.io, do `&sudo blacklist [userID]`. • Unblock with `&sudo whitelist [userID]` If you have any problems with Search.io, join the help server: https://discord.gg/YB8VGYMZSQ""" ) await dm.send(embed=embed) except discord_error.Forbidden: pass finally: return
async def on_guild_join(guild): #Reads settings of server Sudo.settingsCheck(serverSettings, guild.id) owner = await bot.fetch_user(guild.owner_id) dm = await owner.create_dm() appInfo = await bot.application_info() embed = discord.Embed(title=f"Search.io was added to your server: '{guild.name}'.", description = f""" Search.io is a bot that searches through multiple search engines/APIs. The activation command is '&', and a list of various commands can be found using '&help'. A list of admin commands can be found by using '&help sudo'. These commands may need ID numbers, which requires Developer Mode. To turn on Developer Mode, go to Settings > Appearances > Advanced > Developer Mode. Then right click on users, roles, channels, or guilds to copy their ID. If you need to block a specific user from using Search.io, do '&sudo blacklist [userID]'. Unblock with '&sudo whitelist [userID]' Guild-specific settings can be accessed with '&config' As a start, it is suggested to designate an administrator role that can use Search.io's sudo commands. Do '&config adminrole [roleID]' to designate an admin role. You can change the command prefix with '&config prefix [character]' You can also block or unblock specific commands with '&config [command]' It is also suggested to turn on Safe Search, if needed. Do '&config safesearch'. The default is off. If you have any problems with Search.io, DM {str(appInfo.owner)}""") await dm.send(embed=embed) return
async def on_connect(): t0 = time() DiscordComponents(bot) bot.load_extension('src.cogs.search_engine_cog') bot.load_extension('src.cogs.administration_cog') bot.load_extension('src.cogs.administration_slashcog') bot.load_extension('src.cogs.search_engine_slashcog') auto_save.start() cache_clear.start() #add new servers to settings for servers in bot.guilds: bot.serverSettings = Sudo.server_settings_check(servers.id, bot) #sets bot globals bot.devmode = False #remove old servers from settings delete_queue = [] guild_list = [g.id for g in bot.guilds] for keys in bot.serverSettings.keys(): if int(keys, 0) not in guild_list: delete_queue.append(keys) for keys in delete_queue: del bot.serverSettings[keys] Sudo.save_configs(bot) with open("logs.csv", "r", newline='', encoding='utf-8-sig') as file: lines = [ dict(row) for row in DictReader(file) if datetime.now(timezone.utc) - datetime.fromisoformat(row["Time"]) < timedelta(weeks=8) ] with open("logs.csv", "w", newline='', encoding='utf-8-sig') as file: logFieldnames = [ "Time", "Guild", "User", "User_Plaintext", "Command", "Args" ] writer = DictWriter(file, fieldnames=logFieldnames, extrasaction='ignore') writer.writeheader() writer.writerows(lines) bot.session = ClientSession() bot.botuser = await bot.application_info() await bot.change_presence(activity=Activity( type=ActivityType.listening, name="command prefix '&'")) t1 = time() print(f"Bot alive. Took {t1-t0:.3f}s") return
async def config(self, ctx, *args): args = list(args) global serverSettings command = Sudo(bot, ctx, serverSettings) if Sudo.isSudoer(bot, ctx, serverSettings) == True: await command.config(args) else: await command.config([]) with open('serverSettings.json', 'r') as data: serverSettings = json.load(data, object_hook=lambda d: {int(k) if k.isdigit() else k: v for k, v in d.items()}) return
async def sudo(self, ctx, *args): global serverSettings args = list(args) if Sudo.isSudoer(bot, ctx, serverSettings) == False: await ctx.send(f"{ctx.author} is not in the sudoers file. This incident will be reported.") Log.appendToLog(ctx, 'sudo', 'unauthorised') else: Log.appendToLog(ctx, "sudo", ' '.join(args).strip()) command = Sudo(bot, ctx, serverSettings) await command.sudo(args) with open('serverSettings.json', 'r') as data: serverSettings = json.load(data, object_hook=lambda d: {int(k) if k.isdigit() else k: v for k, v in d.items()}) return
async def sudo(self, ctx, *args): if Sudo.is_sudoer(self.bot, ctx): Log.append_to_log(ctx, None, args) command = Sudo(self.bot, ctx) self.bot.serverSettings, self.bot.userSettings = await command.sudo( list(args)) Sudo.save_configs(self.bot) else: await ctx.send( f"`{ctx.author}` is not in the sudoers file. This incident will be reported." ) Log.append_to_log(ctx, None, 'unauthorised') return
async def config(self, ctx, *args): args = list(args) command = Sudo(self.bot, ctx) if len(args) > 0: localSetting = args[0] in ['locale', 'alias'] else: localSetting = False if Sudo.is_sudoer(self.bot, ctx) or localSetting: self.bot.serverSettings, self.bot.userSettings = await command.config( args) else: self.bot.serverSettings, self.bot.userSettings = await command.config( []) Sudo.save_configs(self.bot) Log.append_to_log(ctx)
async def cog_before_invoke(self, ctx): if Sudo.is_authorized_command(self.bot, ctx): old_userSettings = deepcopy(self.bot.userSettings) self.bot.userSettings = Sudo.user_settings_check( self.bot.userSettings, ctx.author.id) if old_userSettings != self.bot.userSettings: Sudo.save_configs(self.bot) #Leveling system self.bot.userSettings[ctx.author.id]['level']['xp'] += 1 if self.bot.userSettings[ ctx.author.id]['level']['xp'] >= self.bot.userSettings[ ctx.author.id]['level']['rank'] * 10: self.bot.userSettings[ctx.author.id]['level']['xp'] = 0 self.bot.userSettings[ctx.author.id]['level']['rank'] += 1 Sudo.save_configs(self.bot) await ctx.send(embed=Embed( description= f"Congratulations {ctx.author}, you are now level {self.bot.userSettings[ctx.author.id]['level']['rank']}" )) # if ctx.command.name == 's' and self.bot.userSettings[ctx.author.id]['searchAlias'] is not None: # Log.append_to_log(ctx, self.bot.userSettings[ctx.author.id]['searchAlias']) # elif ctx.command.name == 's': # Log.append_to_log(ctx, 's', 'Not set') # else: Log.append_to_log(ctx) return
async def on_connect(): global serverSettings await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name="command prefix '&'")) appInfo = await bot.application_info() bot.owner_id = appInfo.owner.id for servers in bot.guilds: serverSettings = Sudo.settingsCheck(serverSettings, servers.id) with open('serverSettings.json', 'w') as data: data.write(json.dumps(serverSettings, indent=4)) return
async def finance(self, ctx, *args): args = list(args) if args[0] == 'help' or len(args) == 1: if len(args) == 1: helpmessage = Embed(title='finance', description=ctx.command.help) elif args[1] == 'stock': helpmessage = Embed(title='Stock', description=""" finance stock [ticker] [range] [interval] [display] [moving average values] Ex: finance stock AAPL 1y 1d candle 2 3 5 Example creates a candle chart displaying 1 year of AAPL with 1 day data points and MAV lines of 2, 3, and 5 days. """) helpmessage.add_field(name='ticker', value='Symbol') helpmessage.add_field(name='range', value='Length of time for data') helpmessage.add_field(name='interval', value='Time between data points') helpmessage.add_field(name='display', value='candle OR line') helpmessage.add_field( name='moving average values', value='number of days for a simple moving average line') await ctx.send(embed=helpmessage) try: resp = await self.bot.wait_for( "button_click", check=lambda b_ctx: Sudo.pageTurnCheck(bot=self.bot, ctx=ctx, button_ctx=b_ctx, message=helpmessage ), timeout=60) if str(resp.custom_id) == "🗑️": await helpmessage.delete() return except TimeoutError: await helpmessage.edit(components=[]) return else: await self.genericSearch(ctx, FinancialSearch, args)
async def __call__(self): UserCancel = KeyboardInterrupt def search_pages(result_) -> discord.Embed: return discord.Embed( title=f"Titles matching '{self.query}'", description="\n".join([ f"[{index_}]: {value.title}" for index_, value in enumerate(result_) ]), ) try: errorMessage = None search = AnimeSearch(self.query) while 1: result = [ [anime for anime in search.results][x:x + 10] for x in range(0, len([anime for anime in search.results]), 10) ] embeds = list(map(search_pages, result)) cur_page = 0 for index, item in enumerate(embeds): item.set_footer( text= f"Please choose option or cancel\nPage {index+1}/{len(embeds)}" ) if len(embeds) > 1: emojis = ["🗑️", "◀️", "▶️"] else: emojis = ["🗑️"] await self.message.edit(content='', embed=embeds[cur_page % len(embeds)], components=[[ Button(style=ButtonStyle.blue, label=e, custom_id=e) for e in emojis ]]) while 1: try: emojitask = asyncio.create_task( self.bot.wait_for( "button_click", check=lambda b_ctx: Sudo.pageTurnCheck( bot=self.bot, ctx=self.ctx, button_ctx=b_ctx, message=self.message), timeout=60, )) responsetask = asyncio.create_task( self.bot.wait_for( "message", check=lambda m: m.author == self.ctx.author, timeout=30, )) waiting = [emojitask, responsetask] done, waiting = await asyncio.wait( waiting, return_when=asyncio.FIRST_COMPLETED ) # 30 seconds wait either reply or react if emojitask in done: emojitask = emojitask.result() if str(emojitask.custom_id) == "🗑️": await self.message.delete() return elif str(emojitask.custom_id) == "◀️": cur_page -= 1 elif str(emojitask.custom_id) == "▶️": cur_page += 1 await emojitask.respond(type=7, content='', embed=embeds[cur_page % len(embeds)]) elif responsetask in done: try: emojitask.cancel() input = responsetask.result() await input.delete() if input.content.lower() == "cancel": raise UserCancel input = int(input.content) anime_item = result[cur_page][input] if errorMessage is not None: await errorMessage.delete() embed = discord.Embed( title=f"{anime_item.title}", description=anime_item.synopsis, url=anime_item.url, ) # Myanimelist data embed.add_field( name="MyAnimeListID", value=str(anime_item.mal_id), inline=True, ) embed.add_field( name="Rating", value=str(anime_item.score), inline=True, ) embed.add_field( name="Episodes", value=str(anime_item.episodes), inline=True, ) embed.set_thumbnail(url=anime_item.image_url) embed.set_footer( text=f"Requested by {self.ctx.author}") Log.append_to_log( self.ctx, f"{self.ctx.command} result", anime_item.title) await self.message.edit( embed=embed, components=[ Button(style=ButtonStyle.blue, label="🗑️", custom_id="🗑️") ]) await self.bot.wait_for( "button_click", check=lambda button_ctx: Sudo. pageTurnCheck(bot=self.bot, ctx=self.ctx, button_ctx=button_ctx, message=self.message), timeout=60, ) return except (ValueError, IndexError): errorMessage = await self.ctx.send( content= "Invalid choice. Please choose a number between 0-9 or cancel" ) continue except asyncio.TimeoutError: await self.message.edit(components=[]) return except UserCancel: await self.message.delete() except asyncio.TimeoutError: await self.message.delete() except (asyncio.CancelledError, discord.errors.NotFound): pass except Exception: await self.message.delete() raise except Exception as e: await error_handler(self.bot, self.ctx, e, self.query) finally: return
async def cog_before_invoke(self, ctx): self.bot.userSettings = Sudo.user_settings_check( self.bot.userSettings, ctx.author.id) Sudo.save_configs(self.bot) return
async def genericSearch(self, ctx, searchObject, query: str, optionals: str = None): if Sudo.is_authorized_command(self.bot, ctx): old_userSettings = deepcopy(self.bot.userSettings) self.bot.userSettings = Sudo.user_settings_check( self.bot.userSettings, ctx.author.id) if old_userSettings != self.bot.userSettings: Sudo.save_configs(self.bot) #Leveling system self.bot.userSettings[ctx.author.id]['level']['xp'] += 1 if self.bot.userSettings[ ctx.author.id]['level']['xp'] >= self.bot.userSettings[ ctx.author.id]['level']['rank'] * 10: self.bot.userSettings[ctx.author.id]['level']['xp'] = 0 self.bot.userSettings[ctx.author.id]['level']['rank'] += 1 Sudo.save_configs(self.bot) await ctx.send(embed=Embed( description= f"Congratulations {ctx.author}, you are now level {self.bot.userSettings[ctx.author.id]['level']['rank']}" )) # if ctx.command.name == 's' and self.bot.userSettings[ctx.author.id]['searchAlias'] is not None: # Log.append_to_log(ctx, self.bot.userSettings[ctx.author.id]['searchAlias']) # elif ctx.command.name == 's': # Log.append_to_log(ctx, 's', 'Not set') # else: Log.append_to_log(ctx) #allows users to edit their search query after results are returned continueLoop = True while continueLoop: try: message = await ctx.send(content=get_loading_message()) messageEdit = create_task( self.bot.wait_for('message_edit', check=lambda var, m: m.author == ctx. author and m == ctx.message)) search = create_task( searchObject( bot=self.bot, ctx=ctx, server_settings=self.bot.serverSettings, user_settings=self.bot.userSettings, message=message, args=optionals.split(' ') if optionals is not None else [], query=query, )()) #checks for message edit waiting = [messageEdit, search] done, waiting = await wait( waiting, return_when=asyncio.FIRST_COMPLETED) if messageEdit in done: #if the message is edited, the search is cancelled, message deleted, and command is restarted if type(messageEdit.exception()) == TimeoutError: raise TimeoutError await message.delete() messageEdit.cancel() search.cancel() messageEdit = messageEdit.result() userquery = messageEdit[1].content.replace( f'{Sudo.print_prefix(self.bot.serverSettings, ctx)}{ctx.invoked_with} ', '') #finds the new user query continue else: raise TimeoutError except TimeoutError: #after a minute, everything cancels await message.edit(components=[]) messageEdit.cancel() search.cancel() continueLoop = False return except Exception as e: await error_handler(self.bot, ctx, e, userquery) return
async def auto_save(): Sudo.save_configs(bot) return
async def help(ctx, *args): try: def check(reaction, user): return user == ctx.author and str(reaction.emoji) in ["🗑️"] commandPrefix = Sudo.print_prefix(bot.serverSettings, ctx) searchEngineCog = dict(bot.cogs)['Search Engines'] adminCog = dict(bot.cogs)['Administration'] maxAdminCommandStrLength = len( max([command.name for command in adminCog.get_commands()], key=len)) args = list(args) embed = Embed( title="SearchIO", description= "Search.io is a bot that searches through multiple search engines/APIs.\nIt is developed by ACEslava#1984, K1NG#6219, and Nanu#3294" ) embed.add_field( name="Administration", inline=False, value="\n".join([ f'`{command.name:>{maxAdminCommandStrLength}}:` {command.brief}' for command in adminCog.get_commands() ])) embed.add_field( name="Search Engines", inline=False, value='\n'.join([ f"`{command.name:>10}:` {command.brief}" for command in searchEngineCog.get_commands() if command.enabled is True and bot.serverSettings[hex( ctx.guild.id)]['searchEngines'][command.name] is True ])) embed.set_footer( text=f"Do {commandPrefix}help [command] for more information") if args: try: command = getattr(searchEngineCog, args[0].lower()) except AttributeError: try: command = getattr(adminCog, args[0].lower()) except AttributeError: command = None if command is not None: embed = Embed(title=command.name, description=f""" {command.help} Usage: ```{command.usage}``` {'Optionals:```'+command.description+'```' if command.description != '' else ''}""" ) embed.set_footer(text=f"Requested by {ctx.author}") helpMessage = await ctx.send(embed=embed) try: await helpMessage.add_reaction('🗑️') reaction, _ = await bot.wait_for("reaction_add", check=check, timeout=60) if str(reaction.emoji) == '🗑️': await helpMessage.delete() return except TimeoutError as e: await helpMessage.clear_reactions() else: pass else: invite_link = discord_utils.oauth_url( client_id=bot.botuser.id, permissions=Permissions(4228381776), scopes=['bot', 'applications.commands']) dm = await ctx.author.create_dm() await dm.send(embed=embed) await dm.send('\n'.join([ 'If you have further questions, feel free to join the support server: https://discord.gg/YB8VGYMZSQ', f'Want to add the bot to your server? Use this invite link: {invite_link}' ])) except discord_error.Forbidden: await ctx.send(embed=Embed( description= 'Sorry, I cannot open a DM at this time. Please check your privacy settings' )) except Exception as e: await error_handler(bot, ctx, e) finally: return
async def genericSearch(self, ctx: commands.context, searchObject, args: list) -> None: '''A generic search handler for bot search functions. Args: ctx: discord.commands.context searchObject: function args: list Raises: None Returns: None ''' if Sudo.is_authorized_command(self.bot, ctx): # region args parsing UserCancel = KeyboardInterrupt if not args: #checks if search is empty await ctx.send("Enter search query or cancel" ) #if empty, asks user for search query try: userquery = await self.bot.wait_for( 'message', check=lambda m: m.author == ctx.author, timeout=30) # 30 seconds to reply if userquery.content.lower() == 'cancel': raise UserCancel else: userquery = userquery.content.split('--') except TimeoutError: await ctx.send( f'{ctx.author.mention} Error: You took too long. Aborting' ) #aborts if timeout except UserCancel: await ctx.send('Aborting') return else: userquery = ' '.join([ query.strip() for query in list(args) ]).split('--') #turns multiword search into single string. if len(userquery) > 1: args = userquery[1:] else: args = None userquery = userquery[0] #check if user actually searched something if userquery is None: return #endregion #allows users to edit their search query after results are returned continueLoop = True while continueLoop: try: message = await ctx.send(get_loading_message()) messageEdit = create_task( self.bot.wait_for('message_edit', check=lambda var, m: m.author == ctx. author and m == ctx.message)) search = create_task( searchObject( bot=self.bot, ctx=ctx, server_settings=self.bot.serverSettings, user_settings=self.bot.userSettings, message=message, args=args, query=userquery, )()) #checks for message edit waiting = [messageEdit, search] done, waiting = await wait( waiting, return_when=asyncio.FIRST_COMPLETED) if messageEdit in done: #if the message is edited, the search is cancelled, message deleted, and command is restarted if type(messageEdit.exception()) == TimeoutError: raise TimeoutError await message.delete() messageEdit.cancel() search.cancel() messageEdit = messageEdit.result() userquery = messageEdit[1].content.replace( f'{Sudo.print_prefix(self.bot.serverSettings, ctx)}{ctx.invoked_with} ', '') #finds the new user query continue else: raise TimeoutError except TimeoutError: #after a minute, everything cancels await message.clear_reactions() messageEdit.cancel() search.cancel() continueLoop = False return except Exception as e: await error_handler(self.bot, ctx, e, userquery) return return
async def __call__(self): UserCancel = KeyboardInterrupt if self.args is None: Wikipedia.set_lang("en") elif any("lang" in i for i in self.args): language = self.args[[ idx for idx, s in enumerate(self.args) if "lang" in s ][0]].replace("lang ", "") Wikipedia.set_lang(language) def search_pages(result_) -> discord.Embed: return discord.Embed( title=f"Titles matching '{self.query}'", description="\n".join([ f"[{index_}]: {value}" for index_, value in enumerate(result_) ]), ) try: errorMessage = None result = Wikipedia.search(self.query) while 1: result = [result[x:x + 10] for x in range(0, len(result), 10)] embeds = list(map(search_pages, result)) cur_page = 0 for index, item in enumerate(embeds): item.set_footer( text= f"Please choose option or cancel\nPage {index+1}/{len(embeds)}" ) if len(embeds) > 1: emojis = ["🗑️", "◀️", "▶️"] else: emojis = ["🗑️"] await self.message.edit(content='', embed=embeds[cur_page % len(embeds)], components=[[ Button(style=ButtonStyle.blue, label=e, custom_id=e) for e in emojis ]]) while 1: try: emojitask = asyncio.create_task( self.bot.wait_for( "button_click", check=lambda b_ctx: Sudo.pageTurnCheck( bot=self.bot, ctx=self.ctx, button_ctx=b_ctx, message=self.message), timeout=60, )) responsetask = asyncio.create_task( self.bot.wait_for( "message", check=lambda m: m.author == self.ctx.author, timeout=30, )) waiting = [emojitask, responsetask] done, waiting = await asyncio.wait( waiting, return_when=asyncio.FIRST_COMPLETED ) # 30 seconds wait either reply or react if emojitask in done: emojitask = emojitask.result() if str(emojitask.custom_id) == "🗑️": await self.message.delete() return elif str(emojitask.custom_id) == "◀️": cur_page -= 1 elif str(emojitask.custom_id) == "▶️": cur_page += 1 await emojitask.respond(type=7, content='', embed=embeds[cur_page % len(embeds)]) elif responsetask in done: try: emojitask.cancel() input = responsetask.result() await input.delete() if input.content.lower() == "cancel": raise UserCancel input = int(input.content) if errorMessage is not None: await errorMessage.delete() self.query = result[cur_page][input] page = Wikipedia.WikipediaPage( title=self.query) summary = page.summary[:page.summary. find(". ") + 1] embed = discord.Embed( title= f"Wikipedia Article: {page.original_title}", description=summary, url=page.url, ) # outputs wikipedia article embed.set_footer( text=f"Requested by {self.ctx.author}") await self.message.edit( embed=embed, components=[ Button(style=ButtonStyle.blue, label="🗑️", custom_id="🗑️") ]) await self.bot.wait_for( "button_click", check=lambda button_ctx: Sudo. pageTurnCheck(bot=self.bot, ctx=self.ctx, button_ctx=button_ctx, message=self.message), timeout=60, ) await self.message.delete() return except Wikipedia.DisambiguationError as e: result = str(e).split("\n") result.pop(0) await self.message.edit( content=f"{get_loading_message()}", components=[]) break except (ValueError, IndexError): errorMessage = await self.ctx.send( "Invalid choice. Please choose a number between 0-9 or cancel" ) continue except asyncio.TimeoutError: await self.message.edit(components=[]) return except (UserCancel, asyncio.TimeoutError): await self.message.delete() except Exception: raise except Exception as e: await error_handler(self.bot, self.ctx, e, self.query) finally: return
async def help(ctx, *args): try: def check(reaction, user): return user == ctx.author and str(reaction.emoji) in ["ЁЯЧСя╕П"] commandPrefix = Sudo.printPrefix(ctx) args = list(args) embed = discord.Embed(title="Help", description="Search.io is a bot that searches through multiple search engines/APIs.\nIt is developed by ACEslava#9735, K1NG#6219, and Nanu#3294") embed.add_field(name="Administration", inline=False, value=textwrap.dedent(f"""\ ` sudo:` Various admin commands. Usage: {commandPrefix}sudo [command] [args]. ` logs:` DMs a .csv of personal logs or guild logs if user is a sudoer. Usage: {commandPrefix}log `config:` Views the guild settings. Requires sudo privileges to edit settings """)) embed.add_field(name="Search Engines", inline=False, value=textwrap.dedent(f"""\ {"`wikipedia:` Search through Wikipedia." if serverSettings[ctx.guild.id]['wikipedia'] == True else ''} {"` wikilang:` Lists supported languages for Wikipedia's --lang flag" if serverSettings[ctx.guild.id]['wikipedia'] == True else ''} {"` google:` Search through Google" if serverSettings[ctx.guild.id]['google'] == True else ''} {"` image:` Google's Reverse Image Search with an image URL or image reply" if serverSettings[ctx.guild.id]['google'] == True else ''} {"` scholar:` Search through Google Scholar" if serverSettings[ctx.guild.id]['scholar'] == True else ''} {"` youtube:` Search through Youtube" if serverSettings[ctx.guild.id]['youtube'] == True else ''} {"` anime:` Search through MyAnimeList" if serverSettings[ctx.guild.id]['mal'] == True else ''} {"` xkcd:` Search for XKCD comics" if serverSettings[ctx.guild.id]['xkcd'] == True else ''} """)) embed.set_footer(text=f"Do {commandPrefix}help [command] for more information") if args: if args[0] == 'sudo': embed = discord.Embed(title="Sudo", description=f"Admin commands. Server owner has sudo privilege by default.\nUsage: {commandPrefix}sudo [command] [args]") embed.add_field(name="Commands", inline=False, value= f"""` echo:` Have the bot say something. Args: message Optional flag: --channel [channelID] `blacklist:` Block a user from using the bot. Args: userName OR userID `whitelist:` Unblock a user from using the bot. Args: userName OR userID ` sudoer:` Add a user to the sudo list. Only guild owners can do this. Args: userName OR userID ` unsudoer:` Remove a user from the sudo list. Only guild owners can do this. Args: userName OR userID""") elif args[0] == 'log': embed = discord.Embed(title="Log", description= f"DMs a .csv file of all the logs that the bot has for your username or guild if a sudoer.\nUsage: {commandPrefix}log") elif args[0] == 'config': embed = discord.Embed(title="Guild Configuration", description=f"Views the guild configuration. Only sudoers can edit settings.\nUsage: {commandPrefix}config") elif args[0] == 'wiki': embed = discord.Embed(title="Wikipedia", description=f"Wikipedia search. \nUsage: {commandPrefix}wiki [query] [flags]") embed.add_field(name="Optional Flags", inline=False, value= f"""`--lang [ISO Language Code]:` Specifies a country code to search through Wikipedia. Use {commandPrefix}wikilang to see available codes""") elif args[0] == 'wikilang': embed = discord.Embed(title="WikiLang", description= """Lists Wikipedia's supported wikis in ISO codes. Common language codes are: zh: ф╕нцЦЗ es: Espa├▒ol en: English pt: Portugu├кs hi: рд╣рд┐рдиреНрджреА bn: ржмрж╛ржВрж▓рж╛ ru: ╤А╤Г╤Б╤Б╨║╨╕╨╣""") elif args[0] == 'google': embed = discord.Embed(title="Google", description= f"Google search.\nUsage: {commandPrefix}google [query].\nIf a keyword is detected in [query], a special function will activate") embed.add_field(name="Keywords", inline=False, value= """`translate:` Uses Google Translate API to translate languages. Input automatically detects language unless specified with 'from [language]' Defaults to output English unless specified with 'to [language]' Example Query: translate ┘Е╪▒╪н╪и╪з from arabic to spanish""") elif args[0] == 'image': embed = discord.Embed(title="Google Image", description= f"Uses Google's Reverse Image search to output URLs that contain the image.\nUsage: {commandPrefix}image [imageURL] OR reply to an image in the chat") elif args[0] == 'scholar': embed = discord.Embed(title="GoogleScholar", description= f"Google Scholar search. \nUsage: {commandPrefix}scholar [query] [flags].") embed.add_field(name="Flags", inline=False, value=""" `--author:` Use [query] to search for a specific author. Cannot be used with --cite ` --cite:` Outputs a citation for [query] in BibTex. Cannot be used with --author""") elif args[0] == 'youtube': embed = discord.Embed(title="Youtube", description= f"Searches through Youtube videos.\nUsage: {commandPrefix}youtube [query].") elif args[0] == 'anime': embed = discord.Embed(title="MyAnimeList", description= f"Searches through MyAnimeList\nUsage:{commandPrefix}anime [query]") elif args[0] == 'xkcd': embed = discord.Embed(title="XKCD", description= f"Searches for an XKCD comic\nUsage:{commandPrefix}anime [XKCD Comic #]") else: pass else: pass helpMessage = await ctx.send(embed=embed) try: await helpMessage.add_reaction('ЁЯЧСя╕П') reaction, user = await bot.wait_for("reaction_add", check=check, timeout=60) if str(reaction.emoji) == 'ЁЯЧСя╕П': await helpMessage.delete() return except asyncio.TimeoutError as e: await helpMessage.clear_reactions() finally: return except Exception as e: ErrorHandler(bot, ctx, e, 'help', '')