diff --git a/cogs/birthdays.py b/cogs/birthdays.py index 8c0f351..2c3c284 100644 --- a/cogs/birthdays.py +++ b/cogs/birthdays.py @@ -163,8 +163,8 @@ class Birthdays(commands.Cog): # Create a datetime object for this birthday timeString = "{}/{}/{}".format( - stringFormatters.leading_zero(str(day)), - stringFormatters.leading_zero(str(month)), + stringFormatters.leadingZero(str(day)), + stringFormatters.leadingZero(str(month)), year ) diff --git a/cogs/define.py b/cogs/define.py index 26adb40..23eba64 100644 --- a/cogs/define.py +++ b/cogs/define.py @@ -1,8 +1,11 @@ -from data.embeds.urban_dictionary import Definition +import os + from decorators import help +import discord from discord.ext import commands from enums.help_categories import Category from functions import checks +import requests class Define(commands.Cog): @@ -16,15 +19,99 @@ class Define(commands.Cog): @commands.command(name="Define", aliases=["UrbanDictionary", "Ud"], usage="[Woord]") @commands.check(checks.allowedChannels) @help.Category(category=Category.Other) - async def define(self, ctx, *, query): + async def define(self, ctx, *words): """ Command that looks up the definition of a word in the Urban Dictionary. :param ctx: Discord Context - :param query: Word(s) to look up + :param words: Word(s) to look up """ - embed = Definition(query).to_embed() + words = list(words) + if len(words) == 0: + return await ctx.send("Controleer je argumenten.") + + query = " ".join(words) + answer = self.lookup(query) + + embed = discord.Embed(colour=discord.Colour.from_rgb(220, 255, 0)) + embed.set_author(name="Urban Dictionary") + + embed.add_field(name="Woord", value=answer["word"], inline=True) + embed.add_field(name="Auteur", value=answer["author"], inline=True) + embed.add_field(name="Definitie", value=self.cleanString(answer["definition"]), inline=False) + embed.add_field(name="Voorbeeld", value=self.cleanString(answer["example"]), inline=False) + embed.add_field(name="Rating", value=str(round(self.ratio(answer), 2)) + "%") + embed.add_field(name="Link naar de volledige definitie", + value="[Urban Dictionary]({})".format(str(answer["link"]))) + await ctx.send(embed=embed) + def lookup(self, word): + """ + Function that sends the API request to get the definition. + :param word: the woord to look up + :return: a dictionary representing the info of this word + """ + url = "https://mashape-community-urban-dictionary.p.rapidapi.com/define" + + querystring = {"term": word} + + headers = { + 'x-rapidapi-host': "mashape-community-urban-dictionary.p.rapidapi.com", + 'x-rapidapi-key': os.getenv("URBANDICTIONARY") + } + + try: + if word.lower() == "didier": + raise Exception + + response = requests.request("GET", url, headers=headers, params=querystring).json()["list"] + + if len(response) > 0: + return {"word": response[0]["word"], "definition": response[0]["definition"], + "example": response[0]["example"], "thumbs_up": response[0]["thumbs_up"], + "thumbs_down": response[0]["thumbs_down"], "link": response[0]["permalink"], + "author": response[0]["author"]} + + # No valid response + return self.defineDidier() + except Exception: + return self.defineDidier() + + def cleanString(self, text: str): + """ + Function that cuts off definitions that are too long & strips out UD markdown + from an input string. + :param text: the input string to clean up + :return: the edited version of the string + """ + text = text.replace("[", "") + text = text.replace("]", "") + + if not text: + return "N/A" + + return text if len(text) < 1024 else text[:1021] + "..." + + def ratio(self, dic): + """ + Function that alculates the upvote/downvote ratio of the definition. + :param dic: the dictionary representing the definition + :return: the upvote/downvote ratio (float) + """ + return (100 * int(dic["thumbs_up"])) / (int(dic["thumbs_up"]) + int(dic["thumbs_down"])) \ + if int(dic["thumbs_down"]) != 0 else 100.0 + + def defineDidier(self): + """ + Function that returns a stock dictionary to define Didier + in case people call it, or no definition was found. + :return: a dictionary that defines Didier + """ + return {"word": "Didier", "definition": "Didier", "example": "1: Didier\n2: Hmm?", "thumbs_up": 69420, + "thumbs_down": 0, "author": "Didier", + "link": "https://upload.wikimedia.org/wikipedia/commons/a/a5" + "/Didier_Reynders_in_Iranian_Parliament_02.jpg"} + def setup(client): client.add_cog(Define(client)) diff --git a/cogs/faq.py b/cogs/faq.py index 1b198fe..8817b29 100644 --- a/cogs/faq.py +++ b/cogs/faq.py @@ -37,7 +37,7 @@ class Faq(commands.Cog): return await self.faqCategory(ctx, (constants.faq_channels[ctx.channel.id],)) # List of all categories with the first letter capitalized - resp = [stringFormatters.title_case(cat[0]) for cat in faq.getCategories()] + resp = [stringFormatters.titleCase(cat[0]) for cat in faq.getCategories()] # Sort alphabetically resp.sort() @@ -146,7 +146,7 @@ class Faq(commands.Cog): resp.sort(key=lambda x: int(x[0])) embed = discord.Embed(colour=discord.Colour.blue()) - embed.set_author(name="FAQ {}".format(stringFormatters.title_case(category))) + embed.set_author(name="FAQ {}".format(stringFormatters.titleCase(category))) # Add everything into the embed for i, pair in enumerate(resp): diff --git a/cogs/fun.py b/cogs/fun.py index 11b0a21..8d7a381 100644 --- a/cogs/fun.py +++ b/cogs/fun.py @@ -120,7 +120,7 @@ class Fun(commands.Cog): memeList = memes.getAllMemes() # Turn the list into a list of [Name: fields] - memeList = [": ".join([stringFormatters.title_case(meme[1]), + memeList = [": ".join([stringFormatters.titleCase(meme[1]), str(meme[2])]) for meme in sorted(memeList, key=lambda x: x[1])] pages = paginatedLeaderboard.Pages(source=paginatedLeaderboard.Source(memeList, "Memes", discord.Colour.blue()), diff --git a/cogs/google.py b/cogs/google.py index 429b4f4..310403d 100644 --- a/cogs/google.py +++ b/cogs/google.py @@ -1,8 +1,30 @@ import discord from discord.ext import commands +from dislash import slash_command, SlashInteraction, Option, OptionType from decorators import help from enums.help_categories import Category -from functions.scrapers.google import google_search, create_google_embed +from functions.scrapers.google import google_search, SearchResult + + +def _create_google_embed(result: SearchResult) -> discord.Embed: + embed = discord.Embed(colour=discord.Colour.blue()) + embed.set_author(name="Google Search") + + # Empty list of results + if len(result.results) == 0: + embed.colour = discord.Colour.red() + embed.description = "Geen resultaten gevonden." + return embed + + # Add results into a field + links = [] + + for index, link in enumerate(result.results): + links.append(f"{index + 1}: {link}") + + embed.description = "\n".join(links) + + return embed class Google(commands.Cog): @@ -13,6 +35,22 @@ class Google(commands.Cog): def cog_check(self, ctx): return not self.client.locked + @slash_command(name="google", + description="Google search", + options=[ + Option("query", "Search query", OptionType.STRING, required=True) + ], + guild_ids=[880175869841277008] + ) + async def _google_slash(self, interaction: SlashInteraction, query: str): + result = google_search(query) + + if not result.results: + return await interaction.reply("Er ging iets fout (Response {})".format(result.status_code)) + + embed = _create_google_embed(result) + await interaction.reply(embed=embed) + @commands.command(name="Google", aliases=["Gtfm", "Search"], usage="[Query]", case_insensitive=True) @help.Category(Category.Other) async def google(self, ctx, *query): @@ -24,7 +62,7 @@ class Google(commands.Cog): if not result.results: return await ctx.send("Er ging iets fout (Response {})".format(result.status_code)) - embed = create_google_embed(result) + embed = _create_google_embed(result) await ctx.reply(embed=embed, mention_author=False) diff --git a/cogs/slash/define_slash.py b/cogs/slash/define_slash.py deleted file mode 100644 index 55899d8..0000000 --- a/cogs/slash/define_slash.py +++ /dev/null @@ -1,25 +0,0 @@ -from discord.ext import commands -from dislash import SlashInteraction, slash_command, Option, OptionType - -from data.embeds.urban_dictionary import Definition -from startup.didier import Didier - - -class DefineSlash(commands.Cog): - def __init__(self, client: Didier): - self.client: Didier = client - - @slash_command(name="define", - description="Urban Dictionary", - options=[ - Option("query", "Search query", OptionType.STRING, required=True) - ], - guild_ids=[728361030404538488, 880175869841277008] - ) - async def _define_slash(self, interaction: SlashInteraction, query): - embed = Definition(query).to_embed() - await interaction.reply(embed=embed) - - -def setup(client: Didier): - client.add_cog(DefineSlash(client)) diff --git a/cogs/slash/google_slash.py b/cogs/slash/google_slash.py deleted file mode 100644 index fe9ba61..0000000 --- a/cogs/slash/google_slash.py +++ /dev/null @@ -1,29 +0,0 @@ -from discord.ext import commands -from dislash import slash_command, SlashInteraction, Option, OptionType -from functions.scrapers.google import google_search, create_google_embed -from startup.didier import Didier - - -class GoogleSlash(commands.Cog): - def __init__(self, client: Didier): - self.client: Didier = client - - @slash_command(name="google", - description="Google search", - options=[ - Option("query", "Search query", OptionType.STRING, required=True) - ], - guild_ids=[728361030404538488, 880175869841277008] - ) - async def _google_slash(self, interaction: SlashInteraction, query: str): - result = google_search(query) - - if not result.results: - return await interaction.reply("Er ging iets fout (Response {})".format(result.status_code)) - - embed = create_google_embed(result) - await interaction.reply(embed=embed) - - -def setup(client: Didier): - client.add_cog(GoogleSlash(client)) diff --git a/cogs/slash/translate_slash.py b/cogs/slash/translate_slash.py deleted file mode 100644 index 226aa0d..0000000 --- a/cogs/slash/translate_slash.py +++ /dev/null @@ -1,26 +0,0 @@ -from discord.ext import commands -from dislash import SlashInteraction, slash_command, Option, OptionType - -from data.embeds.translate import Translation -from startup.didier import Didier - - -class TranslateSlash(commands.Cog): - def __init__(self, client: Didier): - self.client: Didier = client - - @slash_command( - name="translate", - description="Google Translate", - options=[ - Option("text", "Tekst om te vertalen", OptionType.STRING, required=True), - Option("to", "Taal om naar te vertalen (default NL)", OptionType.STRING) - ] - ) - async def _translate_slash(self, interaction: SlashInteraction, text: str, to: str = "nl"): - translation = Translation(text=text, to=to.lower()) - await interaction.reply(embed=translation.to_embed()) - - -def setup(client: Didier): - client.add_cog(TranslateSlash(client)) diff --git a/cogs/translate.py b/cogs/translate.py index 74186b7..e607ca8 100644 --- a/cogs/translate.py +++ b/cogs/translate.py @@ -2,7 +2,7 @@ from decorators import help import discord from discord.ext import commands from enums.help_categories import Category -from functions.stringFormatters import title_case as tc +from functions.stringFormatters import titleCase as tc from googletrans import Translator, LANGUAGES import re diff --git a/data/embeds/translate.py b/data/embeds/translate.py deleted file mode 100644 index 86ade0e..0000000 --- a/data/embeds/translate.py +++ /dev/null @@ -1,54 +0,0 @@ -import discord -from googletrans import Translator, LANGUAGES -from functions.stringFormatters import title_case -from typing import Optional - - -class Translation: - def __init__(self, text: str, to: str): - self.text = text - self.to = to - self.embed: Optional[discord.Embed] = None - self.translation = None - - self.translate(text, to) - - def translate(self, query: str, to: str): - """ - Translate [query] into [to] - """ - try: - translator = Translator() - self.translation = translator.translate(query, to, "auto") - except ValueError as e: - message = str(e) - - if "destination" in message: - self._create_error_embed(f"{title_case(to)} is geen geldige taal.") - - raise e - - def _create_error_embed(self, message): - embed = discord.Embed(colour=discord.Colour.red()) - embed.set_author(name="Didier Translate") - embed.description = message - self.embed = embed - - def to_embed(self) -> discord.Embed: - # There's an error embed to show - if self.embed is not None: - return self.embed - - embed = discord.Embed(colour=discord.Colour.blue()) - embed.set_author(name="Didier Translate") - - language = self.translation.src - embed.add_field(name="Gedetecteerde taal", value=title_case(LANGUAGES[language])) - - if self.translation.extra_data["confidence"] is not None: - embed.add_field(name="Zekerheid", value="{}%".format(self.translation.extra_data["confidence"] * 100)) - - embed.add_field(name="Origineel ({})".format(self.translation.src.upper()), value=self.text, inline=False) - embed.add_field(name="Vertaling ({})".format(self.to.upper()), value=self.translation.text) - - return embed diff --git a/data/embeds/ufora.py b/data/embeds/ufora.py index 613c932..c445e1b 100644 --- a/data/embeds/ufora.py +++ b/data/embeds/ufora.py @@ -1,6 +1,6 @@ from datetime import datetime from discord import Embed, Colour -from functions.stringFormatters import leading_zero as lz +from functions.stringFormatters import leadingZero as lz from functions.timeFormatters import intToWeekday from markdownify import markdownify as md import pytz diff --git a/data/embeds/urban_dictionary.py b/data/embeds/urban_dictionary.py deleted file mode 100644 index c65017e..0000000 --- a/data/embeds/urban_dictionary.py +++ /dev/null @@ -1,113 +0,0 @@ -import os -from typing import Dict - -import discord -import requests - - -class Definition: - def __init__(self, query: str): - self.query = query - self.definition = Definition.lookup(query) - - @staticmethod - def lookup(word) -> Dict: - """ - Function that sends the API request to get the definition. - :param word: the woord to look up - :return: a dictionary representing the info of this word - """ - url = "https://mashape-community-urban-dictionary.p.rapidapi.com/define" - - querystring = {"term": word} - - headers = { - 'x-rapidapi-host': "mashape-community-urban-dictionary.p.rapidapi.com", - 'x-rapidapi-key': os.getenv("URBANDICTIONARY") - } - - try: - if word.lower() == "didier": - raise Exception - - response = requests.get(url, headers=headers, params=querystring).json()["list"] - - if len(response) > 0: - return {"word": response[0]["word"], "definition": response[0]["definition"], - "example": response[0]["example"], "thumbs_up": response[0]["thumbs_up"], - "thumbs_down": response[0]["thumbs_down"], "link": response[0]["permalink"], - "author": response[0]["author"]} - - # No valid response - return {} - except Exception: - return Definition.define_didier() - - @staticmethod - def clean_string(text: str): - """ - Function that cuts off definitions that are too long & strips out UD markdown - from an input string. - :param text: the input string to clean up - :return: the edited version of the string - """ - text = text.replace("[", "") - text = text.replace("]", "") - - if not text: - return "N/A" - - return text if len(text) < 1024 else text[:1021] + "..." - - @staticmethod - def ratio(dic) -> float: - """ - Function that alculates the upvote/downvote ratio of the definition. - :param dic: the dictionary representing the definition - :return: the upvote/downvote ratio (float) - """ - return (100 * int(dic["thumbs_up"])) / (int(dic["thumbs_up"]) + int(dic["thumbs_down"])) \ - if int(dic["thumbs_down"]) != 0 else 100.0 - - @staticmethod - def define_didier() -> Dict: - """ - Function that returns a stock dictionary to define Didier - in case people call it, or no definition was found. - :return: a dictionary that defines Didier - """ - return {"word": "Didier", "definition": "Didier", "example": "1: Didier\n2: Hmm?", "thumbs_up": 69420, - "thumbs_down": 0, "author": "Didier", - "link": "https://upload.wikimedia.org/wikipedia/commons/a/a5" - "/Didier_Reynders_in_Iranian_Parliament_02.jpg"} - - def to_embed(self) -> discord.Embed: - """ - Create an embed for this definition - """ - # No results found - if not self.definition: - return self._nothing_found_embed() - - embed = discord.Embed(colour=discord.Colour.from_rgb(220, 255, 0)) - embed.set_author(name="Urban Dictionary") - - embed.add_field(name="Woord", value=self.definition["word"], inline=True) - embed.add_field(name="Auteur", value=self.definition["author"], inline=True) - embed.add_field(name="Definitie", value=Definition.clean_string(self.definition["definition"]), inline=False) - embed.add_field(name="Voorbeeld", value=Definition.clean_string(self.definition["example"]), inline=False) - embed.add_field(name="Rating", value=str(round(Definition.ratio(self.definition), 2)) + "%") - embed.add_field(name="Link naar de volledige definitie", - value="[Urban Dictionary]({})".format(str(self.definition["link"]))) - - return embed - - def _nothing_found_embed(self) -> discord.Embed: - """ - Special embed when no results could be found - """ - embed = discord.Embed(colour=discord.Colour.red(), title=self.query[:256]) - embed.set_author(name="Urban Dictionary") - embed.description = "Geen resultaten gevonden" - - return embed diff --git a/functions/football.py b/functions/football.py index 59edf45..0648096 100644 --- a/functions/football.py +++ b/functions/football.py @@ -5,7 +5,7 @@ from datetime import datetime from enum import Enum from functions.timeFormatters import fromString from functions.scrapers.sporza import getJPLMatches, getJPLTable -from functions.stringFormatters import leading_zero +from functions.stringFormatters import leadingZero import re from requests import get import tabulate @@ -103,7 +103,7 @@ class Match: # No score to show yet, show time when the match starts if not self._hasStarted(): - return "{}:{}".format(leading_zero(str(self.start.hour)), leading_zero(str(self.start.minute))) + return "{}:{}".format(leadingZero(str(self.start.hour)), leadingZero(str(self.start.minute))) return "{} - {}".format(self.homeScore, self.awayScore) diff --git a/functions/scrapers/google.py b/functions/scrapers/google.py index a6e6546..71fec5d 100644 --- a/functions/scrapers/google.py +++ b/functions/scrapers/google.py @@ -1,21 +1,16 @@ -from typing import List +from typing import Optional, List -import discord from bs4 import BeautifulSoup from dataclasses import dataclass from requests import get -from urllib.parse import urlencode, unquote_plus +from urllib.parse import urlencode @dataclass class SearchResult: status_code: int - query: str results: List[str] - def __post_init__(self): - self.query = unquote_plus(self.query[2:]) - def google_search(query) -> SearchResult: """ @@ -31,7 +26,7 @@ def google_search(query) -> SearchResult: resp = get("https://www.google.com/search?{}&num=20&hl=en".format(query), headers=headers) if resp.status_code != 200: - return SearchResult(resp.status_code, query, []) + return SearchResult(resp.status_code, []) bs = BeautifulSoup(resp.text, "html.parser") @@ -56,34 +51,7 @@ def google_search(query) -> SearchResult: # Map to urls links = [] - for (l, t) in results: - links.append(f"[{t}]({l})") + for (link, title) in results: + links.append(f"[{title}]({link})") - return SearchResult(200, query, links[:10]) - - -def create_google_embed(result: SearchResult) -> discord.Embed: - embed = discord.Embed(colour=discord.Colour.blue()) - embed.set_author(name="Google Search") - - # Empty list of results - if len(result.results) == 0: - embed.colour = discord.Colour.red() - embed.description = "Geen resultaten gevonden." - return embed - - # Add results into a field - links = [] - - for index, link in enumerate(result.results): - links.append(f"{index + 1}: {link}") - - embed.description = "\n".join(links) - - # Add query into embed - if len(result.query) > 256: - embed.title = result.query[:253] + "..." - else: - embed.title = result.query - - return embed + return SearchResult(200, links[:10]) diff --git a/functions/stringFormatters.py b/functions/stringFormatters.py index b1646cf..c38c3c3 100644 --- a/functions/stringFormatters.py +++ b/functions/stringFormatters.py @@ -1,4 +1,4 @@ -def title_case(string): +def titleCase(string): return " ".join(capitalize(word) for word in string.split(" ")) @@ -8,7 +8,7 @@ def capitalize(string): return string[0].upper() -def leading_zero(string, size=2): +def leadingZero(string, size=2): string = str(string) while len(string) < size: string = "0" + string diff --git a/functions/timeFormatters.py b/functions/timeFormatters.py index 1d7788a..4460156 100644 --- a/functions/timeFormatters.py +++ b/functions/timeFormatters.py @@ -161,14 +161,14 @@ def fromString(timeString: str, formatString="%d/%m/%Y", tzinfo=pytz.timezone("E def fromArray(data: List[int]) -> datetime: - day = stringFormatters.leading_zero(str(data[0])) - month = stringFormatters.leading_zero(str(data[1])) + day = stringFormatters.leadingZero(str(data[0])) + month = stringFormatters.leadingZero(str(data[1])) year = str(data[2]) if len(data) == 6: - hour = stringFormatters.leading_zero(str(data[3])) - minute = stringFormatters.leading_zero(str(data[4])) - second = stringFormatters.leading_zero(str(data[5])) + hour = stringFormatters.leadingZero(str(data[3])) + minute = stringFormatters.leadingZero(str(data[4])) + second = stringFormatters.leadingZero(str(data[5])) return fromString(f"{day}/{month}/{year} {hour}:{minute}:{second}", formatString="%d/%m/%Y %H:%M:%S") diff --git a/startup/didier.py b/startup/didier.py index 850080c..9f5a314 100644 --- a/startup/didier.py +++ b/startup/didier.py @@ -47,24 +47,9 @@ class Didier(commands.Bot): self.load_extension(f"cogs.{ext}") # Load all remaining cogs - self._init_directory("./cogs") - - def _init_directory(self, path: str): - """ - Load all cogs from a directory - """ - # Path to pass into load_extension - load_path = path[2:].replace("/", ".") - - for file in os.listdir(path): - # Python file - if file.endswith(".py"): - if not file.startswith(self._preload): - self.load_extension(f"{load_path}.{file[:-3]}") - elif os.path.isdir(new_path := f"{path}/{file}"): - # Subdirectory - # Also walrus operator hype - self._init_directory(new_path) + for file in os.listdir("./cogs"): + if file.endswith(".py") and not (file.startswith(self._preload)): + self.load_extension("cogs.{}".format(file[:-3])) async def on_ipc_ready(self): print("IPC server is ready.")