Compare commits

...

4 Commits

Author SHA1 Message Date
Stijn De Clercq ef547a7090 Translate slash command 2021-09-03 18:53:05 +02:00
Stijn De Clercq 358f8693dd Clean up define, create define slash command 2021-09-03 18:26:26 +02:00
Stijn De Clercq c47f908e57 Show search result in google embed 2021-09-03 18:05:23 +02:00
Stijn De Clercq 831459a321 Separate loading slash commands from normal commands, split slash commands to separate cogs, make init_extensions support directories 2021-09-03 17:57:45 +02:00
17 changed files with 325 additions and 156 deletions

View File

@ -163,8 +163,8 @@ class Birthdays(commands.Cog):
# Create a datetime object for this birthday
timeString = "{}/{}/{}".format(
stringFormatters.leadingZero(str(day)),
stringFormatters.leadingZero(str(month)),
stringFormatters.leading_zero(str(day)),
stringFormatters.leading_zero(str(month)),
year
)

View File

@ -1,11 +1,8 @@
import os
from data.embeds.urban_dictionary import Definition
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):
@ -19,99 +16,15 @@ 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, *words):
async def define(self, ctx, *, query):
"""
Command that looks up the definition of a word in the Urban Dictionary.
:param ctx: Discord Context
:param words: Word(s) to look up
:param query: Word(s) to look up
"""
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"])))
embed = Definition(query).to_embed()
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))

View File

@ -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.titleCase(cat[0]) for cat in faq.getCategories()]
resp = [stringFormatters.title_case(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.titleCase(category)))
embed.set_author(name="FAQ {}".format(stringFormatters.title_case(category)))
# Add everything into the embed
for i, pair in enumerate(resp):

View File

@ -120,7 +120,7 @@ class Fun(commands.Cog):
memeList = memes.getAllMemes()
# Turn the list into a list of [Name: fields]
memeList = [": ".join([stringFormatters.titleCase(meme[1]),
memeList = [": ".join([stringFormatters.title_case(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()),

View File

@ -1,30 +1,8 @@
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, 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
from functions.scrapers.google import google_search, create_google_embed
class Google(commands.Cog):
@ -35,22 +13,6 @@ 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):
@ -62,7 +24,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)

View File

@ -0,0 +1,25 @@
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))

View File

@ -0,0 +1,29 @@
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))

View File

@ -0,0 +1,26 @@
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))

View File

@ -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 titleCase as tc
from functions.stringFormatters import title_case as tc
from googletrans import Translator, LANGUAGES
import re

View File

@ -0,0 +1,54 @@
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

View File

@ -1,6 +1,6 @@
from datetime import datetime
from discord import Embed, Colour
from functions.stringFormatters import leadingZero as lz
from functions.stringFormatters import leading_zero as lz
from functions.timeFormatters import intToWeekday
from markdownify import markdownify as md
import pytz

View File

@ -0,0 +1,113 @@
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

View File

@ -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 leadingZero
from functions.stringFormatters import leading_zero
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(leadingZero(str(self.start.hour)), leadingZero(str(self.start.minute)))
return "{}:{}".format(leading_zero(str(self.start.hour)), leading_zero(str(self.start.minute)))
return "{} - {}".format(self.homeScore, self.awayScore)

View File

@ -1,16 +1,21 @@
from typing import Optional, List
from typing import List
import discord
from bs4 import BeautifulSoup
from dataclasses import dataclass
from requests import get
from urllib.parse import urlencode
from urllib.parse import urlencode, unquote_plus
@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:
"""
@ -26,7 +31,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, [])
return SearchResult(resp.status_code, query, [])
bs = BeautifulSoup(resp.text, "html.parser")
@ -51,7 +56,34 @@ def google_search(query) -> SearchResult:
# Map to urls
links = []
for (link, title) in results:
links.append(f"[{title}]({link})")
for (l, t) in results:
links.append(f"[{t}]({l})")
return SearchResult(200, links[:10])
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

View File

@ -1,4 +1,4 @@
def titleCase(string):
def title_case(string):
return " ".join(capitalize(word) for word in string.split(" "))
@ -8,7 +8,7 @@ def capitalize(string):
return string[0].upper()
def leadingZero(string, size=2):
def leading_zero(string, size=2):
string = str(string)
while len(string) < size:
string = "0" + string

View File

@ -161,14 +161,14 @@ def fromString(timeString: str, formatString="%d/%m/%Y", tzinfo=pytz.timezone("E
def fromArray(data: List[int]) -> datetime:
day = stringFormatters.leadingZero(str(data[0]))
month = stringFormatters.leadingZero(str(data[1]))
day = stringFormatters.leading_zero(str(data[0]))
month = stringFormatters.leading_zero(str(data[1]))
year = str(data[2])
if len(data) == 6:
hour = stringFormatters.leadingZero(str(data[3]))
minute = stringFormatters.leadingZero(str(data[4]))
second = stringFormatters.leadingZero(str(data[5]))
hour = stringFormatters.leading_zero(str(data[3]))
minute = stringFormatters.leading_zero(str(data[4]))
second = stringFormatters.leading_zero(str(data[5]))
return fromString(f"{day}/{month}/{year} {hour}:{minute}:{second}", formatString="%d/%m/%Y %H:%M:%S")

View File

@ -47,9 +47,24 @@ class Didier(commands.Bot):
self.load_extension(f"cogs.{ext}")
# Load all remaining cogs
for file in os.listdir("./cogs"):
if file.endswith(".py") and not (file.startswith(self._preload)):
self.load_extension("cogs.{}".format(file[:-3]))
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)
async def on_ipc_ready(self):
print("IPC server is ready.")