diff --git a/cogs/kanji.py b/cogs/kanji.py index fbbaf57..e0f1ba4 100644 --- a/cogs/kanji.py +++ b/cogs/kanji.py @@ -1,85 +1,90 @@ import discord from discord.ext import commands -from utils import jisho, interactive +from utils import jisho -class KanjiEmbed(interactive.InteractiveEmbed): - REACTIONS = { - "prev_kanji": "⬅️", - "next_kanji": "➡️" - } +class JishoKanjiObject(): + def __init__(self, query, owner): + self.response = jisho.JishoKanji(query) + self.total_pages = self.response.entries + self.page = 0 + self.owner = owner - def __init__(self, parent, ctx, response): - super(KanjiEmbed, self).__init__(parent.bot, ctx, 60.0) - self.parent = parent - self.owner = self.ctx.author - self.response = response + def prev(self): + self.page -= 1 + if self.page < 0: + self.page = self.total_pages - 1 - self.current_kanji = 0 - - def prev_kanji(self): - self.current_kanji -= 1 - if self.current_kanji < 0: - self.current_kanji = self.response.entries - 1 - - def next_kanji(self): - self.current_kanji += 1 - if self.current_kanji >= self.response.entries: - self.current_kanji = 0 - - async def on_reaction(self, reaction, user): - if reaction.emoji == KanjiEmbed.REACTIONS["prev_kanji"]: - self.prev_kanji() - await reaction.remove(user) - - if reaction.emoji == KanjiEmbed.REACTIONS["next_kanji"]: - self.next_kanji() - await reaction.remove(user) - - async def add_navigation(self, message): - if self.response.entries > 1: - await message.add_reaction(KanjiEmbed.REACTIONS["prev_kanji"]) - await message.add_reaction(KanjiEmbed.REACTIONS["next_kanji"]) - - def make_embed(self): - node = self.response.nodes[self.current_kanji] - - embed = discord.Embed( - title = node.meaning, - url = node.url, - description = f"{node.strokes} strokes", - colour = 0x56d926 - ) - - if node.kun: - embed.add_field(name="Kun", value="、 ".join(node.kun), inline=False) - if node.on: - embed.add_field(name="On", value="、 ".join(node.on), inline=False) - - embed.add_field(name=f"Radical: {node.radical[0]}", value=node.radical[1], inline=False) - embed.set_thumbnail(url=node.image_url) - embed.set_footer(text=f"Jōyō kanji (Grade {node.grade}) | JLPT level {node.jlpt}\t\t{self.current_kanji + 1}/{self.response.entries}") - - return embed - - async def on_close(self): - self.parent.activeObjects.pop(self.ctx.channel.id) + def next(self): + self.page += 1 + if self.page >= self.total_pages: + self.page = 0 class Kanji(commands.Cog): def __init__(self, bot): self.bot = bot - self.activeObjects = {} + self.activeObject = None + self.latestMessage = 0 - @commands.command(name="kanji", description="Performs a Kanji search", usage="", aliases=["k"]) - @commands.cooldown(1, 5) - async def kanji(self, ctx, *, kanji: str = None): - if kanji is None: + async def createEmbed(self): + if self.activeObject.total_pages == 0: embed = discord.Embed( title = "No search results", description = "The search returned nothing. Did you make a typo?", colour = 0x56d926 ) - await ctx.send(embed=embed) + else: + response = self.activeObject.response + node = response.nodes[self.activeObject.page] + + embed = discord.Embed( + title = node.meaning, + url = node.url, + description = f"{node.strokes} strokes", + colour = 0x56d926 + ) + + if node.kun: + embed.add_field(name="Kun", value="、 ".join(node.kun), inline=False) + if node.on: + embed.add_field(name="On", value="、 ".join(node.on), inline=False) + + embed.add_field(name=f"Radical: {node.radical[0]}", value=node.radical[1], inline=False) + + embed.set_thumbnail(url=node.image_url) + + embed.set_footer(text=f"Jōyō kanji (Grade {node.grade}) | JLPT level {node.jlpt}\t\t{self.activeObject.page + 1}/{self.activeObject.total_pages}") + + return embed + + @commands.Cog.listener() + async def on_reaction_add(self, reaction, user): + message = reaction.message + if message.id != self.latestMessage: + return + + if user == self.bot.user: + return + + if user.id != self.activeObject.owner: + return + + if reaction.me: + if reaction.emoji == "⬅️": + self.activeObject.prev() + await reaction.remove(user) + + if reaction.emoji == "➡️": + self.activeObject.next() + await reaction.remove(user) + + embed = await self.createEmbed() + await message.edit(embed=embed) + + @commands.command(name="kanji", description="Performs a Kanji search", usage="", aliases=["k"]) + @commands.cooldown(1, 5) + async def kanji(self, ctx, *, kanji: str = None): + if kanji is None: return embed = discord.Embed( @@ -87,23 +92,19 @@ class Kanji(commands.Cog): description = "This might take a few seconds", colour = 0x56d926 ) + message = await ctx.send(embed=embed) kanji = kanji[:5] - response = jisho.JishoKanji(kanji) - - if response.entries < 1: - embed = discord.Embed( - title = "No search results", - description = "The search returned nothing. Did you make a typo?", - colour = 0x56d926 - ) - await message.edit(embed=embed) - return - await message.delete() - self.activeObjects[ctx.channel.id] = KanjiEmbed(self, ctx, response) - await self.activeObjects[ctx.channel.id].show_embed() + self.activeObject = JishoKanjiObject(kanji, ctx.author.id) + embed = await self.createEmbed() + await message.edit(embed=embed) + self.latestMessage = message.id + + if self.activeObject.total_pages > 1: + await message.add_reaction("⬅️") + await message.add_reaction("➡️") def setup(bot): bot.add_cog(Kanji(bot)) \ No newline at end of file diff --git a/cogs/search.py b/cogs/search.py index da6e426..a55c1eb 100644 --- a/cogs/search.py +++ b/cogs/search.py @@ -1,107 +1,106 @@ -from inspect import currentframe import discord from discord.ext import commands -from utils import jisho, interactive +from utils import jisho -class SearchEmbed(interactive.InteractiveEmbed): - REACTIONS = { - "prev_page": "⬅️", - "next_page": "➡️" - } +class JishoObject(): + def __init__(self, query, owner): + self.response = jisho.JishoResponse(query) + self.total_pages = self.response.entries + self.page = 0 + self.owner = owner - def __init__(self, parent, ctx, response): - super(SearchEmbed, self).__init__(parent.bot, ctx, 60.0) - self.parent = parent - self.owner = self.ctx.author - self.response = response + def prev(self): + self.page -= 1 + if self.page < 0: + self.page = self.total_pages - 1 - self.current_page = 0 - - def prev_page(self): - self.current_page -= 1 - if self.current_page < 0: - self.current_page = self.response.size - 1 - - def next_page(self): - self.current_page += 1 - if self.current_page >= self.response.size: - self.current_page = 0 - - async def on_reaction(self, reaction, user): - if reaction.emoji == SearchEmbed.REACTIONS["prev_page"]: - self.prev_page() - await reaction.remove(user) - - if reaction.emoji == SearchEmbed.REACTIONS["next_page"]: - self.next_page() - await reaction.remove(user) - - async def add_navigation(self, message): - await message.add_reaction(SearchEmbed.REACTIONS["prev_page"]) - await message.add_reaction(SearchEmbed.REACTIONS["next_page"]) - - def make_embed(self): - node = self.response.nodes[self.current_page] - embed = discord.Embed( - title = node.japanese[0][0], - url = f"https://jisho.org/word/{node.slug}", - description = node.japanese[0][1], - colour = 0x56d926 - ) - - i = 1 - for sense in node.senses: - embed.add_field(name=f"{i}. {sense.fenglish_definitions}", value=sense.fparts_of_speech, inline=False) - i += 1 - - if len(node.japanese) > 1: - other = "" - for word, reading in node.japanese[1:]: - other += word - if reading != "": - other += f"【{reading}】" - other += "\n" - embed.add_field(name="Other forms", value=other) - - - embed.set_footer( - text = f"{node.ftags} \t\t {self.current_page + 1}/{self.response.size}" - ) - - return embed - - async def on_close(self): - self.parent.activeObjects.pop(self.ctx.channel.id) + def next(self): + self.page += 1 + if self.page >= self.total_pages: + self.page = 0 class Search(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot - self.activeObjects = {} + self.activeObject = None + self.latestMessage = 0 + + async def createEmbed(self): + if self.activeObject.total_pages == 0: + embed = discord.Embed( + title = "No search results", + description = "The search returned nothing. Did you make a typo?", + colour = 0x56d926 + ) + else: + response = self.activeObject.response + node = response.nodes[self.activeObject.page] + embed = discord.Embed( + title = node.japanese[0][0], + url = f"https://jisho.org/word/{node.slug}", + description = node.japanese[0][1], + colour = 0x56d926 + ) + + i = 1 + for sense in node.senses: + embed.add_field(name=f"{i}. {sense.fenglish_definitions}", value=sense.fparts_of_speech, inline=False) + i += 1 + + if len(node.japanese) > 1: + other = "" + for word, reading in node.japanese[1:]: + other += word + if reading != "": + other += f"【{reading}】" + other += "\n" + embed.add_field(name="Other forms", value=other) + + + embed.set_footer( + text = f"{node.ftags} \t\t {self.activeObject.page + 1}/{self.activeObject.total_pages}" + ) + + return embed + + @commands.Cog.listener() + async def on_reaction_add(self, reaction, user): + message = reaction.message + if message.id != self.latestMessage: + return + + if user == self.bot.user: + return + + if user.id != self.activeObject.owner: + return + + if reaction.me: + if reaction.emoji == "⬅️": + self.activeObject.prev() + await reaction.remove(user) + + if reaction.emoji == "➡️": + self.activeObject.next() + await reaction.remove(user) + + embed = await self.createEmbed() + await message.edit(embed=embed) + @commands.command(name="search", description="Searches Jisho", usage="", aliases=["s"]) @commands.cooldown(1, 5) async def search(self, ctx: commands.Context, *, query: str = None): if query is None: - embed = discord.Embed( - title = "No search results", - description = "The search returned nothing. Did you make a typo?", - colour = 0x56d926 - ) - await ctx.send(embed=embed) return - result = jisho.JishoResponse(query) - if result.size == 0: - embed = discord.Embed( - title = "No search results", - description = "The search returned nothing. Did you make a typo?", - colour = 0x56d926 - ) - await ctx.send(embed=embed) - return - - self.activeObjects[ctx.channel.id] = SearchEmbed(self, ctx, result) - await self.activeObjects[ctx.channel.id].show_embed() + self.activeObject = JishoObject(query, ctx.author.id) + embed = await self.createEmbed() + message = await ctx.send(embed=embed) + self.latestMessage = message.id + if self.activeObject.total_pages > 0: + await message.add_reaction("⬅️") + await message.add_reaction("➡️") @search.error async def search_error(self, ctx, error): diff --git a/utils/interactive.py b/utils/interactive.py deleted file mode 100644 index b8c8e75..0000000 --- a/utils/interactive.py +++ /dev/null @@ -1,93 +0,0 @@ -import discord -from discord.ext import commands -from abc import ABC, abstractmethod -import asyncio - -class InteractiveEmbed(ABC): - """ - This abstract base class can be used to create interactive embeds - """ - def __init__(self, bot, ctx, timeout): - """ - Sets up the embed with needed parameters - bot: The bot hosting this embed - ctx: The context that caused this embed - timeuout: The time until the embed times out (in seconds) - """ - self.bot = bot - self.ctx = ctx - self.message = None - self.timeout = timeout - - @abstractmethod - async def on_reaction(self, reaction, user): - """ - Gets called when the user interacted with the embed - """ - pass - - @abstractmethod - def make_embed(self): - """ - Creates and returns a new embed - """ - pass - - @abstractmethod - async def add_navigation(self, message): - """ - Adds the navigational emotes to the embed - """ - pass - - async def on_close(self): - """ - Can be overridden. Gets called when the embed is closed - """ - pass - - def additional_checks(self, reaction, user): - """ - Can be overridden. Additional checks to do before calling on_reaction() - """ - return True - - async def show_embed(self): - """ - Displays an embed / Creates an embed - """ - if self.message is None: - self.message = await self.ctx.send(embed=self.make_embed()) - await self.add_navigation(self.message) - - else: - await self.message.edit(embed=self.make_embed()) - - def check(reaction, user): - if self.message is None: - return False - - if user.id != self.ctx.author.id: - return False - - if reaction.message.id != self.message.id: - return False - - if not reaction.me: - return False - - return self.additional_checks(reaction, user) - - try: - reaction, user = await self.bot.wait_for("reaction_add", check=check, timeout=self.timeout) - await self.on_reaction(reaction, user) - await self.show_embed() - except asyncio.TimeoutError: - await self.close_embed() - - async def close_embed(self): - """ - Close this embed - """ - await self.message.clear_reactions() - await self.on_close() \ No newline at end of file diff --git a/utils/jisho.py b/utils/jisho.py index b72a777..ccf2ec6 100644 --- a/utils/jisho.py +++ b/utils/jisho.py @@ -64,8 +64,6 @@ class JishoResponse(): self.nodes = [] self.disassemble() - self.size = len(self.nodes) - def query(self): url = TEMPLATE_URL.format(urllib.parse.quote_plus(self.query_string)) r = requests.get(url, headers=HEADER)