From 66e8cc9250b1496f1be878300d7c31eb92198ea7 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 11 Aug 2020 15:52:13 +0200 Subject: [PATCH 1/6] Added Kanji cog --- cogs/kanji.py | 14 ++++++++++++++ utils/jisho.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 cogs/kanji.py diff --git a/cogs/kanji.py b/cogs/kanji.py new file mode 100644 index 0000000..72ce067 --- /dev/null +++ b/cogs/kanji.py @@ -0,0 +1,14 @@ +import discord +from discord.ext import commands + +class Kanji(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.command(name="kanji", description="Performs a Kanji search", usage="", aliases=["k"]) + @commands.cooldown(1, 5) + async def kanji(self, ctx, *, kanji): + return kanji + +def setup(bot): + bot.add_cog(Kanji(bot)) \ No newline at end of file diff --git a/utils/jisho.py b/utils/jisho.py index 801d6be..6e9e161 100644 --- a/utils/jisho.py +++ b/utils/jisho.py @@ -63,7 +63,7 @@ class JishoResponse(): def query(self): url = TEMPLATE_URL.format(urllib.parse.quote_plus(self.query_string)) - r = requests.get(url) + r = requests.get(url, headers=HEADER) if r.status_code != 200: print(f"ERROR: Failed to access Jisho API... {r.status_code}") From d3cbf5b5abcd1f7b60b913e3c211c26ca83a104c Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 11 Aug 2020 16:56:19 +0200 Subject: [PATCH 2/6] Added html parsing --- .gitignore | 3 ++- cogs/kanji.py | 9 +++++++-- utils/jisho.py | 39 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index fdc50ab..a0dcfb4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .vscode __pycache__ -*.json \ No newline at end of file +*.json +*.html \ No newline at end of file diff --git a/cogs/kanji.py b/cogs/kanji.py index 72ce067..c90f6c6 100644 --- a/cogs/kanji.py +++ b/cogs/kanji.py @@ -1,5 +1,6 @@ import discord from discord.ext import commands +from utils import jisho class Kanji(commands.Cog): def __init__(self, bot): @@ -7,8 +8,12 @@ class Kanji(commands.Cog): @commands.command(name="kanji", description="Performs a Kanji search", usage="", aliases=["k"]) @commands.cooldown(1, 5) - async def kanji(self, ctx, *, kanji): - return kanji + async def kanji(self, ctx, *, kanji: str = None): + if kanji is None: + return + + response = jisho.JishoKanji(kanji) + await ctx.send(response.entries) def setup(bot): bot.add_cog(Kanji(bot)) \ No newline at end of file diff --git a/utils/jisho.py b/utils/jisho.py index 6e9e161..a6a91a3 100644 --- a/utils/jisho.py +++ b/utils/jisho.py @@ -1,14 +1,16 @@ import requests import urllib.parse import json +from bs4 import BeautifulSoup TEMPLATE_URL = "https://jisho.org/api/v1/search/words?keyword={0}" +TEMPLATE_KANJI_URL = "https://jisho.org/search/{0}" HEADER = { "User-Agent": "Jisho Bot", "From": "https://github.com/Lauchmelder23/JishoBot" } -class JishoSenses(): +class JishoSense(): def __init__(self, sense): self.english_definitions = sense["english_definitions"] self.fenglish_definitions = "; ".join(self.english_definitions) @@ -52,7 +54,7 @@ class JishoNode(): self.senses = [] for sense in node["senses"]: - self.senses.append(JishoSenses(sense)) + self.senses.append(JishoSense(sense)) class JishoResponse(): def __init__(self, query: str): @@ -78,3 +80,36 @@ class JishoResponse(): for node in self.raw["data"]: self.nodes.append(JishoNode(node)) + + +class JishoKanjiNode(): + def __init__(self): + # Information about the Kanji + self.kanji = "" + self.on = [] + self.kun = [] + +class JishoKanji(): + def __init__(self, query): + self.query_string = query + + # List of JishoKanjiNodes + self.nodes = [] + self.entries = 0 + + self.query() + + def query(self): + url = TEMPLATE_KANJI_URL.format(urllib.parse.quote_plus(self.query_string + "#kanji")) + r = requests.get(url, headers=HEADER) + + if r.status_code != 200: + print(f"ERROR: Failed to access Jisho API... {r.status_code}") + return None + + body = BeautifulSoup(r.text, features="html.parser") + + info_blocks = body.find_all("div", {"class": "kanji details"}) + + for info in info_blocks: + block = BeautifulSoup(str(info), features="html.parser") From b333bbad41264bc7e9dac75e63bd135452742728 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 11 Aug 2020 17:34:22 +0200 Subject: [PATCH 3/6] Added Kun/On readings to kanji search --- cogs/kanji.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++++-- cogs/search.py | 10 +++++--- utils/jisho.py | 29 ++++++++++++++++++--- 3 files changed, 98 insertions(+), 10 deletions(-) diff --git a/cogs/kanji.py b/cogs/kanji.py index c90f6c6..4017b26 100644 --- a/cogs/kanji.py +++ b/cogs/kanji.py @@ -2,9 +2,68 @@ import discord from discord.ext import commands from utils import jisho +class JishoKanjiObject(): + def __init__(self, query): + self.response = jisho.JishoKanji(query) + self.total_pages = self.response.entries + self.page = 0 + + def prev(self): + self.page -= 1 + if self.page < 0: + self.page = self.total_pages - 1 + + 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.activeObject = None + self.latestMessage = 0 + + async def createEmbed(self): + response = self.activeObject.response + node = response.nodes[self.activeObject.page] + + embed = discord.Embed( + title = node.kanji, + url = node.url, + colour = 0x56d926 + ) + + if node.kun: + embed.add_field(name="Kun", value=", ".join(node.kun)) + if node.on: + embed.add_field(name="On", value=", ".join(node.on)) + + embed.set_footer(text=f"{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 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) @@ -12,8 +71,14 @@ class Kanji(commands.Cog): if kanji is None: return - response = jisho.JishoKanji(kanji) - await ctx.send(response.entries) + self.activeObject = JishoKanjiObject(kanji) + embed = await self.createEmbed() + message = await ctx.send(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 235451f..41a1f5d 100644 --- a/cogs/search.py +++ b/cogs/search.py @@ -67,15 +67,15 @@ class Search(commands.Cog): 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) - await reaction.remove(user) - @commands.command(name="search", description="Searches Jisho", usage="", aliases=["s"]) @commands.cooldown(1, 5) @@ -87,8 +87,10 @@ class Search(commands.Cog): embed = await self.createEmbed() message = await ctx.send(embed=embed) self.latestMessage = message.id - await message.add_reaction("⬅️") - await message.add_reaction("➡️") + + if self.activeObject.total_pages > 1: + await message.add_reaction("⬅️") + await message.add_reaction("➡️") @search.error async def search_error(self, ctx, error): diff --git a/utils/jisho.py b/utils/jisho.py index a6a91a3..f9f618e 100644 --- a/utils/jisho.py +++ b/utils/jisho.py @@ -86,8 +86,9 @@ class JishoKanjiNode(): def __init__(self): # Information about the Kanji self.kanji = "" - self.on = [] + self.url = "https://jisho.org/search/" self.kun = [] + self.on = [] class JishoKanji(): def __init__(self, query): @@ -100,8 +101,8 @@ class JishoKanji(): self.query() def query(self): - url = TEMPLATE_KANJI_URL.format(urllib.parse.quote_plus(self.query_string + "#kanji")) - r = requests.get(url, headers=HEADER) + self.url = TEMPLATE_KANJI_URL.format(urllib.parse.quote_plus(self.query_string + "#kanji")) + r = requests.get(self.url, headers=HEADER) if r.status_code != 200: print(f"ERROR: Failed to access Jisho API... {r.status_code}") @@ -112,4 +113,24 @@ class JishoKanji(): info_blocks = body.find_all("div", {"class": "kanji details"}) for info in info_blocks: - block = BeautifulSoup(str(info), features="html.parser") + self.entries += 1 + self.nodes.append(JishoKanjiNode()) + + self.nodes[-1].kanji = info.findChild("h1").string + self.nodes[-1].url += urllib.parse.quote_plus(self.nodes[-1].kanji + "#kanji") + + readings_block = info.findChild("div", {"class": "kanji-details__main-readings"}, recursive=True) + + # Kun Yomi + kun_block = readings_block.findChild("dl", {"class": "dictionary_entry kun_yomi"}, recursive=True) + if kun_block != None: + readings = kun_block.findChildren("a", recursive=True) + for reading in readings: + self.nodes[-1].kun.append(reading.string) + + # On Yomi + on_block = readings_block.findChild("dl", {"class": "dictionary_entry on_yomi"}, recursive=True) + if on_block != None: + readings = on_block.findChildren("a", recursive=True) + for reading in readings: + self.nodes[-1].on.append(reading.string) From 1d1b66f87a967123890144afc0712603318b5a37 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 11 Aug 2020 17:38:38 +0200 Subject: [PATCH 4/6] Added meanings --- cogs/kanji.py | 5 +++-- utils/jisho.py | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cogs/kanji.py b/cogs/kanji.py index 4017b26..32f62aa 100644 --- a/cogs/kanji.py +++ b/cogs/kanji.py @@ -32,13 +32,14 @@ class Kanji(commands.Cog): embed = discord.Embed( title = node.kanji, url = node.url, + description = node.meaning, colour = 0x56d926 ) if node.kun: - embed.add_field(name="Kun", value=", ".join(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)) + embed.add_field(name="On", value=", ".join(node.on), inline=False) embed.set_footer(text=f"{self.activeObject.page + 1}/{self.activeObject.total_pages}") diff --git a/utils/jisho.py b/utils/jisho.py index f9f618e..c72acc4 100644 --- a/utils/jisho.py +++ b/utils/jisho.py @@ -87,6 +87,7 @@ class JishoKanjiNode(): # Information about the Kanji self.kanji = "" self.url = "https://jisho.org/search/" + self.meaning = "" self.kun = [] self.on = [] @@ -119,8 +120,11 @@ class JishoKanji(): self.nodes[-1].kanji = info.findChild("h1").string self.nodes[-1].url += urllib.parse.quote_plus(self.nodes[-1].kanji + "#kanji") + # Meanings + self.nodes[-1].meaning = info.findChild("div", {"class": "kanji-details__main-meanings"}, recursive=True).string + readings_block = info.findChild("div", {"class": "kanji-details__main-readings"}, recursive=True) - + # Kun Yomi kun_block = readings_block.findChild("dl", {"class": "dictionary_entry kun_yomi"}, recursive=True) if kun_block != None: From 67b50c3b8cfad26c6ba85798920f7cf3b8f92e6b Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 11 Aug 2020 18:07:31 +0200 Subject: [PATCH 5/6] Fixed permissions for embed usage --- cogs/kanji.py | 8 ++++++-- cogs/search.py | 8 ++++++-- utils/jisho.py | 9 +++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/cogs/kanji.py b/cogs/kanji.py index 32f62aa..9f67ba1 100644 --- a/cogs/kanji.py +++ b/cogs/kanji.py @@ -3,10 +3,11 @@ from discord.ext import commands from utils import jisho class JishoKanjiObject(): - def __init__(self, query): + def __init__(self, query, owner): self.response = jisho.JishoKanji(query) self.total_pages = self.response.entries self.page = 0 + self.owner = owner def prev(self): self.page -= 1 @@ -54,6 +55,9 @@ class Kanji(commands.Cog): if user == self.bot.user: return + if user.id != self.activeObject.owner: + return + if reaction.me: if reaction.emoji == "⬅️": self.activeObject.prev() @@ -72,7 +76,7 @@ class Kanji(commands.Cog): if kanji is None: return - self.activeObject = JishoKanjiObject(kanji) + self.activeObject = JishoKanjiObject(kanji, ctx.author.id) embed = await self.createEmbed() message = await ctx.send(embed=embed) self.latestMessage = message.id diff --git a/cogs/search.py b/cogs/search.py index 41a1f5d..b3835ee 100644 --- a/cogs/search.py +++ b/cogs/search.py @@ -3,10 +3,11 @@ from discord.ext import commands from utils import jisho class JishoObject(): - def __init__(self, query): + def __init__(self, query, owner): self.response = jisho.JishoResponse(query) self.total_pages = self.response.entries self.page = 0 + self.owner = owner def prev(self): self.page -= 1 @@ -64,6 +65,9 @@ class Search(commands.Cog): if user == self.bot.user: return + if user.id != self.activeObject.owner: + return + if reaction.me: if reaction.emoji == "⬅️": self.activeObject.prev() @@ -83,7 +87,7 @@ class Search(commands.Cog): if query == None: return - self.activeObject = JishoObject(query) + self.activeObject = JishoObject(query, ctx.author.id) embed = await self.createEmbed() message = await ctx.send(embed=embed) self.latestMessage = message.id diff --git a/utils/jisho.py b/utils/jisho.py index c72acc4..800cff5 100644 --- a/utils/jisho.py +++ b/utils/jisho.py @@ -90,6 +90,10 @@ class JishoKanjiNode(): self.meaning = "" self.kun = [] self.on = [] + self.radical = "" + self.grade = "" + self.jlpt = "" + class JishoKanji(): def __init__(self, query): @@ -138,3 +142,8 @@ class JishoKanji(): readings = on_block.findChildren("a", recursive=True) for reading in readings: self.nodes[-1].on.append(reading.string) + + # Radical + radical_block = readings_block.findChild("div", {"class": "radicals"}, recursive=True) + print(radical_block) + From 68bf4ccba50c2680e920bb112d3f0a35b42e8edf Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 11 Aug 2020 18:31:20 +0200 Subject: [PATCH 6/6] Finished Kanji search --- cogs/kanji.py | 8 +++++--- utils/jisho.py | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/cogs/kanji.py b/cogs/kanji.py index 9f67ba1..801e3d2 100644 --- a/cogs/kanji.py +++ b/cogs/kanji.py @@ -38,11 +38,13 @@ class Kanji(commands.Cog): ) if node.kun: - embed.add_field(name="Kun", value=", ".join(node.kun), inline=False) + 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="On", value="、 ".join(node.on), inline=False) - embed.set_footer(text=f"{self.activeObject.page + 1}/{self.activeObject.total_pages}") + embed.add_field(name=f"Radical: {node.radical[0]}", value=node.radical[1], inline=False) + + 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 diff --git a/utils/jisho.py b/utils/jisho.py index 800cff5..ac2dd88 100644 --- a/utils/jisho.py +++ b/utils/jisho.py @@ -1,6 +1,7 @@ import requests import urllib.parse import json +import re from bs4 import BeautifulSoup TEMPLATE_URL = "https://jisho.org/api/v1/search/words?keyword={0}" @@ -90,7 +91,7 @@ class JishoKanjiNode(): self.meaning = "" self.kun = [] self.on = [] - self.radical = "" + self.radical = [] self.grade = "" self.jlpt = "" @@ -144,6 +145,14 @@ class JishoKanji(): self.nodes[-1].on.append(reading.string) # Radical - radical_block = readings_block.findChild("div", {"class": "radicals"}, recursive=True) - print(radical_block) + radical_block = info.findChild("div", {"class": "radicals"}, recursive=True).findChild("span") + self.nodes[-1].radical.append(re.sub(r'[ \n"]', "", radical_block.contents[2].string)) + self.nodes[-1].radical.append(re.sub(r'[ \n"]', "", radical_block.contents[1].string)) + + # JLPT/Grade info + grade_block = info.findChild("div", {"class": "grade"}, recursive=True) + if grade_block != None: + self.nodes[-1].grade = grade_block.findChild("strong").string[-1] + + self.nodes[-1].jlpt = info.findChild("div", {"class": "jlpt"}, recursive=True).findChild("strong").string