def _make_install_cog_func( cogs: List[CogItem], repo_list: Dict[str, RepoItem] ) -> Callable[[ commands.Context, Union[List[str], List[discord.Embed]], Dict[Any, Callable[..., Awaitable[Any]]], discord.Message, int, float, str, ], Awaitable[Any], ]: async def install_cog( ctx: commands.Context, pages: Union[List[str], List[discord.Embed]], controls: Dict[Any, Callable[..., Awaitable[Any]]], message: discord.Message, page: int, timeout: float, emoji: str, ) -> Any: cog_item = cogs[page] if (repo_item := repo_list.get(cog_item["repo_name"])) is None: await ctx.send("Error: The repo for this cog is unknown.") return menu(ctx, pages, controls, message, page, timeout) downloader = cast(Optional[Downloader], ctx.bot.get_cog("Downloader")) if downloader is None: await ctx.send("Error: Downloader is not loaded.") return menu(ctx, pages, controls, message, page, timeout) url = repo_item["repo_url"] if (repo := get_repo_by_url(downloader, url)) is None: msg = await ctx.send( "Error: Repository with this URL couldn't have been found.\n" "Do you want to add it?") start_adding_reactions(msg, ReactionPredicate.YES_OR_NO_EMOJIS) pred = ReactionPredicate.yes_or_no(msg, ctx.author) await ctx.bot.wait_for("reaction_add", check=pred) result = cast(bool, pred.result) if not result: return menu(ctx, pages, controls, message, page, timeout) command = downloader._repo_add fake_context = await get_fake_context(ctx, command) branch = branch if (branch := repo_item["branch"]) != "-" else None await command(fake_context, repo_item["repo_name"], url, branch) if (repo := get_repo_by_url(downloader, url)) is None: await ctx.send( "Error: I couldn't find the repo after adding it to Downloader." ) return menu(ctx, pages, controls, message, page, timeout)
async def all(self, ctx: commands.Context): """List all commands and how many time they have been used.""" message = "\n".join("- {cmd}: Used {count} time.".format( cmd=inline(d[0]), count=d[1]["count"]) for d in sorted( self.commands.items(), key=lambda infos: infos[1]["count"], reverse=True, )) embeds = [] embed_base = discord.Embed( color=await ctx.embed_color(), title="All commands usage since last reboot:") embed_base.set_footer( text="Requested by {author}".format(author=ctx.author.name), icon_url=ctx.author.avatar_url, ) for text in pagify(message): again_embed = embed_base.copy() again_embed.description = text embeds.append(again_embed) if len(embeds) > 1: self.bot.loop.create_task( menu(ctx, embeds, DEFAULT_CONTROLS, timeout=300)) else: await ctx.send(embed=embeds[0])
async def embed_convert_error(ctx: commands.Context, error_type: str, error: Exception): embed = discord.Embed( color=await ctx.embed_color(), title=f"{error_type}: `{type(error).__name__}`", description=f"```py\n{error}\n```", ) embed.set_footer( text=f"Use `{ctx.prefix}help {ctx.command.qualified_name}` to see an example" ) asyncio.create_task(menus.menu(ctx, [embed], {"❌": menus.close_menu})) raise CheckFailure
async def install_cog( ctx: commands.Context, pages: Union[List[str], List[discord.Embed]], controls: Dict[Any, Callable[..., Awaitable[Any]]], message: discord.Message, page: int, timeout: float, emoji: str, ) -> Any: cog_item = cogs[page] if (repo_item := repo_list.get(cog_item["repo_name"])) is None: await ctx.send("Error: The repo for this cog is unknown.") return menu(ctx, pages, controls, message, page, timeout)
async def embed_convert_error(self, ctx: commands.Context, error_type: str, error: Exception): embed = discord.Embed( color=await ctx.embed_color(), title=error_type, description=f"```py\n{error}\n```", ) embed.set_footer( text= f"Use `{ctx.prefix}help {ctx.command.qualified_name}` to see an example" ) emoji = ctx.bot.get_emoji(736038541364297738) or "❌" asyncio.create_task(menus.menu(ctx, [embed], {emoji: menus.close_menu})) raise CheckFailure
async def lyrics(self, ctx: commands.Context, *, song_name: Optional[str]): """Return the lyrics of a given music/song name or running music. This command can also find out the music you're actually listening to. Powered by KSoft.Si. """ music = await self.determine_music_source(ctx, song_name) if not music and not song_name: await ctx.send_help() return try: client = await self.obtain_client() except AttributeError: await ctx.send( "Not key for KSoft.Si has been set, ask owner to add a key.") return try: music_lyrics = await client.music.lyrics(music) except ksoftapi.NoResults: await ctx.send("No lyrics were found for your music.") return except ksoftapi.APIError as e: await ctx.send("The API returned an unknown error: {error}".format( error=inline(str(e)))) return except ksoftapi.Forbidden: await ctx.send("Request forbidden by the API.") return except KeyError: await ctx.send( "The set API key seem to be wrong. Please contact the bot owner." ) return music = await self.get_song(ctx, music_lyrics, bool(song_name)) if music is None: return embeds = await self.make_embed(music, ctx) if len(embeds) > 1: create_task( menu(ctx, embeds, DEFAULT_CONTROLS, timeout=600)) # No await since max_concurrency is there else: await ctx.send(embed=embeds[0])
def construct_menu( ctx: commands.Context, pages: Union[List[str], List[discord.Embed]], cogs: List[CogItem], repo_list: Dict[str, RepoItem], *, allow_install: bool = False, ) -> Awaitable[Any]: if allow_install: controls = { **DEFAULT_CONTROLS, DOWNWARDS_ARROW: _make_install_cog_func(cogs, repo_list), } else: # Red isn't typed that well (+ this is recursive type), # and I don't want to deal with this controls = DEFAULT_CONTROLS # type: ignore[assignment] return menu(ctx, pages, controls)
async def page_logic(self, ctx: commands.Context, dictionary: dict, item: str, field_num: int = 15) -> None: """Convert a dictionary into a pagified embed""" embeds = [] count = 0 title = item embed = Embed.create(self, ctx=ctx, title=title, thumbnail=ctx.guild.icon_url) if len(dictionary.keys()) > field_num: for key, value in dictionary.items(): if count == field_num - 1: embed.add_field(name=key, value=value, inline=True) embeds.append(embed) embed = Embed.create(self, ctx=ctx, title=title, thumbnail=ctx.guild.icon_url) count = 0 else: embed.add_field(name=key, value=value, inline=True) count += 1 else: embeds.append(embed) else: for key, value in dictionary.items(): embed.add_field(name=key, value=value, inline=True) embeds.append(embed) msg = await ctx.send(embed=embeds[0]) control = menus.DEFAULT_CONTROLS if len(embeds) > 1 else { "\N{CROSS MARK}": menus.close_menu } asyncio.create_task(menus.menu(ctx, embeds, control, message=msg)) menus.start_adding_reactions(msg, control.keys())
async def lyrics(self, ctx: commands.Context, *, song_name: str): """Return the lyrics of a given music/song name. Powered by KSoft.Si. """ song_name = BOT_SONG_RE.sub("", song_name) try: client = await self.obtain_client() except AttributeError: await ctx.send("Not key for KSoft.Si has been set, ask owner to add a key.") return try: music_lyrics = await client.music.lyrics(song_name) except ksoftapi.NoResults: await ctx.send("No lyrics were found for your music.") return except ksoftapi.APIError as e: await ctx.send( "The API returned an unknown error: {error}".format(error=inline(str(e))) ) return except ksoftapi.Forbidden: await ctx.send("Request forbidden by the API.") return except KeyError: await ctx.send("The set API key seem to be wrong. Please contact the bot owner.") return message, available_musics = await self._title_choose(music_lyrics) bot_message = await ctx.maybe_send_embed(message) predicator = MessagePredicate.less(10, ctx) try: user_message = await self.bot.wait_for("message", check=predicator, timeout=60) await bot_message.delete() except Te: await ctx.send("Rude.") await bot_message.delete() return chosen_music = user_message.content if chosen_music not in available_musics: await ctx.send( "I was unable to find the corresponding music in the available music list." ) return music = available_musics[chosen_music] embeds = [] color = await ctx.embed_color() for text in pagify(music.lyrics): embed = discord.Embed(color=color, title=music.name, description=None) embed.set_thumbnail( url=music.album_art if str(music.album_art) != "https://cdn.ksoft.si/images/Logo1024%20-%20W.png" else discord.Embed.Empty ) embed.set_footer(text="Powered by KSoft.Si.", icon_url=ctx.author.avatar_url) embed.description = text embeds.append(embed) if len(embeds) > 1: create_task( menu(ctx, embeds, DEFAULT_CONTROLS, timeout=600) ) # No await since max_concurrency is here else: await ctx.send(embed=embeds[0])
return menu(ctx, pages, controls, message, page, timeout) command = downloader._repo_add fake_context = await get_fake_context(ctx, command) branch = branch if (branch := repo_item["branch"]) != "-" else None await command(fake_context, repo_item["repo_name"], url, branch) if (repo := get_repo_by_url(downloader, url)) is None: await ctx.send( "Error: I couldn't find the repo after adding it to Downloader." ) return menu(ctx, pages, controls, message, page, timeout) await downloader._cog_install(ctx, repo, cog_item["name"]) return menu(ctx, pages, controls, message, page, timeout) return install_cog def construct_menu( ctx: commands.Context, pages: Union[List[str], List[discord.Embed]], cogs: List[CogItem], repo_list: Dict[str, RepoItem], *, allow_install: bool = False, ) -> Awaitable[Any]: if allow_install: controls = { **DEFAULT_CONTROLS,
async def update_profile(bot, user_data: dict, author: discord.User): msg = await author.send( "What country are you from (Enter the number next to the country)?") country_data = WorldData.get("country", {}) validcountries = sorted( list(value.get("name") for _, value in country_data.items())) desc = "" valid_county_list = [] for index, value in enumerate(validcountries, start=1): desc += f"{index}. {value}\n" valid_county_list.append(str(index)) pages = [ box(page, lang="md") for page in list(pagify(desc, shorten_by=20)) ] ctx = namedtuple("Context", "author me bot send channel") new_ctx = ctx(author, bot.user, bot, author.send, msg.channel) menu_task = asyncio.create_task( menu(new_ctx, pages, DEFAULT_CONTROLS, timeout=180)) country = None pred_check = MessagePredicate.contained_in(valid_county_list, ctx=new_ctx) while not country: with contextlib.suppress(asyncio.TimeoutError): await bot.wait_for("message", timeout=30.0, check=pred_check) country = (valid_county_list[pred_check.result] if pred_check.result is not None else None) with contextlib.suppress(Exception): menu_task.cancel() user_data["country"] = validcountries[int(country) - 1] cached_country = user_data["country"].lower().strip() if cached_country: country_data = WorldData.get("country", {}) region = country_data.get(cached_country, {}).get("region") country_timezones = country_data.get(cached_country, {}).get("timezones") user_data["subzone"] = country_data.get(cached_country, {}).get("subregion") else: region = None country_timezones = None continent_data = sorted(CONTINENT_DATA.values()) if not region: await author.send("Which zone are you from?") embed = discord.Embed(title="Pick a number that matches your zone") desc = "" valid_continent_list = [] for index, value in enumerate(continent_data, start=1): desc += f"{index}. {value.title()}\n" valid_continent_list.append(str(index)) embed.description = box(desc, lang="md") await author.send(embed=embed) zone = None pred_check = MessagePredicate.contained_in(valid_continent_list, ctx=new_ctx) while not zone: with contextlib.suppress(asyncio.TimeoutError): await bot.wait_for("message", timeout=30.0, check=pred_check) zone = (valid_continent_list[pred_check.result] if pred_check.result is not None else None) user_data["zone"] = continent_data[int(zone) - 1] else: user_data["zone"] = country_data.get(cached_country, {}).get("region", None) user_data["language"] = None if country_timezones and len(country_timezones) > 1: country_timezones_dict = { str(i): key for i, key in enumerate(country_timezones, start=1) } country_timezones = sorted(country_timezones_dict.values()) await author.send( "There are multiple timezone for your country, please pick the one that match yours?" ) embed = discord.Embed(title="Pick a number that matches your timezone") desc = "" valid_timezone_list = [] for index, value in enumerate(country_timezones, start=1): desc += f"{index}. {value.upper()}\n" valid_timezone_list.append(str(index)) embed.description = box(desc, lang="md") await author.send(embed=embed) timezone = None pred_check = MessagePredicate.contained_in(valid_timezone_list, ctx=new_ctx) while not timezone: with contextlib.suppress(asyncio.TimeoutError): await bot.wait_for("message", timeout=30.0, check=pred_check) timezone = (valid_timezone_list[pred_check.result] if pred_check.result is not None else None) user_data["timezone"] = country_timezones[int(timezone) - 1] elif country_timezones and len(country_timezones) == 1: user_data["timezone"] = country_timezones[0] return user_data
async def awbadge(self, ctx, tier: str = None, group: int = None): """Get alliance war badges.""" if group is not None and group >= 1 and group < 4: group_num = group - 1 # This is to make sure that it will work with the urls tiers = { "master": [ "https://media.discordapp.net/attachments/401476363707744257/738083791654092940/47EFB6D4D1380ABD2C40D2C7B0533A29245F7955.png", "https://media.discordapp.net/attachments/401476363707744257/738083791113027654/650E29ADB8C5C382FF5A358113B2C02B8EADA415.png", "https://media.discordapp.net/attachments/401476363707744257/738083791440052294/08BA0A081A9D56E35E60E3FD61FAB7ED9A10CD00.png" ], "platinum": [ "https://media.discordapp.net/attachments/401476363707744257/738083790718631937/E78E2BAF9B0C9BA6C7FE45BE726FFB0B0B0CACFD.png", "https://media.discordapp.net/attachments/401476363707744257/738083790362116116/487EA26A1BA0F2C2848E7C87F10430BD218C2178.png", "https://media.discordapp.net/attachments/401476363707744257/738083790559117352/0ED8BD10441C6D086AEB7BBA5271269F46E009D1.png" ], "gold": [ "https://media.discordapp.net/attachments/401476363707744257/738083790131298375/76BC21BF523A415866D19814BD8AF4BE16EF30A9.png", "https://media.discordapp.net/attachments/401476363707744257/738083998462509096/8CD52FEB7540016B6ABA1EC67B9F1777E3C29878.png", "https://media.discordapp.net/attachments/401476363707744257/738084001926873098/3A9A8FDA006D0BE225242AAA5909021CD52BCFB3.png" ], "silver": [ "https://media.discordapp.net/attachments/401476363707744257/738084001465499789/4B389D377A94EDA747B38DF640C0B33A3A3F61AE.png", "https://media.discordapp.net/attachments/401476363707744257/738084001465499789/4B389D377A94EDA747B38DF640C0B33A3A3F61AE.png", "https://media.discordapp.net/attachments/401476363707744257/738083994612006914/5302FA8FA04735224847C8BBF82D1D54C8567B9C.png" ], "bronze": [ "https://media.discordapp.net/attachments/401476363707744257/738083995211792404/719AC2C2AB5833D815C899DAF9ADB7CF11819CBA.png", "https://media.discordapp.net/attachments/401476363707744257/738083993043337276/E636A90C3F0DFFDAED0176D972AA0C73F3E40FF8.png", "https://media.discordapp.net/attachments/401476363707744257/738083997866786876/5B06D509847E0FA1405A50021486C1A5D8C6F9B2.png" ], "stone": [ "https://media.discordapp.net/attachments/401476363707744257/738083996054978730/9AC92A2FDC2996C346125296356C664373147F2F.png", "https://media.discordapp.net/attachments/401476363707744257/738083993681002586/BF3D13EACC9F44216E754884AA183185761C84CF.png", "https://media.discordapp.net/attachments/401476363707744257/738084098857238670/EA938C0B0C2AE3E6DB91514F5F8768C4F033D373.png" ] } tier = tier.lower() if tier is not None else None if tier is None or tier not in tiers: embed = Embed.create( self, ctx, title="Alliance War Badge Tiers", description="Please choose one of the tiers below :arrow_down:\nSyntax: `,awbadge <tier>`" ) normal = "\n".join([t.capitalize() for t in tiers.keys()]) embed.add_field( # Unfortunatly I have to do this to make sure that participation gets in the list :/ name="Badges", value="{}\nParticipation".format(normal) ) normal = "\n".join(tiers) return await ctx.send(embed=embed) if tier == "participation": embed = Embed.create( self, ctx, title="Participation", image="https://media.discordapp.net/attachments/401476363707744257/738083790886535228/DA7D39277836A9CF1B39A68D37EAF99999B366C7.png" ) return await ctx.send(embed=embed) if group is None: embeds = [] for i in range(3): embed = Embed.create( self, ctx, title="{} Badges".format(tier.capitalize()), image=tiers[tier][i] ) embeds.append(embed) msg = await ctx.send(embed=embeds[0]) control = menus.DEFAULT_CONTROLS if len(embeds) > 1 else { "\N{CROSS MARK}": menus.close_menu } asyncio.create_task(menus.menu(ctx, embeds, control, message=msg)) menus.start_adding_reactions(msg, control.keys()) else: embed = Embed.create( self, ctx, title="{} Badge".format(tier.capitalize()), description="{} {}".format(tier.capitalize(), group), image=tiers[tier][group_num] ) await ctx.send(embed=embed)