diff --git a/cogs/anime.py b/cogs/anime.py index 2c878c1f..97d22917 100644 --- a/cogs/anime.py +++ b/cogs/anime.py @@ -1,5 +1,5 @@ # Ensō~Chan - A Multi Purpose Discord Bot That Has Everything Your Server Needs! -# Copyright (C) 2020 Goudham Suresh +# Copyright (C) 2020 Hamothy # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -14,16 +14,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import asyncio import datetime import aiohttp from decouple import config from discord import Embed -from discord.ext import menus from discord.ext.commands import Cog, group, bot_has_permissions, command -from bot.libs.paginator import SimpleMenu +from cogs.libs.paginators import SimpleMenu, MWLMenu my_waifu_list_auth = config('MYWAIFULIST_AUTH') @@ -50,13 +48,10 @@ def store_in_dict(_dict, api): """Store the waifu data in dicts""" # Store all the shows with the name as the key - try: - for item in api: - _dict[item["name"]] = {} - for value in item: - store_dict(_dict, item, value) - except Exception as e: - print(e) + for item in api: + _dict[item["name"]] = {} + for value in item: + store_dict(_dict, item, value) def store_dict(dict_, key, value): @@ -88,38 +83,6 @@ async def get_from_api(self, ctx, url): return _dict -def search(self, bot): - """Method to generate embed of multiple waifu's""" - - not_found = "https://media.discordapp.net/attachments/741072426984538122/748586578074664980/DzEZ4UsXgAAcFjN.png?width=423&height=658" - - embeds = [] - for key in self._dict.values(): - - # Only setting up description if waifu og_name has a value - desc = f"{key['original_name']}" if key["original_name"] else Embed.Empty - # Only using image if it can be displayed, else display 404 image - url = key["display_picture"] if key["display_picture"].endswith((".jpeg", ".png", ".jpg")) else not_found - - embed = Embed(title=key["name"], description=desc, - colour=bot.random_colour(), - url=key["url"]) - embed.set_image(url=url) - embed.set_author(name=key["type"]) - - if key["type"] in ["Waifu", "Husbando"]: - embed.set_footer(text=f"❤️ {key['likes']} 🗑️ {key['trash']} | Powered by MyWaifuList") - elif key["type"] in ["TV", "ONA", "OVA"]: - if key['romaji_name']: - embed.set_footer(text=f"{key['romaji_name']} | Powered by MyWaifuList") - else: - embed.set_footer(text="Powered by MyWaifuList") - - embeds.append(embed) - - return embeds - - def waifu_embed(self, waifu, _type): """Generate embed of single waifu's""" @@ -180,7 +143,8 @@ async def detailed_waifu_embed(self, waifu, author, ctx): hip = waifu["hip"] # Only setting up description if waifu og_name has a value - desc = f"**Original Name:** {og_name}\n" if og_name else f"**Original Name:** {self.bot.cross}\n" + desc = f"**Waifu ID:** {waifu_id}\n" + desc += f"**Original Name:** {og_name}\n" if og_name else f"**Original Name:** {self.bot.cross}\n" desc += f"**Romaji Name:** {romaji_name}\n" if romaji_name else f"**Romaji Name:** {self.bot.cross}\n" desc += f"\n**Age:** {age}\n" if age else f"**Age:** {self.bot.cross}\n" @@ -188,11 +152,16 @@ async def detailed_waifu_embed(self, waifu, author, ctx): desc += f"**Birthday-Month:** {b_month}\n" if b_month else f"**Birthday-Month:** {self.bot.cross}\n" desc += f"**Birthday-Year:** {b_year}\n" if b_year else f"**Birthday-Year:** {self.bot.cross}\n" - height = f"**Height:** {height}cm" if height else f"**Height:** {self.bot.cross}" - weight = f"**Weight:** {weight}kg" if weight else f"**Weight:** {self.bot.cross}" - waist = f"**Waist:** {waist}cm" if waist else f"**Waist:** {self.bot.cross}" - bust = f"**Bust:** {bust}cm" if bust else f"**Bust:** {self.bot.cross}" - hip = f"**Hip:** {hip}cm" if hip else f"**Hip:** {self.bot.cross}" + height = f"**Height:** {height}cm" if height != "0.00" else f"**Height:** {self.bot.cross}" + weight = f"**Weight:** {weight}kg" if weight != "0.00" else f"**Weight:** {self.bot.cross}" + waist = f"**Waist:** {waist}cm" if waist != "0.00" else f"**Waist:** {self.bot.cross}" + bust = f"**Bust:** {bust}cm" if bust != "0.00" else f"**Bust:** {self.bot.cross}" + hip = f"**Hip:** {hip}cm" if hip != "0.00" else f"**Hip:** {self.bot.cross}" + + # Only setting up the ranks if they are returned + pop_rank_string = f"**Popularity Rank:** {popularity_rank}\n" if popularity_rank else f"**Popularity Rank:** {self.bot.cross}\n" + like_rank_string = f"**Like Rank:** {like_rank}\n" if like_rank else f"**Like Rank:** {self.bot.cross}\n" + trash_rank_string = f"**Trash Rank:** {trash_rank}\n" if trash_rank else f"**Trash Rank:** {self.bot.cross}\n" fields = [("Measurements", f"{height}" @@ -202,21 +171,18 @@ async def detailed_waifu_embed(self, waifu, author, ctx): f"\n{hip}", True), ("Ranks", - f"**Popularity Rank:** {popularity_rank}" - f"\n**Like Rank:** {like_rank}" - f"\n**Trash Rank:** {trash_rank}", True)] + f"{pop_rank_string}" + f"{like_rank_string}" + f"{trash_rank_string}", True)] # Only using image if it can be displayed, else display 404 image picture_url = picture if picture.endswith((".jpeg", ".png", ".jpg")) else not_found # Different titles depending on if author was given or not title = f"True Love | {name}" if author else f"Detailed Waifu | {name}" - # Different author depending on if author was given or not - set_author = f"True Love ID: {waifu_id}" if author else f"Waifu ID: {waifu_id}" detailed = Embed(title=title, description=desc, colour=self.bot.random_colour(), url=url) - detailed.set_author(name=set_author) detailed.set_image(url=picture_url) detailed.set_footer(text=f"❤️ {likes} 🗑️ {trash} | Powered by MyWaifuList") @@ -275,270 +241,17 @@ async def user_embed(self, user, ctx): return author, love -def true_love_embed(): - """Generate embed for profile with true love information""" - - -class MWLMenu(menus.Menu): - """Setup menus for MyWaifuList results""" - - def __init__(self, i, perms, _dict, bot): - super().__init__(timeout=125.0, clear_reactions_after=True) - self.i = i - self.perms = perms - self._dict = _dict - self.bot = bot - self.dicts = search(self, bot) - - async def remove_reaction(self, reaction): - """Remove the reaction given""" - - if self.perms.manage_messages: - await self.message.remove_reaction(reaction, self.ctx.author) - - @staticmethod - def check(m, payload): - """Simple check to make sure that the reaction is performed by the user""" - - return m.author == payload.member and m.channel.id == payload.channel_id - - @staticmethod - def get_page(self): - """ - Return the current page index - """ - - cur_page = self.i + 1 - pages = len(self.dicts) - - return cur_page, pages - - @staticmethod - def set_author(embed, cur_page, pages): - """ - Returns the author for the first initial embed - - The reason why it's different is because I need to retrieve the previous author that I set for the - embed (to get the type from the API) - - """ - - __type = embed.author.name - embed.remove_author() - return embed.set_author(name=f"{__type} | Page {cur_page}/{pages}") - - @staticmethod - def set_author_after(embed, cur_page, pages): - """ - Returns the author for all the pages when the user reacts to go back and forwards - - This needs to be another method because the previous author is gonna be different to the one - specified at the start "multiple_dict_generators()" - """ - - author = embed.author.name - tv_type = author.split("|") - __type = tv_type[0].strip() - return embed.set_author(name=f"{__type} | Page {cur_page}/{pages}") - - async def send_initial_message(self, ctx, channel): - """Set the first embed to the first element in the pages[]""" - - initial = self.dicts[self.i] - - cur_page, pages = self.get_page(self) - initial = self.set_author(initial, cur_page, pages) - - # Send embed - return await channel.send(embed=initial) - - @menus.button('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}') - async def on_first_page_arrow(self, payload): - """Reaction to allow the user to return to the first page""" - - # Do nothing if the check does not return true - if self.check(self.ctx, payload): - - # Send the embed and remove the reaction of the user - if self.i == 0: - await self.remove_reaction("\U000023ee") - return - - self.i = 0 % len(self.dicts) - first_page = self.dicts[self.i] - - cur_page, pages = self.get_page(self) - first_page = self.set_author_after(first_page, cur_page, pages) - - await self.message.edit(embed=first_page) - await self.remove_reaction("\U000023ee") - - @menus.button('\N{LEFTWARDS BLACK ARROW}') - async def on_left_arrow(self, payload): - """Reaction to allow user to go to the previous page in the embed""" - - # Do nothing if the check does not return true - if self.check(self.ctx, payload): - # Set self.i to (i - 1) remainder length of the array - self.i = (self.i - 1) % len(self.dicts) - prev_page = self.dicts[self.i] - - cur_page, pages = self.get_page(self) - prev_page = self.set_author_after(prev_page, cur_page, pages) - - # Send the embed and remove the reaction of the user - await self.message.edit(embed=prev_page) - await self.remove_reaction("⬅") - - @menus.button('\N{BLACK RIGHTWARDS ARROW}') - async def on_right_arrow(self, payload): - """Reaction to allow user to go to the next page in the embed""" - - # Do nothing if the check does not return true - if self.check(self.ctx, payload): - # Set self.i to (i + 1) remainder length of the array - self.i = (self.i + 1) % len(self.dicts) - next_page = self.dicts[self.i] - - cur_page, pages = self.get_page(self) - next_page = self.set_author_after(next_page, cur_page, pages) - - # Send the embed and remove the reaction of the user - await self.message.edit(embed=next_page) - await self.remove_reaction("➡") - - @menus.button('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}') - async def on_last_page_arrow(self, payload): - """Reaction to allow the user to go to the last page in the embed""" - - # Do nothing if the check does not return true - if self.check(self.ctx, payload): - - # Send the embed and remove the reaction of the user - if self.i == len(self.dicts) - 1: - await self.remove_reaction("\U000023ed") - return - - self.i = len(self.dicts) - 1 - last_page = self.dicts[self.i] - - cur_page, pages = self.get_page(self) - last_page = self.set_author_after(last_page, cur_page, pages) - - await self.message.edit(embed=last_page) - await self.remove_reaction("\U000023ed") - - @menus.button('\N{INPUT SYMBOL FOR NUMBERS}') - async def on_numbered_page(self, payload): - """Reaction to allow users to input page numbers""" - - # Do nothing if the check does not return true - if self.check(self.ctx, payload): - - embed = Embed(description="**What Page Would You Like To Go To? (Only Numbers!)**", - colour=self.bot.random_colour()) - message = await self.ctx.send(embed=embed) - - def check(m): - """Simple check to make sure that the reaction is performed by the user""" - return m.author == payload.member and m.channel.id == payload.channel_id - - try: - # Wait for the message from the mentioned user - msg = await self.bot.wait_for('message', check=check, timeout=20.0) - - # Catch timeout error - except asyncio.TimeoutError as ex: - print(ex) - - await self.remove_reaction("\U0001f522") - - embed = Embed(description="**You Waited Too Long D:**", - colour=self.bot.random_colour()) - await message.edit(embed=embed) - - await asyncio.sleep(2.5) - await message.delete() - - else: - # As long as the number entered is within the page numbers, go to that page - try: - if 0 < int(msg.content) <= len(self.dicts): - await message.delete() - await msg.delete() - - self.i = int(msg.content) - 1 - number_page = self.dicts[self.i] - - cur_page, pages = self.get_page(self) - last_page = self.set_author_after(number_page, cur_page, pages) - - await self.message.edit(embed=last_page) - await self.remove_reaction("\U0001f522") - - # Delete the message and remove the reaction if out of bounds - else: - await message.delete() - await msg.delete() - await self.remove_reaction("\U0001f522") - except Exception as e: - print(e) - await message.delete() - await msg.delete() - await self.remove_reaction("\U0001f522") - - @menus.button('\N{INFORMATION SOURCE}') - async def on_information(self, payload): - """Show's information about the pagination session""" - - # Do nothing if the check does not return true - if self.check(self.ctx, payload): - - messages = ['Welcome to the Waifu/Anime Pagination Session!', - 'This interactively allows you to see pages of text by navigating with ' - 'reactions. They are as follows:\n'] - - reaction_emojis = [ - ('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', "Takes You To The First Page"), - ('\N{BLACK LEFT-POINTING TRIANGLE}', "Takes You To The Previous Page"), - ('\N{BLACK RIGHT-POINTING TRIANGLE}', "Takes You To The Next Page"), - ('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', "Takes You To The Last Page"), - ('\N{INPUT SYMBOL FOR NUMBERS}', "Enter Page Number To Go To"), - ('\N{INFORMATION SOURCE}', "Shows This Message"), - ('\N{BLACK SQUARE FOR STOP}', "Closes The Pagination Session") - ] - - for value, func in reaction_emojis: - messages.append(f"{value}, {func}") - - embed = Embed(description='\n'.join(messages), - colour=self.bot.random_colour(), - timestamp=datetime.datetime.utcnow()) - embed.set_footer(text=f'We Were On Page {self.i + 1} Before This Message') - - await self.message.edit(embed=embed) - await self.remove_reaction("\U00002139") - - @menus.button('\N{BLACK SQUARE FOR STOP}\ufe0f') - async def on_stop(self, payload): - """Reaction to allow user to make the embed disappear""" - - # Do nothing if the check does not return true - if self.check(self.ctx, payload): - # Edit the embed and tell the member that the session has been closed - embed = Embed(description="**Waifu/Anime Reaction Session Has Been Closed**", - colour=self.bot.random_colour()) - await self.message.edit(embed=embed) - self.stop() - - class Anime(Cog): """ Search MyWaifuList for Waifu's, Anime's and more! - Please keep in mind that this API is in ALPHA. - Searches might not return the proper results and images may be missing + Please keep in mind that this API is in ALPHA (And it is a community driven website.) + Searches might not return fully detailed results and images may be missing """ + # TODO: ADD A DETAILED SERIES COMMAND + # TODO: ADD AIRING SHOWS BY SEASON COMMAND + # TODO: ADD SERIES WAIFU COMMAND + def __init__(self, bot): self.bot = bot self.headers = {'apikey': my_waifu_list_auth} @@ -638,7 +351,7 @@ class Anime(Cog): menu = MWLMenu(i, perms, anime_dict, self.bot) await menu.start(ctx) - @group(name="waifu", invoke_without_command=True, case_insensitive=True) + @group(name="waifu", invoke_without_command=True, case_insensitive=True, usage="`daily|random`") @bot_has_permissions(embed_links=True) async def waifu(self, ctx): """