follow contribution guidelines

This commit is contained in:
LBlend committed 2022-11-17 22:03:23 +01:00
1 parent 4ea61bcfad
commit 1ee4b92ad7
19 files changed
+1092 -313

No files matched your search

+126 -30
View File
@@ -10,8 +10,7 @@ from cogs.utils import embed_templates
class Anime(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
"""View information about different media on Anilist"""
anilist = app_commands.Group(name='anilist', description='Hent informasjon fra Anilist')
anilist_profile = app_commands.Group(parent=anilist, name='profil', description='Hent informasjon om en bruker på Anilist')
@@ -22,12 +21,13 @@ class Anime(commands.Cog):
Parameters
----------
color: The color string returned from the Anilist API
color (str): The color string returned from the Anilist API
Returns
----------
(int): The color in hex for use in discord embeds
"""
colors = {
'blue': 0x3db4f2,
'purple': 0xc063ff,
@@ -37,6 +37,7 @@ class Anime(commands.Cog):
'green': 0x4CCA51,
'gray': 0x677B94
}
return colors.get(color, 0x677B94)
def __convert_media_format(self, media_format: str) -> str:
@@ -45,12 +46,13 @@ class Anime(commands.Cog):
Parameters
----------
media_format: The english media format name returned from the Anilist API
media_format (str): The english media format name returned from the Anilist API
Returns
----------
(str): The media format name in norwegian. If a translation doesn't exist it returns the english name
"""
media_formats = {
'TV': 'TV-Serie',
'TV_SHORT': 'Kort TV-Serie',
@@ -69,12 +71,13 @@ class Anime(commands.Cog):
Parameters
----------
language_name: The english language name returned from the Anilist API
language_name (str): The english language name returned from the Anilist API
Returns
----------
(str): The language name in norwegian. If a translation doesn't exist it returns the english name
"""
languages = {
'JAPANESE': 'Japansk',
'ENGLISH': 'Engelsk',
@@ -87,6 +90,7 @@ class Anime(commands.Cog):
'HEBREW': 'Hebraisk',
'HUNGARIAN': 'Ungarsk'
}
return languages.get(language_name, language_name)
def __convert_role_names(self, role_name: str) -> str:
@@ -95,7 +99,7 @@ class Anime(commands.Cog):
Parameters
----------
role_name: The english role name returned from the Anilist API
role_name (str): The english role name returned from the Anilist API
Returns
----------
@@ -118,18 +122,20 @@ class Anime(commands.Cog):
Parameters
----------
status: The english status name returned from the Anilist API
status (str): The english status name returned from the Anilist API
Returns
----------
(str): The status name in norwegian. If a translation doesn't exist it returns the english name
"""
statuses = {
'FINISHED': 'Fullt utgitt',
'RELEASING': 'Pågående',
'NOT_YET_RELEASED': 'Ikke utgitt enda',
'CANCELLED': 'Kansellert'
}
return statuses.get(status, status)
def __remove_html(self, text: str) -> str:
@@ -144,8 +150,10 @@ class Anime(commands.Cog):
----------
(str): The input string without HTML tags
"""
compiled = re.compile(r'<.*?>')
clean_text = re.sub(compiled, '', text)
return clean_text
async def __request_anilist(self, interaction: discord.Interaction, query: str, variables: dict, key: str) -> tuple[dict, str] | tuple[None, None]:
@@ -154,14 +162,16 @@ class Anime(commands.Cog):
Parameters
----------
query: The GraphQL query
variables: The variables for the query
key: The key to return from the response
interaction (discord.Interaction): Slash command context object
query (str): The GraphQL query
variables (str): The variables for the query
key (str): The key to return from the response
Returns
----------
(dict): The response from the Anilist API
(tuple[dict, str] | tuple[None, None]): The response from the Anilist API
"""
try:
url = 'https://graphql.anilist.co'
response = requests.post(url, json={'query': query, 'variables': variables}, timeout=10)
@@ -181,12 +191,13 @@ class Anime(commands.Cog):
Parameters
----------
media: The list of media returned from the Anilist API
media (list): The list of media returned from the Anilist API
Returns
----------
(str): The constructed string
"""
favorite_media = []
for node in media:
try:
@@ -196,6 +207,7 @@ class Anime(commands.Cog):
favorite_media.append(f'[{anime_name}]({anime_url}){nsfwtag}')
except KeyError:
pass
return ' | '.join(favorite_media)
def __construct_favorite_entity_string(self, entities: list, studio: bool = False) -> str:
@@ -204,23 +216,26 @@ class Anime(commands.Cog):
Parameters
----------
entity: The list of entities returned from the Anilist API
entities (list): The list of entities returned from the Anilist API
studio (bool): Whether the entities are studios or not
Returns
----------
(str): The constructed string
"""
favortie_entities = []
for entity in entities:
try:
if studio:
entity_name = entity['name']
else:
entity_name = entity['name']["full"]
entity_name = entity['name']['full']
entity_url = entity['siteUrl']
favortie_entities.append(f'[{entity_name}]({entity_url})')
except KeyError:
pass
return ' | '.join(favortie_entities)
def __construct_release_schedule_string(self, numbers: dict) -> str:
@@ -235,16 +250,17 @@ class Anime(commands.Cog):
----------
(str): The constructed string
"""
# Release and end date formatting
if numbers['start_day'] != '?' and numbers['start_month'] != '?' and numbers['start_year'] != '?':
release_date = datetime(numbers['start_year'], numbers['start_month'], numbers['start_day'])
release_date = discord.utils.format_dt(release_date, style="d")
release_date = discord.utils.format_dt(release_date, style='d')
else:
release_date = f'{numbers["start_day"]}.{numbers["start_month"]}.{numbers["start_year"]}'
if numbers['end_day'] != '?' and numbers['end_month'] != '?' and numbers['end_year'] != '?':
end_date = datetime(numbers['end_year'], numbers['end_month'], numbers['end_day'])
end_date = discord.utils.format_dt(end_date, style="d")
if numbers["end_day"] != '?' and numbers["end_month"] != '?' and numbers["end_year"] != '?':
end_date = datetime(numbers["end_year"], numbers["end_month"], numbers["end_day"])
end_date = discord.utils.format_dt(end_date, style='d')
else:
end_date = f'{numbers["end_day"]}.{numbers["end_month"]}.{numbers["end_year"]}'
@@ -259,6 +275,15 @@ class Anime(commands.Cog):
@app_commands.checks.cooldown(1, 5)
@anilist_profile.command(name='generelt', description='Viser informasjon om en Anilistprofil')
async def anilist_profile_general(self, interaction: discord.Interaction, bruker: str):
"""
Shows general information about a user's Anilist profile
Parameters
----------
interaction (discord.Interaction): Slash command context object
bruker (str): The user to get information about
"""
# GraphQL
query = """
query ($name: String) {
@@ -388,6 +413,15 @@ class Anime(commands.Cog):
@app_commands.checks.cooldown(1, 5)
@anilist_profile.command(name='anime', description='Se statistikk om animetittingen til en bruker')
async def anilist_profile_anime_stats(self, interaction: discord.Interaction, bruker: str):
"""
Shows anime viewing statistics from a user's Anilist profile
Parameters
----------
interaction (discord.Interaction): Slash command context object
bruker (str): The user to get information about
"""
# GraphQL
query = """
query ($name: String) {
@@ -487,6 +521,15 @@ class Anime(commands.Cog):
@app_commands.checks.cooldown(1, 5)
@anilist_profile.command(name='manga', description='Se statistikk om mangalesingen til en bruker')
async def anilist_profile_manga_stats(self, interaction: discord.Interaction, bruker: str):
"""
Shows manga reading statistics from a user's Anilist profile
Parameters
----------
interaction (discord.Interaction): Slash command context object
bruker (str): The user to get information about
"""
# GraphQL
query = """
query ($name: String) {
@@ -588,8 +631,17 @@ class Anime(commands.Cog):
@app_commands.checks.cooldown(1, 5)
@anilist.command(name='anime', description='Hent informasjon om en anime')
async def anilist_anime(self, interaction: discord.Interaction, navn: str):
"""
Shows information about an anime
Parameters
----------
interaction (discord.Interaction): Slash command context object
navn (str): The name of the anime to fetch information about
"""
# GraphQL
query = '''
query = """
query ($search: String, $isMain: Boolean) {
Media (search: $search, type: ANIME) {
siteUrl
@@ -642,7 +694,7 @@ class Anime(commands.Cog):
}
}
}
'''
"""
variables = {
'search': navn,
'isMain': True
@@ -747,7 +799,16 @@ class Anime(commands.Cog):
@app_commands.checks.cooldown(1, 5)
@anilist.command(name='manga', description='Hent informasjon om en manga')
async def anilist_manga(self, interaction: discord.Interaction, navn: str):
query = '''
"""
Shows information about a manga
Parameters
----------
interaction (discord.Interaction): Slash command context object
navn (str): The name of the manga to fetch information about
"""
query = """
query ($search: String) {
Media (search: $search, type: MANGA) {
siteUrl
@@ -794,7 +855,7 @@ class Anime(commands.Cog):
}
}
}
'''
"""
variables = {
'search': navn
}
@@ -880,7 +941,16 @@ class Anime(commands.Cog):
@app_commands.checks.cooldown(1, 5)
@anilist.command(name='karakter', description='Hent informasjon om en karakter')
async def anilist_character(self, interaction: discord.Interaction, navn: str):
query = '''
"""
Shows information about a character
Parameters
----------
interaction (discord.Interaction): Slash command context object
navn (str): The name of the character to fetch information about
"""
query = """
query ($search: String) {
Character (search: $search) {
name {
@@ -915,7 +985,7 @@ class Anime(commands.Cog):
}
}
}
'''
"""
variables = {
'search': navn
}
@@ -968,7 +1038,16 @@ class Anime(commands.Cog):
@app_commands.checks.cooldown(1, 5)
@anilist.command(name='skaper', description='Hent informasjon om en skaper')
async def anilist_creator(self, interaction: discord.Interaction, navn: str):
query = '''
"""
Shows information about a creator
Parameters
----------
interaction (discord.Interaction): Slash command context object
navn (str): The name of the creator to fetch information about
"""
query = """
query ($search: String) {
Staff(search: $search) {
name {
@@ -1007,7 +1086,7 @@ class Anime(commands.Cog):
}
}
}
'''
"""
variables = {
'search': navn
}
@@ -1061,7 +1140,16 @@ class Anime(commands.Cog):
@app_commands.checks.cooldown(1, 5)
@anilist.command(name='studio', description='Hent informasjon om et studio')
async def anilist_studio(self, interaction: discord.Interaction, navn: str):
query = '''
"""
Shows information about a studio
Parameters
----------
interaction (discord.Interaction): Slash command context object
navn (str): The name of the studio to fetch information about
"""
query = """
query ($search: String) {
Studio(search: $search) {
name
@@ -1081,7 +1169,7 @@ class Anime(commands.Cog):
}
}
}
'''
"""
variables = {
'search': navn
}
@@ -1101,7 +1189,7 @@ class Anime(commands.Cog):
popular_media.append(f'- [{media_name}]({media_url}){nsfwtag}')
popular_media = '\n'.join(popular_media)
query2 = '''
query2 = """
query ($search: String) {
Studio(search: $search) {
media(sort: START_DATE_DESC) {
@@ -1116,7 +1204,7 @@ class Anime(commands.Cog):
}
}
}
'''
"""
data = requests.post('https://graphql.anilist.co', json={'query': query2, 'variables': variables}, timeout=10).json()
data = data['data']['Studio']
@@ -1146,4 +1234,12 @@ class Anime(commands.Cog):
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
await bot.add_cog(Anime(bot))
+126 -41
View File
@@ -10,12 +10,21 @@ from cogs.utils import discord_utils, embed_templates
class Birthday(commands.Cog):
"""Save the birthday of Discord users and allow them to see the birthdays of other users"""
def __init__(self, bot: commands.Bot):
"""
Parameters
----------
bot (commands.Bot): The bot instance
"""
self.bot = bot
self.cursor = self.bot.db_connection.cursor()
def init_db(self):
"""Create the necessary tables for the birthday cog to work."""
"""Create the necessary tables for the birthday cog to work"""
self.cursor.execute(
"""
CREATE TABLE IF NOT EXISTS birthdays (
@@ -27,22 +36,43 @@ class Birthday(commands.Cog):
self.bot.db_connection.commit()
def __fetch_user_birthday(self, user_id: int) -> datetime | None:
"""Fetch the birthday of a user from the database"""
self.cursor.execute("SELECT birthday FROM birthdays WHERE discord_id = (%s)", (user_id,))
"""
Fetch the birthday of a user in the database
Parameters
----------
user_id (int): The Discord user ID
Returns
----------
(datetime | None): The birthday of the user
"""
self.cursor.execute('SELECT birthday FROM birthdays WHERE discord_id = (%s)', (user_id,))
result = self.cursor.fetchone()
if result:
birthday = result[0]
return datetime(birthday.year, birthday.month, birthday.day)
def __fetch_user_next_birthday(self, user_id: int) -> datetime:
"""Get date of next birthday of a user"""
"""
Get date of next birthday for a user
Parameters
----------
user_id (int): The Discord user ID
Returns
----------
(datetime): The date of the next birthday
"""
self.cursor.execute(
"""
SELECT *, CAST(birthday + ((EXTRACT(YEAR FROM AGE(birthday)) + 1) * interval '1' YEAR) AS DATE) AS next_birthday
FROM birthdays
WHERE discord_id = %s
""",
(user_id,),
""", (user_id,)
)
results = self.cursor.fetchone()
if results:
@@ -52,7 +82,14 @@ class Birthday(commands.Cog):
return datetime.now() # This will never happen unless a database error occurs. Keeping the type checker happy
def __fetch_next_birthdays(self) -> list[tuple[int, datetime, datetime]]:
"""Fetch the 5 first future birthdays of all users in the database"""
"""
Fetch the 5 first future birthdays of all users in the database
Returns
----------
(list[tuple[int, datetime, datetime]]): A list of tuples containing the user ID, the date of birth and the next birthday
"""
self.cursor.execute(
"""
SELECT *, CAST(birthday + ((EXTRACT(YEAR FROM AGE(birthday)) + 1) * interval '1' YEAR) AS DATE) AS next_birthday
@@ -71,8 +108,16 @@ class Birthday(commands.Cog):
return results
def __set_user_birthday(self, user_id: int, birthday: datetime) -> None:
"""Iset the birthday of a user in the database. If it already exists, update it."""
def __set_user_birthday(self, user_id: int, birthday: datetime):
"""
Set the birthday of a user in the database. If it already exists, update it.
Parameters
----------
user_id (int): The Discord user ID
birthday (datetime): The birthday of the user
"""
try:
self.cursor.execute(
"""
@@ -82,10 +127,10 @@ class Birthday(commands.Cog):
self.bot.db_connection.commit()
except psycopg2.errors.UniqueViolation:
self.bot.db_connection.rollback()
self.cursor.execute("UPDATE birthdays SET birthday = %s WHERE discord_id = %s", (birthday, user_id))
self.cursor.execute('UPDATE birthdays SET birthday = %s WHERE discord_id = %s', (birthday, user_id))
self.bot.db_connection.commit()
# @aiocron.crontab("0 0 * * *")
# @aiocron.crontab('0 0 * * *')
# async def __check_birthdays(self):
# """Check if it's someone's birthday every day at midgnight and send a greeting if it is."""
# await asyncio.sleep(1) # Prevent sending message before date has really changed
@@ -106,54 +151,79 @@ class Birthday(commands.Cog):
# for birthday in birthdays:
# user = self.bot.get_user(birthday[0])
# if user:
# await channel.send(f"Gratulrer med dagen {user.mention}!")
# await channel.send(f'Gratulrer med dagen {user.mention}!')
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 5)
@app_commands.command()
async def settbursdag(self, interaction: discord.Interaction, dag: int, måned: int, år: int):
"""Lagrer din bursdag i databasen"""
@app_commands.command(name='settbursdag', description='Lagrer din bursdag i databasen')
async def birthday_set(self, interaction: discord.Interaction, dag: int, måned: int, år: int):
"""
Allows the user to set their birthday in the database.
Parameters
----------
interaction (discord.Interaction): Slash command context object
dag (int): Day of the month
måned (int): Month of the year
år (int): Year
"""
try:
date = datetime(år, måned, dag)
except ValueError:
return await interaction.response.send_message(
embed=embed_templates.error_fatal(interaction, text="ikke en gyldig dato, gjøk!"),
embed=embed_templates.error_fatal(interaction, text='ikke en gyldig dato, gjøk!'),
ephemeral=True
)
if date.year < 1970:
return await interaction.response.send_message(
embed=embed_templates.error_fatal(interaction, text="Ok boomer, men nei. Hvorfor? Unix timestamps. Google it"),
embed=embed_templates.error_fatal(interaction, text='Ok boomer, men nei. Hvorfor? Unix timestamps. Google it'),
ephemeral=True
)
if date > datetime.now():
return await interaction.response.send_message(
embed=embed_templates.error_fatal(interaction, text="Du kan ikke sette en fremtidig dato!"),
embed=embed_templates.error_fatal(interaction, text='Du kan ikke sette en fremtidig dato!'),
ephemeral=True
)
self.__set_user_birthday(interaction.user.id, date)
embed = embed_templates.success(interaction, text=f"Bursdag satt til {discord.utils.format_dt(date, style='D')}")
embed = embed_templates.success(interaction, text=f'Bursdag satt til {discord.utils.format_dt(date, style="D")}')
await interaction.response.send_message(embed=embed)
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 5)
@app_commands.command()
async def fjernbursdag(self, interaction: discord.Interaction):
"""Fjerner bursdagen din fra databasen"""
self.cursor.execute("DELETE FROM birthdays WHERE discord_id = (%s)", (interaction.user.id,))
@app_commands.command(name='fjernbursdag', description='Fjerner bursdagen din fra databasen')
async def birthday_remove(self, interaction: discord.Interaction):
"""
Removes the invoking user's birthday from the database
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
self.cursor.execute('DELETE FROM birthdays WHERE discord_id = (%s)', (interaction.user.id,))
self.bot.db_connection.commit()
embed = embed_templates.success(interaction, text="Bursdag fjernet")
embed = embed_templates.success(interaction, text='Bursdag fjernet')
await interaction.response.send_message(embed=embed)
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 5)
@app_commands.command()
async def bursdag(self, interaction: discord.Interaction, bruker: discord.Member | discord.User | None = None):
"""Viser bursdagen til en bruker. Om ingen er gitt, vises din egen bursdag."""
@app_commands.command(name='bursdag', description='Viser bursdagen til en bruker. Om ingen er gitt, vises din egen')
async def birthday_show(self, interaction: discord.Interaction, bruker: discord.Member | discord.User | None = None):
"""
Shows the birthday of a user. If none is given, shows the invoking user's one.
Parameters
----------
interaction (discord.Interaction): Slash command context object
bruker (discord.Member | discord.User | None): The user to show the birthday of. Defaults to None.
"""
if not bruker:
bruker = interaction.user
@@ -161,7 +231,7 @@ class Birthday(commands.Cog):
if not user:
return await interaction.response.send_message(
embed=embed_templates.error_fatal(interaction, text="Brukeren har ikke registrert bursdagen sin")
embed=embed_templates.error_fatal(interaction, text='Brukeren har ikke registrert bursdagen sin')
)
# Current age information
@@ -176,24 +246,31 @@ class Birthday(commands.Cog):
embed = discord.Embed(description=bruker.mention, color=discord_utils.get_color(bruker))
embed.set_thumbnail(url=bruker.display_avatar)
embed.set_author(name=bruker.name, icon_url=bruker.display_avatar)
embed.add_field(name="Bursdag", value=discord.utils.format_dt(birthday, style="D"))
embed.add_field(name="Hvor gammel?", value=f"{years_old} år\n({days_old} dager)", inline=False)
embed.add_field(name="Neste bursdag om", value=f"{next_birthday_days} dager", inline=False)
embed.add_field(name='Bursdag', value=discord.utils.format_dt(birthday, style='D'))
embed.add_field(name='Hvor gammel?', value=f'{years_old} år\n({days_old} dager)', inline=False)
embed.add_field(name='Neste bursdag om', value=f'{next_birthday_days} dager', inline=False)
embed_templates.default_footer(interaction, embed)
await interaction.response.send_message(embed=embed)
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 5)
@app_commands.command()
async def kommendebursdager(self, interaction: discord.Interaction):
"""Se opptil de 5 neste bursdagene i UiO Gaming"""
@app_commands.command(name='kommendebursdager', description='Viser en liste over de opptil 5 kommende bursdager i serveren')
async def birthdays_upcoming(self, interaction: discord.Interaction):
"""
Lists up to 5 upcoming birthdays of users in the server.
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
next_birthdays = self.__fetch_next_birthdays()
if not next_birthdays:
return await interaction.response.send_message(embed=embed_templates.error_fatal(interaction, text="Ingen bursdager"))
return await interaction.response.send_message(embed=embed_templates.error_fatal(interaction, text='Ingen bursdager'))
birthday_string = ""
birthday_string = ''
for user in next_birthdays:
user_id, _, next_birthday = user
try:
@@ -201,17 +278,25 @@ class Birthday(commands.Cog):
except (discord.NotFound, discord.HTTPException):
continue
timestamp = discord.utils.format_dt(next_birthday, style="D")
relative_timestamp = discord.utils.format_dt(next_birthday, style="R")
birthday_string += f"{discord_user.name}#{discord_user.discriminator} - {timestamp} ({relative_timestamp})\n"
timestamp = discord.utils.format_dt(next_birthday, style='D')
relative_timestamp = discord.utils.format_dt(next_birthday, style='R')
birthday_string += f'{discord_user.name}#{discord_user.discriminator} - {timestamp} ({relative_timestamp})\n'
if not birthday_string:
return await interaction.response.send_message(embed=embed_templates.error_fatal(interaction, text="Ingen bursdager"))
return await interaction.response.send_message(embed=embed_templates.error_fatal(interaction, text='Ingen bursdager'))
embed = discord.Embed(title="Kommende bursdager", description=birthday_string)
embed = discord.Embed(title='Kommende bursdager', description=birthday_string)
embed_templates.default_footer(interaction, embed)
await interaction.response.send_message(embed=embed)
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
await bot.add_cog(Birthday(bot))
+45 -10
View File
@@ -11,14 +11,29 @@ from cogs.utils import embed_templates
class BotInfo(commands.Cog):
"""View information about the bot"""
def __init__(self, bot: commands.Bot):
"""
Parameters
----------
bot (commands.Bot): The bot instance
"""
self.bot = bot
@app_commands.checks.bot_has_permissions(embed_links=True, external_emojis=True)
@app_commands.checks.cooldown(1, 2)
@app_commands.command()
@app_commands.command(name='botinfo', description='Se informajson om botten')
async def botinfo(self, interaction: discord.Interaction):
"""Viser informasjon om bot"""
"""
View information about the bot
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
# Dev user info
dev = await self.bot.fetch_user(170506717140877312)
@@ -78,9 +93,15 @@ class BotInfo(commands.Cog):
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@app_commands.command()
async def oppetid(self, interaction: discord.Interaction):
"""Viser hvor lenge bot har vært kjørende"""
@app_commands.command(name='oppetid', description='Se hvor lenge botten har kjørt')
async def uptime(self, interaction: discord.Interaction):
"""
View the bot's uptime
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
embed = discord.Embed(color=interaction.client.user.color)
embed.add_field(name='🔌 Oppetid', value=self.__get_uptime())
@@ -89,9 +110,16 @@ class BotInfo(commands.Cog):
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@app_commands.command()
@app_commands.command(name='ping', description='Se botten sin nåværende ping')
async def ping(self, interaction: discord.Interaction):
"""Viser bot sin ping"""
"""
View the bot's ping
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
embed = discord.Embed(color=interaction.client.user.color)
embed.add_field(
name='📶 Ping',
@@ -108,19 +136,18 @@ class BotInfo(commands.Cog):
----------
(int) The bot's ping in milliseconds
"""
return int(self.bot.latency * 1000)
def __get_uptime(self) -> str:
"""
Returns the current uptime of the bot in string format
Parameters
----------
Returns
----------
(str) The bot's uptime in human readable format
"""
now = time()
diff = int(now - self.bot.uptime)
days, remainder = divmod(diff, 24 * 60 * 60)
@@ -131,4 +158,12 @@ class BotInfo(commands.Cog):
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
await bot.add_cog(BotInfo(bot))
+22 -22
View File
@@ -69,7 +69,7 @@ class SocialCredit(commands.Cog):
def add_new_citizen(func):
async def wrapper(*args, **kwargs):
self = args[0]
self.cursor.execute("SELECT user_id FROM social_credit WHERE user_id = %s", (args[1],))
self.cursor.execute('SELECT user_id FROM social_credit WHERE user_id = %s', (args[1],))
if not self.cursor.fetchone():
self._add_citizen(args[1])
await func(*args, **kwargs)
@@ -100,9 +100,9 @@ class SocialCredit(commands.Cog):
async def get_leaderboard(self, ctx, page, worst=False):
if worst:
keyword = "ASC"
keyword = 'ASC'
else:
keyword = "DESC"
keyword = 'DESC'
self.cursor.execute(
f"""
@@ -113,13 +113,13 @@ class SocialCredit(commands.Cog):
result = self.cursor.fetchall()
if not result:
return await ctx.send(embed=embed_templates.error_fatal(ctx, "Ingen brukere er registrert i databasen"))
return await ctx.send(embed=embed_templates.error_fatal(ctx, 'Ingen brukere er registrert i databasen'))
output_list = []
for i, row in enumerate(result):
user = ctx.guild.get_member(row[0])
if user:
output_list.append(f"{i+1}. {user.name}#{user.discriminator} - `{row[1]}` poeng")
output_list.append(f'{i+1}. {user.name}#{user.discriminator} - `{row[1]}` poeng')
return misc_utils.paginator(output_list, int(page))
@@ -134,7 +134,7 @@ class SocialCredit(commands.Cog):
@add_new_citizen
async def social_punishment(self, user_id, points):
print(f"{points} points deducted from {user_id}")
print(f'{points} points deducted from {user_id}')
self.cursor.execute(
"""
UPDATE social_credit
@@ -147,7 +147,7 @@ class SocialCredit(commands.Cog):
@add_new_citizen
async def social_reward(self, user_id, points):
print(f"{points} points given to {user_id}")
print(f'{points} points given to {user_id}')
self.cursor.execute(
"""
UPDATE social_credit
@@ -164,17 +164,17 @@ class SocialCredit(commands.Cog):
if not bruker:
bruker = ctx.author
self.cursor.execute("SELECT * FROM social_credit WHERE user_id = %s", (bruker.id,))
self.cursor.execute('SELECT * FROM social_credit WHERE user_id = %s', (bruker.id,))
result = self.cursor.fetchone()
if not result:
return await ctx.send(
embed=embed_templates.error_fatal(ctx, f"{bruker.mention} er ikke registrert i databasen")
embed=embed_templates.error_fatal(ctx, f'{bruker.mention} er ikke registrert i databasen')
)
db_user = CreditUser(*result)
embed = discord.Embed(description=(f"{bruker.mention} har `{db_user.credit_score}` social credits"))
embed = discord.Embed(description=(f'{bruker.mention} har `{db_user.credit_score}` social credits'))
await ctx.send(embed=embed)
@commands.command()
@@ -185,13 +185,13 @@ class SocialCredit(commands.Cog):
page = 0
page_data = await self.get_leaderboard(ctx, page)
output_content = "\n".join(page_data["page_content"])
output_content = '\n'.join(page_data['page_content'])
embed = discord.Embed(title="Social credit leaderboard", description=output_content)
embed.set_footer(text=f"Side {page_data['page']}/{page_data['pagecount']}")
embed = discord.Embed(title='Social credit leaderboard', description=output_content)
embed.set_footer(text=f'Side {page_data['page']}/{page_data['pagecount']}')
await ctx.send(embed=embed)
@commands.command(aliases=["skammeliste"])
@commands.command(aliases=['skammeliste'])
async def shamelist(self, ctx, page=0):
try:
page = int(page)
@@ -199,13 +199,13 @@ class SocialCredit(commands.Cog):
page = 0
page_data = await self.get_leaderboard(ctx, page, worst=True)
output_content = "\n".join(page_data["page_content"])
output_content = '\n'.join(page_data['page_content'])
embed = discord.Embed(title="Social credit skammeliste", description=output_content)
embed.set_footer(text=f"Side {page_data['page']}/{page_data['pagecount']}")
embed = discord.Embed(title='Social credit skammeliste', description=output_content)
embed.set_footer(text=f'Side {page_data['page']}/{page_data['pagecount']}')
await ctx.send(embed=embed)
@commands.Cog.listener("on_message")
@commands.Cog.listener('on_message')
async def on_message(self, message):
if message.author.bot:
return
@@ -246,12 +246,12 @@ class SocialCredit(commands.Cog):
for mention in message.mentions:
await self.social_punishment(mention.id, 10)
@commands.Cog.listener("on_reaction_add")
@commands.Cog.listener('on_reaction_add')
async def on_star_add(self, reaction, user):
if user.bot:
return
if reaction.emoji == "⭐":
if reaction.emoji == '⭐':
if reaction.message.author == user:
await self.social_punishment(user.id, 100)
else:
@@ -259,12 +259,12 @@ class SocialCredit(commands.Cog):
await self.social_punishment(user.id, (len(reaction.message.reactions) - 1) * 25)
await self.social_reward(user.id, 25 * len(reaction.message.reactions))
@commands.Cog.listener("on_reaction_remove")
@commands.Cog.listener('on_reaction_remove')
async def on_star_remove(self, reaction, user):
if user.bot:
return
if reaction.emoji == "⭐":
if reaction.emoji == '⭐':
if len(reaction.message.reactions) >= 3:
await self.social_punishment(user.id, 25)
+5 -5
View File
@@ -10,7 +10,7 @@ class Vær(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
@aiocron.crontab("0 6 * * *")
@aiocron.crontab('0 6 * * *')
async def forecast():
dev = await self.bot.fetch_user(162337748781367296)
@@ -19,8 +19,8 @@ class Vær(commands.Cog):
weather = Yr(location_name='Norway/Oslo/Oslo/Oslo', forecast_link='forecast_hour_by_hour')
embed = discord.Embed(title=":white_sun_small_cloud: Værmelding for Oslo :white_sun_small_cloud:")
embed.description = "*Værmeldingen levert til deg av Petter*"
embed = discord.Embed(title=':white_sun_small_cloud: Værmelding for Oslo :white_sun_small_cloud:')
embed.description = '*Værmeldingen levert til deg av Petter*'
embed.set_author(name=dev.name, icon_url=dev.display_avatar)
half_hour = False
@@ -35,11 +35,11 @@ class Vær(commands.Cog):
rain = data['precipitation']
regn = rain['@value']
temperatur = temp['@value']
embed.add_field(name=f"kl {klokkeslett}", value=f"{temperatur}°C - {regn}mm")
embed.add_field(name=f'kl {klokkeslett}', value=f'{temperatur}°C - {regn}mm')
klokkeslett += 1
half_hour = True
await channel.send("RISE AND SHINE GAMERS!", embed=embed)
await channel.send('RISE AND SHINE GAMERS!', embed=embed)
async def setup(bot: commands.Bot):
+2 -2
View File
@@ -6,7 +6,7 @@ class Wiki(commands.Cog):
@commands.command()
async def wiki_search(self, ctx, *search_term):
search_term = " ".join(search_term)
search_term = ' '.join(search_term)
search = wikipedia.search(search_term)
search = search[0]
@@ -15,7 +15,7 @@ class Wiki(commands.Cog):
summary = wikipedia.summary(search_term, sentences=5)
url = search.url
embed = discord.Embed(title=f"Wikipediasøk for {search_term}", url=url)
embed = discord.Embed(title=f'Wikipediasøk for {search_term}', url=url)
embed.add_field(name=search_term, value=summary)
embed_templates.default_footer(ctx,embed)
+121 -26
View File
@@ -9,14 +9,31 @@ from cogs.utils import embed_templates
class DevTools(commands.Cog):
"""Commands for developers to mangage cogs and other functionality of the bot"""
def __init__(self, bot: commands.Bot):
"""
Parameters
----------
bot (commands.Bot): The bot instance
"""
self.bot = bot
@commands.is_owner()
@commands.bot_has_permissions(embed_links=True)
@commands.command()
@commands.command(name='custommsg', description='Send en melding til hvilken som helst kanal på hvilken som helst server botten er i')
async def custommsg(self, ctx: commands.Context, channel: int, *text: tuple[str]):
"""Send a message to a specified channel"""
"""
Send a message to any channel on any server the bot is in
Parameters
----------
ctx (commands.Context): Context object
channel (int): The channel ID to send the message to
text (tuple[str]): The text to send
"""
# Send message to the requested channel
channel = self.bot.get_channel(channel)
custommessage = ' '.join(text)
@@ -30,9 +47,19 @@ class DevTools(commands.Cog):
@commands.is_owner()
@commands.bot_has_permissions(embed_links=True)
@commands.cooldown(1, 10, commands.BucketType.guild)
@commands.command()
@commands.command(name='changepresence', description='Endre botten sin nåværende status')
async def changepresence(self, ctx: commands.Context, activity_type: str, message: str, status_type: str):
"""Changes the bot's presence status"""
"""
Change the bot's presence status
Parameters
----------
ctx (commands.Context): Context object
activity_type (str): The type of activity to set the bot's status to
message (str): The message to set the bot's status to
status_type (str): The type of status to set the bot's status to
"""
activities = {
'playing': 0,
'listening': 2,
@@ -52,14 +79,23 @@ class DevTools(commands.Cog):
status=status_type,
activity=discord.Activity(type=activity_type, name=message)
)
embed = discord.Embed(color=ctx.me.color, description='Endret Presence!')
await ctx.send(embed=embed)
@commands.is_owner()
@commands.bot_has_permissions(embed_links=True, add_reactions=True)
@commands.command()
@commands.command(name='leave', description='Forlater en server. Om ingen er gitt, forlat der det ble sendt fra')
async def leave(self, ctx: commands.Context, *guild_id: int):
"""Leaves a specified guild"""
"""
Make bot leave a specified guild. If no guild is specified, leave the guild the command was sent from
Parameters
----------
ctx (commands.Context): Context object
guild_id (int): The ID of the guild to leave
"""
# If no guild id is specified, leave the current guild
guild_id = guild_id if guild_id else ctx.guild.id
@@ -75,7 +111,7 @@ class DevTools(commands.Cog):
await confirmation_msg.add_reaction('✅')
# Check confirmation
def comfirm(reaction, user):
def comfirm(reaction: discord.Reaction, user: discord.Member):
return user == ctx.author and str(reaction.emoji) == '✅'
try:
@@ -93,9 +129,16 @@ class DevTools(commands.Cog):
@commands.is_owner()
@commands.bot_has_permissions(embed_links=True)
@commands.command()
@commands.command(name='publicip', description='Hent den offentlige IP-adressen til serveren botten kjører på')
async def publicip(self, ctx: commands.Context):
"""Sends WAN IP-address. inb4 I leak my IP-address"""
"""
Sends WAN IP-address. Inb4 I leak my IP-address
Parameters
----------
ctx (commands.Context): Context object
"""
data = requests.get('https://wtfismyip.com/json', timeout=10).json()
ip = data['YourFuckingIPAddress']
location = data['YourFuckingLocation']
@@ -107,15 +150,30 @@ class DevTools(commands.Cog):
@commands.is_owner()
@commands.bot_has_permissions(embed_links=True)
@commands.group()
@commands.group(name='cogs', description='Administrer cogs')
async def cogs(self, ctx: commands.Context):
"""Cog management commands"""
"""
Cog management commands
Parameters
----------
ctx (commands.Context): Context object
"""
if not ctx.invoked_subcommand:
await ctx.send_help(ctx.command)
@cogs.command()
async def unload(self, ctx: commands.Context, cog: str):
"""Disables a specified cog"""
@cogs.command(name='unload', description='Avslutt en cog')
async def cogs_unload(self, ctx: commands.Context, cog: str):
"""
Disables a specified cog
Parameters
----------
ctx (commands.Context): Context object
cog (str): The name of the cog to disable
"""
for file in listdir('./src/cogs'):
if file.endswith('.py'):
name = file[:-3]
@@ -127,9 +185,17 @@ class DevTools(commands.Cog):
embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist')
await ctx.send(embed=embed)
@cogs.command()
async def load(self, ctx: commands.Context, cog: str):
"""Enables a speicifed cog"""
@cogs.command(name='load', description='Aktiver en cog')
async def cogs_load(self, ctx: commands.Context, cog: str):
"""
Enables a speicifed cog
Parameters
----------
ctx (commands.Context): Context object
cog (str): The name of the cog to enable
"""
for file in listdir('./src/cogs'):
if file.endswith('.py'):
name = file[:-3]
@@ -141,9 +207,16 @@ class DevTools(commands.Cog):
embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist')
await ctx.send(embed=embed)
@cogs.command()
async def reload(self, ctx: commands.Context, cog: str):
"""Reloads a specified cog"""
@cogs.command(name='reload', description='Last inn en cog på nytt')
async def cogs_reload(self, ctx: commands.Context, cog: str):
"""
Reloads a specified cog
Parameters
----------
ctx (commands.Context): Context object
cog (str): The name of the cog to reload
"""
for file in listdir('./src/cogs'):
if file.endswith('.py'):
name = file[:-3]
@@ -155,9 +228,16 @@ class DevTools(commands.Cog):
embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist')
await ctx.send(embed=embed)
@cogs.command()
async def reloadunloaded(self, ctx: commands.Context):
"""Reloads all cogs, including previously disabled ones"""
@cogs.command(name='reloadunloaded', description='Last inn alle cogs på nytt, selv de som ikke er lastet inn')
async def cogs_reloadunloaded(self, ctx: commands.Context):
"""
Reloads all cogs, including previously disabled ones
Parameters
----------
ctx (commands.Context): Context object
"""
# Unload all cogs
for file in listdir('./src/cogs'):
if file.endswith('.py'):
@@ -173,9 +253,16 @@ class DevTools(commands.Cog):
embed = discord.Embed(color=ctx.me.color, description='Reloaded all cogs')
await ctx.send(embed=embed)
@cogs.command()
async def reloadall(self, ctx: commands.Context):
"""Reloads all previously enabled cogs"""
@cogs.command(name='reloadall', description='Last inn alle cogs på nytt')
async def cogs_reloadall(self, ctx: commands.Context):
"""
Reloads all previously enabled cogs
Parameters
----------
ctx (commands.Context): Context object
"""
for file in listdir('./src/cogs'):
if file.endswith('.py'):
name = file[:-3]
@@ -186,4 +273,12 @@ class DevTools(commands.Cog):
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
await bot.add_cog(DevTools(bot))
+53 -6
View File
@@ -9,13 +9,28 @@ from cogs.utils.misc_utils import ignore_exception
class Errors(commands.Cog):
"""Error handlers for commands"""
def __init__(self, bot: commands.Bot):
"""
Parameters
----------
bot (commands.Bot): The bot instance
"""
self.bot = bot
bot.tree.on_error = self.on_app_command_error
bot.tree.on_error = self.on_app_command_error # Set error handler for slash commands
@commands.Cog.listener()
async def on_command(self, ctx: commands.Context):
"""Logs prefix command execution metadata"""
"""
Logs prefix command execution metadata
Parameters
----------
ctx (commands.Context): Context object
"""
self.bot.logger.info(
f'{"❌ " if ctx.command_failed else "✔ "} {ctx.command} | ' +
f'{ctx.author.name}#{ctx.author.discriminator} ({ctx.author.id}) | ' +
@@ -24,7 +39,15 @@ class Errors(commands.Cog):
@commands.Cog.listener()
async def on_app_command_completion(self, interaction: discord.Interaction, command: app_commands.Command | app_commands.ContextMenu):
"""Logs slash command execution metadata"""
"""
Logs slash command execution metadata
Parameters
----------
interaction (discord.Interaction): Slash command context object
command (app_commands.Command | app_commands.ContextMenu): Command object
"""
self.bot.logger.info(
f'{"❌ " if interaction.command_failed else "✔ "} {command.name} | ' +
f'{interaction.user.name}#{interaction.user.discriminator} ({interaction.user.id}) | ' +
@@ -33,7 +56,15 @@ class Errors(commands.Cog):
@commands.Cog.listener()
async def on_command_error(self, ctx: commands.Context, error: commands.CommandError):
"""Handle prefix command errors"""
"""
Handle prefix command errors
Parameters
----------
ctx (commands.Context): Context object
error (commands.CommandError): Eror context object
"""
# Reset cooldown if command throws AttributeError
with ignore_exception(AttributeError):
self.bot.get_command(f'{ctx.command}').reset_cooldown(ctx)
@@ -83,7 +114,7 @@ class Errors(commands.Cog):
text = 'Denne kommandoen kan bare utføres i servere'
return await ctx.send(text)
except discord.errors.Forbidden: # Thrown if bot is blocked by the user or if the user has closed their DMs
print("DM Blocked!")
print('DM Blocked!')
elif isinstance(error, commands.DisabledCommand):
pass
@@ -98,7 +129,15 @@ class Errors(commands.Cog):
self.bot.logger.error(''.join(traceback.format_exception(type(error), error, error.__traceback__)))
async def on_app_command_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError):
"""Handle slash command errors"""
"""
Handle slash command errors
Parameters
----------
interaction (discord.Interaction): Slash command context object
error (app_commands.AppCommandError): Eror context object
"""
# Log command usage, just in case
await self.on_app_command_completion(interaction, interaction.command)
@@ -131,4 +170,12 @@ class Errors(commands.Cog):
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
await bot.add_cog(Errors(bot))
+68 -5
View File
@@ -2,44 +2,107 @@ from discord.ext import commands
class Fun(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
"""Simple commands that return short strings for the memes"""
@commands.cooldown(1, 2, commands.BucketType.guild)
@commands.command()
@commands.command(name='norskeuniversiteter')
async def norskeuniversiteter(self, ctx: commands.Context):
"""
Sends a link to university meme image album
Parameters
----------
ctx (commands.Context): Context object
"""
await ctx.send('<https://imgur.com/a/uGopaSq>')
@commands.cooldown(1, 2, commands.BucketType.guild)
@commands.command()
@commands.command(name='ifi')
async def ifi(self, ctx: commands.Context):
"""
ifi meme 1
Parameters
----------
ctx (commands.Context): Context object
"""
await ctx.send('https://i.imgur.com/ypyK1mi.jpg')
@commands.cooldown(1, 2, commands.BucketType.guild)
@commands.command()
@commands.command(name='ifi2')
async def ifi2(self, ctx: commands.Context):
"""
ifi meme 2
Parameters
----------
ctx (commands.Context): Context object
"""
await ctx.send('https://i.imgur.com/ZqgZEEA.jpg')
@commands.cooldown(1, 2, commands.BucketType.guild)
@commands.command()
async def ifi3(self, ctx: commands.Context):
"""
ifi meme 3
Parameters
----------
ctx (commands.Context): Context object
"""
await ctx.send('https://i.imgur.com/Gx9DQE5.jpg')
@commands.cooldown(1, 2, commands.BucketType.guild)
@commands.command()
async def uio(self, ctx: commands.Context):
"""
uio meme 1
Parameters
----------
ctx (commands.Context): Context object
"""
await ctx.send('https://i.imgur.com/188MoIV.jpg')
@commands.cooldown(1, 2, commands.BucketType.guild)
@commands.command()
async def ntnu(self, ctx: commands.Context):
"""
ntnu meme 1
Parameters
----------
ctx (commands.Context): Context object
"""
await ctx.send('https://twitter.com/NTNU/status/970667413564993536')
@commands.cooldown(1, 2, commands.BucketType.guild)
@commands.command()
async def ntnu2(self, ctx: commands.Context):
"""
ntnu meme 2
Parameters
----------
ctx (commands.Context): Context object
"""
await ctx.send('https://i.imgur.com/h84fknj.jpg')
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
await bot.add_cog(Fun(bot))
+24 -1
View File
@@ -7,7 +7,15 @@ from discord.ext import commands
class FunReplies(commands.Cog):
"""Reply to messages that trigger certain key words/phrases"""
def __init__(self, bot: commands.Bot):
"""
Parameters
----------
bot (commands.Bot): The bot instance
"""
self.bot = bot
# Cooldowns for trigger words
@@ -24,7 +32,14 @@ class FunReplies(commands.Cog):
}
async def reply_to_triggers(self, message: discord.Message):
"""Replies to messages that trigger certain key words/phrases"""
"""
Replies to messages that trigger certain key words/phrases
Parameters
----------
message (discord.Message): Message object to check for triggers to
"""
if message.author.bot:
return
@@ -62,5 +77,13 @@ class FunReplies(commands.Cog):
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
bot.add_listener(FunReplies(bot).reply_to_triggers, 'on_message')
await bot.add_cog(FunReplies(bot))
+213 -28
View File
@@ -8,24 +8,55 @@ from cogs.utils import discord_utils, embed_templates, misc_utils
class Info(commands.Cog):
"""View information about Discord object such as guilds, users, roles and channels"""
def __init__(self, bot: commands.Bot):
"""
Parameters
----------
bot (commands.Bot): The bot instance
"""
self.bot = bot
guild_group = app_commands.Group(name="guild", description="Se ting om serveren")
user_group = app_commands.Group(name="bruker", description="Se ting om brukeren")
guild_group = app_commands.Group(name='guild', description='Se ting om serveren')
user_group = app_commands.Group(name='bruker', description='Se ting om brukeren')
def __construct_role_string(self, roles: list[discord.Role]) -> str:
"""Puts all roles except @everyone into a list and joins them to a string"""
if not roles:
return "**Ingen roller**"
"""
Puts all roles except @everyone into a list and joins them to a string
roles = [role.name for role in roles if role.name != "@everyone"]
Parameters
----------
roles (list[discord.Role]): List of roles
Returns
-------
(str): String of roles
"""
if not roles:
return '**Ingen roller**'
roles = [role.name for role in roles if role.name != '@everyone']
roles.reverse()
return ', '.join(roles)
def __construct_booster_string(self, interaction: discord.Interaction, join_method: callable = ', '.join) -> str:
"""Joins all boosters into a string"""
"""
Joins all boosters into a string
Parameters
----------
interaction (discord.Interaction): Slash command context object
join_method (callable): Function to join the boosters with
Returns
-------
(str): String of boosters
"""
if not interaction.guild.premium_subscribers:
return '**Ingen boostere**'
@@ -39,7 +70,18 @@ class Info(commands.Cog):
return join_method(boosters)
def __construct_member_string(self, members: list[discord.Member]) -> str:
"""Joins all name#discrim into a string"""
"""
Joins all name#discrim into a string
Parameters
----------
members (list[discord.Member]): List of members
Returns
-------
(str): String of members
"""
if not members:
return '**Ingen**'
@@ -48,7 +90,16 @@ class Info(commands.Cog):
return ', '.join(members)
async def __send_as_txt_file(self, interaction: discord.Interaction, content: str, file_path: str):
"""Sends a string as a txt file and deletes the file afterwards"""
"""
Sends a string as a txt file and deletes the file afterwards
Parameters
----------
interaction (discord.Interaction): Slash command context object
content (str): String that's too long to send
file_path (str): Path to file
"""
# Create file
with open(file_path, 'w', encoding='utf-8') as file:
file.write(content)
@@ -64,10 +115,18 @@ class Info(commands.Cog):
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True, external_emojis=True)
@app_commands.checks.cooldown(1, 2)
@guild_group.command(name="info", description="Hent informasjon om en server")
@guild_group.command(name='info', description='Hent informasjon om en server')
async def guild_info(self, interaction: discord.Interaction):
"""
Sends general information about the guild
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
# Days since guild was created
creation_date_timestamp = discord.utils.format_dt(interaction.guild.created_at, style="F")
creation_date_timestamp = discord.utils.format_dt(interaction.guild.created_at, style='F')
since_created_days = (interaction.created_at - interaction.guild.created_at).days
days_ago = f'{since_created_days} dager' if since_created_days != 1 else f'{since_created_days} dag'
@@ -195,8 +254,16 @@ class Info(commands.Cog):
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@guild_group.command(name="roller", description="Se rollene på serveren")
@guild_group.command(name='roller', description='Se rollene på serveren')
async def guild_roles(self, interaction: discord.Interaction):
"""
List all roles in the guild
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
roles = self.__construct_role_string(interaction.guild.roles)
# IF roles list is longer than 2048, create text file and send it
@@ -211,8 +278,16 @@ class Info(commands.Cog):
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@guild_group.command(name="boosters", description="Se boostere på serveren")
@guild_group.command(name='boosters', description='Se boostere på serveren')
async def guild_boosters(self, interaction: discord.Interaction):
"""
List all boosters in the guild
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
if len(interaction.guild.premium_subscribers) == 0:
embed = embed_templates.error_warning(interaction, text='Serveren har ikke noen boosts :(')
return await interaction.response.send_message(embed=embed)
@@ -227,8 +302,16 @@ class Info(commands.Cog):
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@guild_group.command(name="ikon", description="Hent serverens ikon")
@guild_group.command(name='ikon', description='Hent serverens ikon')
async def guild_icon(self, interaction: discord.Interaction):
"""
Get the guild icon
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
embed = discord.Embed(color=interaction.guild.me.color, description=f'[Lenke]({interaction.guild.icon})')
embed.set_author(name=interaction.guild.name, icon_url=interaction.guild.icon)
embed.set_image(url=interaction.guild.icon)
@@ -238,8 +321,16 @@ class Info(commands.Cog):
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@guild_group.command(name="splash", description="Hent serverens splash (bakgrunnsbilde på invitasjonsside)")
@guild_group.command(name='splash', description='Hent serverens splash (bakgrunnsbilde på invitasjonsside)')
async def guild_splash(self, interaction: discord.Interaction):
"""
Get the guild splash
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
if not interaction.guild.discovery_splash:
embed = embed_templates.error_warning(interaction, text='Serveren har ikke en splash')
return await interaction.response.send_message(embed=embed)
@@ -253,8 +344,16 @@ class Info(commands.Cog):
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@guild_group.command(name="banner", description="Hen serverens banner")
@guild_group.command(name='banner', description='Hen serverens banner')
async def guild_banner(self, interaction: discord.Interaction):
"""
Get the guild banner
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
if not interaction.guild.banner:
embed = embed_templates.error_warning(interaction, text='Serveren har ikke et banner :(')
return await interaction.response.send_message(embed=embed)
@@ -268,14 +367,23 @@ class Info(commands.Cog):
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@guild_group.command(name="rolle", description="Hent informasjon om en rolle på serveren")
@guild_group.command(name='rolle', description='Hent informasjon om en rolle på serveren')
async def guild_role(self, interaction: discord.Interaction, rolle: discord.Role):
"""
Get information about a role
Parameters
----------
interaction (discord.Interaction): Slash command context object
rolle (discord.Role): Role to fetch information about
"""
if rolle.name == '@everyone':
embed = embed_templates.error_fatal(interaction, text='Skriv inn en annen rolle enn @everyone')
return await interaction.response.send_message(embed=embed)
# Timestamp and days since creation
created_at_timestamp = discord.utils.format_dt(rolle.created_at, style="F")
created_at_timestamp = discord.utils.format_dt(rolle.created_at, style='F')
since_created_days = (interaction.created_at - rolle.created_at).days
# List of members with the role
@@ -302,8 +410,17 @@ class Info(commands.Cog):
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@guild_group.command(name="tekstkanal", description="Hent informasjon om en tekstkanal")
@guild_group.command(name='tekstkanal', description='Hent informasjon om en tekstkanal')
async def guild_text_channel(self, interaction: discord.Interaction, kanal: discord.TextChannel):
"""
Get information about a text channel
Parameters
----------
interaction (discord.Interaction): Slash command context object
kanal (discord.TextChannel): Text channel to fetch information about
"""
members = self.__construct_member_string(kanal.members)
if len(members) > 1024:
members = 'For mange for å vise her'
@@ -323,8 +440,17 @@ class Info(commands.Cog):
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@guild_group.command(name="talekanal", description="Hent informasjon om en talekanal")
@guild_group.command(name='talekanal', description='Hent informasjon om en talekanal')
async def guild_voice_channel(self, interaction: discord.Interaction, kanal: discord.VoiceChannel):
"""
Get information about a voice channel
Parameters
----------
interaction (discord.Interaction): Slash command context object
kanal (discord.VoiceChannel): Voice channel to fetch information about
"""
embed = discord.Embed(color=interaction.guild.me.color, title=kanal.name, description=f'ID: {kanal.id}')
embed.set_author(name=kanal.guild.name, icon_url=kanal.guild.icon)
embed.add_field(name='Opprettet', value=discord.utils.format_dt(kanal.created_at, style='F'))
@@ -352,17 +478,25 @@ class Info(commands.Cog):
# embed = discord.Embed(color=interaction.guild.me.color, title=emoji.name, description=f'ID: {emoji.id}')
# embed.set_author(name=emoji.guild.name, icon_url=emoji.guild.icon)
# embed.add_field(name='Opprettet', value=discord.utils.format_dt(emoji.created_at, style="F"))
# embed.add_field(name='Opprettet', value=discord.utils.format_dt(emoji.created_at, style='F'))
# embed.add_field(name='Animert', value='Ja' if emoji.animated else 'Nei')
# embed.add_field(name='Lagt til av', value=emoji_creator)
# embed.set_image(url=emoji.url)
# embed_templates.default_footer(interaction, embed)
# await interaction.response.send_message(embed=embed)
guild_oldest_group = app_commands.Group(name="eldst", description="Viser de eldste medlemmene på serveren", parent=guild_group)
guild_oldest_group = app_commands.Group(name='eldst', description='Viser de eldste medlemmene på serveren', parent=guild_group)
def __construct_oldest_embed(self, paginator: misc_utils.Paginator, page: list, embed: discord.Embed) -> discord.Embed:
"""Constructs the embed for the oldest commands"""
"""
Constructs the embed for the oldest commands
Parameters
----------
paginator (misc_utils.Paginator): Paginator dataclass
page (list): List of members to display
embed (discord.Embed): Embed to add fields to
"""
embed.description = '\n'.join(page)
embed.set_footer(text=f'Side {paginator.current_page}/{paginator.total_page_count}')
return embed
@@ -370,8 +504,16 @@ class Info(commands.Cog):
@commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 5)
@guild_oldest_group.command(name="lagd", description="Liste over de eldste brukerene på serveren basert på når de ble lagd")
@guild_oldest_group.command(name='lagd', description='Liste over de eldste brukerene på serveren basert på når de ble lagd')
async def guild_user_created_oldest(self, interaction: discord.Interaction):
"""
List the oldest users on the server based on when they were created
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
# Sort members by creation date
members = sorted(interaction.guild.members, key=lambda m: m.created_at)
@@ -392,8 +534,16 @@ class Info(commands.Cog):
@commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 5)
@guild_oldest_group.command(name="joined", description="Liste over de eldste brukerene på serveren basert på når de ble med")
@guild_oldest_group.command(name='joined', description='Liste over de eldste brukerene på serveren basert på når de ble med')
async def guild_user_joined_oldest(self, interaction: discord.Interaction):
"""
List the oldest users on the server based on when they joined
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
# Sort members by creation date
members = sorted(interaction.guild.members, key=lambda m: m.joined_at)
@@ -414,8 +564,17 @@ class Info(commands.Cog):
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True, external_emojis=True)
@app_commands.checks.cooldown(1, 2)
@user_group.command(name="info", description="Hent informasjon om en bruker")
@user_group.command(name='info', description='Hent informasjon om en bruker')
async def user_info(self, interaction: discord.Interaction, *, bruker: discord.Member | None = None):
"""
Get information about a user
Parameters
----------
interaction (discord.Interaction): Slash command context object
bruker (discord.Member, optional): User to get information about. Defaults to None (invoker).
"""
if not bruker:
bruker = interaction.user
@@ -489,8 +648,17 @@ class Info(commands.Cog):
@app_commands.guild_only()
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@user_group.command(name="roller", description="Hent roller til en bruker")
@user_group.command(name='roller', description='Hent roller til en bruker')
async def user_roles(self, interaction: discord.Interaction, bruker: discord.Member | None = None):
"""
Get roles of a user
Parameters
----------
interaction (discord.Interaction): Slash command context object
bruker (discord.Member, optional): User to get roles of. Defaults to None (invoker).
"""
if not bruker:
bruker = interaction.user
@@ -507,8 +675,17 @@ class Info(commands.Cog):
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@user_group.command(name="avatar", description="Hent avatar til en bruker")
@user_group.command(name='avatar', description='Hent avatar til en bruker')
async def user_avatar(self, interaction: discord.Interaction, bruker: discord.User | discord.Member | None = None):
"""
Get avatar of a user
Parameters
----------
interaction (discord.Interaction): Slash command context object
bruker (discord.User, optional): User to get avatar of. Defaults to None (invoker).
"""
if not bruker:
bruker = interaction.user
@@ -520,4 +697,12 @@ class Info(commands.Cog):
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
await bot.add_cog(Info(bot))
+35 -11
View File
@@ -8,13 +8,22 @@ from cogs.utils import embed_templates
class MCWhitelist(commands.Cog):
"""Stand alone cog for handling whitelisting of Discord users on the Minecraft server"""
def __init__(self, bot: commands.Bot):
"""
Parameters
----------
bot (commands.Bot): The bot instance
"""
self.bot = bot
self.cursor = self.bot.db_connection.cursor()
self.init_db()
def init_db(self):
"""Create the necessary tables for the mc_whitelist cog to work."""
self.cursor.execute(
"""
CREATE TABLE IF NOT EXISTS mc_whitelist (
@@ -27,15 +36,22 @@ class MCWhitelist(commands.Cog):
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 5)
@app_commands.command()
@app_commands.command(name='whitelist', description='Whitelist minecraftbrukeren din på serveren vår')
async def whitelist(self, interaction: discord.Interaction, minecraftbrukernavn: str):
"""Whitelist Minecraftbrukeren din på serveren vår"""
"""
Whitelist a minecraft user on the Minecraft server
Parameters
----------
interaction (discord.Interaction): Slash command context object
minecraftbrukernavn (str): Minecraft username
"""
# Fetch minecraft uuid from api
data = requests.get(f"https://api.mojang.com/users/profiles/minecraft/{minecraftbrukernavn}", timeout=10).json()
data = requests.get(f'https://api.mojang.com/users/profiles/minecraft/{minecraftbrukernavn}', timeout=10).json()
if data.status_code != 200:
return await interaction.response.send_message(
embed=embed_templates.error_fatal(interaction, text=f"Brukeren `{minecraftbrukernavn}` finnes ikke på minecraft"),
embed=embed_templates.error_fatal(interaction, text=f'Brukeren `{minecraftbrukernavn}` finnes ikke på minecraft'),
ephemeral=True
)
@@ -47,21 +63,21 @@ class MCWhitelist(commands.Cog):
SELECT *
FROM mc_whitelist
WHERE minecraft_id = %s OR discord_id = %s
""", (data["id"], interaction.user.id)
""", (data['id'], interaction.user.id)
)
if self.cursor.fetchone():
return await interaction.response.send_message(
embed=embed_templates.error_fatal(
interaction,
text="Du har allerede whitelisted en bruker eller så er brukeren du oppga whitelisted"
text='Du har allerede whitelisted en bruker eller så er brukeren du oppga whitelisted'
)
)
# Whitelist user on minecraft server
# Unfortunately, this requires an active connection to the server, with correct credentials
with MCRcon(host="127.0.0.1", password=self.bot.mc_rcon_password, port=25575) as mcr:
mcr.command(f"whitelist add {data['name']}")
mcr.command("whitelist reload")
with MCRcon(host='127.0.0.1', password=self.bot.mc_rcon_password, port=25575) as mcr:
mcr.command(f'whitelist add {data["name"]}')
mcr.command('whitelist reload')
# Add user to db
self.cursor.execute(
@@ -69,16 +85,24 @@ class MCWhitelist(commands.Cog):
INSERT INTO mc_whitelist (discord_id, minecraft_id)
VALUES (%s, %s)
""",
(interaction.user.id, data["id"]),
(interaction.user.id, data['id']),
)
self.bot.db_connection.commit()
await interaction.response.send_message(
embed=embed_templates.success(
interaction, text=f"`{data['name']}` er nå tilknyttet din discordbruker og whitelisted!"
interaction, text=f'`{data["name"]}` er nå tilknyttet din discordbruker og whitelisted!'
)
)
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
await bot.add_cog(MCWhitelist(bot))
+148 -70
View File
@@ -14,21 +14,43 @@ from cogs.utils.misc_utils import ignore_exception
class Misc(commands.Cog):
"""Miscellaneous commands that don't fit anywhere else"""
def __init__(self, bot: commands.Bot):
"""
Parameters
----------
bot (commands.Bot): The bot instance
"""
self.bot = bot
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@app_commands.command()
@app_commands.command(name='weeb', description='Kjeft på weebs')
async def weeb(self, interaction: discord.Interaction):
"""Kjeft på weebs"""
await interaction.response.send_message("<:sven:762725919604473866> Weebs 👉 <#803596668129509417>")
"""
Call out weebs
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
await interaction.response.send_message('<:sven:762725919604473866> Weebs 👉 <#803596668129509417>')
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@app_commands.command()
@app_commands.command(name='kweeb', description='김정운, 최고도')
async def kweeb(self, interaction: discord.Interaction):
"""김정운, 최고도"""
"""
Call out kweebs
Parameters
----------
interaction (discord.Interaction): Slash command context object
"""
await interaction.response.send_message(
"""
Melding du nettopp sendte ga muligens følgende vibber for brukeren som brukte denne kommandoen:
@@ -52,17 +74,24 @@ https://cdn.discordapp.com/attachments/674726496878723082/1042631569396990004/kw
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@app_commands.command()
@app_commands.command(name='owo', description='Oversetter teksten din til owo (we_eb)')
async def owo(self, interaction: discord.Interaction, tekst: str):
"""Oversetter teksten din til owo (we_eb)"""
"""
Translate text into owo (we_eb)
owo_rules = {"r": "w", "l": "w", "R": "W", "L": "W", "n": "ny", "N": "Ny", "ove": "uv"}
Parameters
----------
interaction (discord.Interaction): Slash command context object
tekst (str): Text to translate
"""
owo_rules = {'r': 'w', 'l': 'w', 'R': 'W', 'L': 'W', 'n': 'ny', 'N': 'Ny', 'ove': 'uv'}
for key, value in owo_rules.items():
tekst = re.sub(key, value, tekst)
# https://kaomoji.moe/
if len(tekst) >= 1000:
embed = embed_templates.error_warning(interaction, text="Teksten er for lang")
embed = embed_templates.error_warning(interaction, text='Teksten er for lang')
return await interaction.response.send_message(embed=embed)
embed = discord.Embed(color=interaction.client.user.color, description=tekst)
@@ -70,50 +99,74 @@ https://cdn.discordapp.com/attachments/674726496878723082/1042631569396990004/kw
await interaction.response.send_message(embed=embed)
@app_commands.checks.cooldown(1, 5)
@app_commands.command()
async def emne(self, interaction: discord.Interaction, emnekode: str):
"""For NTNU'ere som ikke kan emnekoder på UiO"""
data = requests.get(f"https://data.uio.no/studies/v1/course/{emnekode}", timeout=10)
if data.status_code != 200:
return await interaction.response.send_message(embed=embed_templates.error_fatal(interaction, text="Fant ikke emnekode"))
@app_commands.command(name='emne', description='For NTNU\'ere som ikke kan emnekoder på UiO')
async def course_code(self, interaction: discord.Interaction, emnekode: str):
"""
Translate UiO course codes to their respective course names
await interaction.response.send_message(data.json()["info"]["name"])
Parameters
----------
interaction (discord.Interaction): Slash command context object
emnekode (str): UiO course code
"""
data = requests.get(f'https://data.uio.no/studies/v1/course/{emnekode}', timeout=10)
if data.status_code != 200:
return await interaction.response.send_message(embed=embed_templates.error_fatal(interaction, text='Fant ikke emnekode'))
await interaction.response.send_message(data.json()['info']['name'])
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 2)
@app_commands.command()
async def klappifiser(self, interation: discord.Interaction, tekst: str):
"""Klapppifiserer teksten din"""
@app_commands.command(name='klappifiser', description='Klappifiser tekst')
async def clapify(self, interation: discord.Interaction, tekst: str):
"""
Add clap emoji between every word of a string
Parameters
----------
interaction (discord.Interaction): Slash command context object
tekst (str): Text to clapify
"""
if len(tekst) >= 1000:
embed = embed_templates.error_warning(interation, text="Teksten er for lang")
embed = embed_templates.error_warning(interation, text='Teksten er for lang')
return await interation.response.send_message(embed=embed)
tekst = re.sub(" ", "👏", tekst)
tekst = re.sub(' ', '👏', tekst)
embed = discord.Embed(color=interation.client.user.color, description=f"**{tekst.upper()}**")
embed = discord.Embed(color=interation.client.user.color, description=f'**{tekst.upper()}**')
embed_templates.default_footer(interation, embed)
await interation.response.send_message(embed=embed)
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 5)
@app_commands.command()
@app_commands.command(name='imdb', description='Søk etter filmer på IMDB')
async def imdb(self, interaction: discord.Interaction, tittel: str):
"""Se informasjon om en film eller serie"""
"""
Search for movies on IMDB and displays information about the first result
Parameters
----------
interaction (discord.Interaction): Slash command context object
tittel (str): Movie title
"""
# Search for movie/show
url = "http://www.omdbapi.com/?" + urllib.parse.urlencode({"s": tittel, "apikey": self.bot.api_keys["omdb"]})
url = 'http://www.omdbapi.com/?' + urllib.parse.urlencode({'s': tittel, 'apikey': self.bot.api_keys['omdb']})
search = requests.get(url, timeout=10).json()
try:
best_result_id = search["Search"][0]["imdbID"]
best_result_id = search['Search'][0]['imdbID']
except KeyError:
embed = embed_templates.error_fatal(interaction, text="Fant ikke filmen!")
embed = embed_templates.error_fatal(interaction, text='Fant ikke filmen!')
return await interaction.response.send_message(embed=embed)
# Get movie/show info
data = requests.get(f'http://www.omdbapi.com/?i={best_result_id}&apikey={self.bot.api_keys["omdb"]}', timeout=10).json()
acceptable_media_types = ["movie", "series", "episode"]
if data["Type"] not in acceptable_media_types:
embed = embed_templates.error_fatal(interaction, text="Fant ikke filmen!")
acceptable_media_types = ['movie', 'series', 'episode']
if data['Type'] not in acceptable_media_types:
embed = embed_templates.error_fatal(interaction, text='Fant ikke filmen!')
return await interaction.response.send_message(embed=embed)
embed = discord.Embed(
@@ -122,61 +175,78 @@ https://cdn.discordapp.com/attachments/674726496878723082/1042631569396990004/kw
url=f'https://www.imdb.com/title/{data["imdbID"]}/',
)
embed.set_author(name=interaction.user.name, icon_url=interaction.user.display_avatar)
embed.add_field(name="Type", value=data["Type"].title())
embed.add_field(name="Sjanger", value=data["Genre"])
embed.add_field(name="Spilletid", value=data["Runtime"])
embed.add_field(name="Vurdering på IMDb", value=f'{data["imdbRating"]}/10')
release_date = datetime.strptime(data["Released"], "%d %b %Y")
embed.add_field(name="Utgitt", value=discord.utils.format_dt(release_date, style="D"))
embed.add_field(name='Type', value=data['Type'].title())
embed.add_field(name='Sjanger', value=data['Genre'])
embed.add_field(name='Spilletid', value=data['Runtime'])
embed.add_field(name='Vurdering på IMDb', value=f'{data["imdbRating"]}/10')
release_date = datetime.strptime(data['Released'], '%d %b %Y')
embed.add_field(name='Utgitt', value=discord.utils.format_dt(release_date, style='D'))
embed_templates.default_footer(interaction, embed)
if data["Poster"] != "N/A":
embed.set_thumbnail(url=data["Poster"])
if data["Director"] != "N/A":
embed.description = data["Director"]
if data["Plot"] != "N/A" and len(data["Plot"]) < 1024:
embed.add_field(name="Sammendrag", value=data["Plot"], inline=False)
if data['Poster'] != 'N/A':
embed.set_thumbnail(url=data['Poster'])
if data['Director'] != 'N/A':
embed.description = data['Director']
if data['Plot'] != 'N/A' and len(data['Plot']) < 1024:
embed.add_field(name='Sammendrag', value=data['Plot'], inline=False)
await interaction.response.send_message(embed=embed)
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 5)
@app_commands.command()
async def helligdager(self, interaction: discord.Interaction, *, land: str = "NO", år: int = None):
"""Se hellidagene i et land"""
@app_commands.command(name='helligdager', description='Se helligdager i et land for et år')
async def holidays(self, interaction: discord.Interaction, *, land: str = 'NO', år: int = None):
"""
Get holidays for a country for a given year
Parameters
----------
interaction (discord.Interaction): Slash command context object
land (str): Country code
år (int): Year
"""
land = land.upper()
aar = datetime.now().year if not år else int(år)
data = requests.get(f"https://date.nager.at/api/v2/publicholidays/{aar}/{land}", timeout=10)
data = requests.get(f'https://date.nager.at/api/v2/publicholidays/{aar}/{land}', timeout=10)
if data.status_code != 200:
embed = embed_templates.error_fatal(
interaction, text="Ugyldig land\nHusk å bruke landskoder\n" + "For eksempel: `NO`"
interaction, text='Ugyldig land\nHusk å bruke landskoder\n' + 'For eksempel: `NO`'
)
return await interaction.response.send_message(embed=embed)
data = data.json()
country = data[0]["countryCode"].lower()
country = data[0]['countryCode'].lower()
# Construct output
holiday_str = ""
holiday_str = ''
for day in data:
date = discord.utils.format_dt(datetime.strptime(day["date"], "%Y-%m-%d"), style="D")
date = discord.utils.format_dt(datetime.strptime(day['date'], '%Y-%m-%d'), style='D')
holiday_str += f'**{date}**: {day["localName"]}\n'
embed = discord.Embed(color=interaction.client.user.color, title=f":flag_{country}: Helligdager {aar} :flag_{country}:")
embed = discord.Embed(color=interaction.client.user.color, title=f':flag_{country}: Helligdager {aar} :flag_{country}:')
embed.description = holiday_str
embed_templates.default_footer(interaction, embed)
await interaction.response.send_message(embed=embed)
@app_commands.checks.bot_has_permissions(embed_links=True)
@app_commands.checks.cooldown(1, 5)
@app_commands.command()
@app_commands.command(name='match', description='Se hvor mye du matcher med en annen')
async def match(self, interaction: discord.Interaction, bruker: discord.Member):
"""Se hvor mye du matcher med en annen"""
"""
Get dating compatibility with another user
Parameters
----------
interaction (discord.Interaction): Slash command context object
bruker (discord.Member): User to match with
"""
if bruker == interaction.user:
embed = embed_templates.error_warning(
interaction, text="Jeg vet du er ensom, men du kan " "ikke matche med deg selv"
interaction, text='Jeg vet du er ensom, men du kan ' 'ikke matche med deg selv'
)
return await interaction.response.send_message(embed=embed)
@@ -188,39 +258,47 @@ https://cdn.discordapp.com/attachments/674726496878723082/1042631569396990004/kw
if bruker.id == self.bot.user.id:
match_percent = 100
await interaction.user.display_avatar.save(fp=f"./src/assets/temp/{interaction.user.id}_raw.png")
await bruker.display_avatar.save(fp=f"./src/assets/temp/{bruker.id}_raw.png")
await interaction.user.display_avatar.save(fp=f'./src/assets/temp/{interaction.user.id}_raw.png')
await bruker.display_avatar.save(fp=f'./src/assets/temp/{bruker.id}_raw.png')
invoker = Image.open(f"./src/assets/temp/{interaction.user.id}_raw.png").convert("RGBA")
invoker = Image.open(f'./src/assets/temp/{interaction.user.id}_raw.png').convert('RGBA')
invoker = invoker.resize((389, 389), Image.ANTIALIAS)
user = Image.open(f"./src/assets/temp/{bruker.id}_raw.png").convert("RGBA")
user = Image.open(f'./src/assets/temp/{bruker.id}_raw.png').convert('RGBA')
user = user.resize((389, 389), Image.ANTIALIAS)
heart = Image.open("./src/assets/misc/heart.png")
mask = Image.open("./src/assets/misc/heart.png", "r")
heart = Image.open('./src/assets/misc/heart.png')
mask = Image.open('./src/assets/misc/heart.png', 'r')
image = Image.new("RGBA", (1024, 576))
image = Image.new('RGBA', (1024, 576))
image.paste(invoker, (0, 94))
image.paste(user, (635, 94))
image.paste(heart, (311, 94), mask=mask)
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("./src/assets/fonts/RobotoMono-Medium.ttf", 86)
font_size = font.getsize(f"{match_percent}%")
font = ImageFont.truetype('./src/assets/fonts/RobotoMono-Medium.ttf', 86)
font_size = font.getsize(f'{match_percent}%')
font_size = ((image.size[0] - font_size[0]) / 2, (image.size[1] - font_size[1]) / 2)
draw.text(font_size, f"{match_percent}%", font=font, fill=(255, 255, 255, 255))
draw.text(font_size, f'{match_percent}%', font=font, fill=(255, 255, 255, 255))
image.save(f"./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png")
image.save(f'./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png')
f = discord.File(f"./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png")
f = discord.File(f'./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png')
embed = discord.Embed()
embed.set_image(url=f"attachment://{interaction.user.id}_{bruker.id}_edit.png")
embed.set_image(url=f'attachment://{interaction.user.id}_{bruker.id}_edit.png')
embed_templates.default_footer(interaction, embed)
await interaction.response.send_message(embed=embed, file=f)
with ignore_exception(OSError):
remove(f"./src/assets/temp/{bruker.id}_raw.png")
remove(f"./src/assets/temp/{interaction.user.id}_raw.png")
remove(f"./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png")
remove(f'./src/assets/temp/{bruker.id}_raw.png')
remove(f'./src/assets/temp/{interaction.user.id}_raw.png')
remove(f'./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png')
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
await bot.add_cog(Misc(bot))
+24 -9
View File
@@ -3,34 +3,49 @@ from discord.ext import commands
class RepeatedMessages(commands.Cog):
"""Send messages at specific points of time"""
def __init__(self, bot: commands.Bot):
self.bot = bot
self.uiog_server = self.bot.get_guild(747542543750660178)
@aiocron.crontab("0 0 * * 5")
@aiocron.crontab('0 0 * * 5')
async def fredag():
"""Sends a message on Friday at 00:00"""
channel = await self.uiog_server.fetch_channel(747542544291987597)
await channel.send(
"NU ÄR DET FREDAG!\n" +
"https://cdn.discordapp.com/attachments/750052141346979850/851216786259181578/video0.mp4"
'NU ÄR DET FREDAG!\n' +
'https://cdn.discordapp.com/attachments/750052141346979850/851216786259181578/video0.mp4'
)
@aiocron.crontab("0 0 * * 1")
@aiocron.crontab('0 0 * * 1')
async def mandag():
"""Sends a message on Monday at 00:00"""
channel = await self.uiog_server.fetch_channel(747542544291987597)
await channel.send(
"ENDELIG MANDAG!\n\n" +
"https://cdn.discordapp.com/attachments/678396498089738250/862853827278929940/hvorfor_de_rike_br_spises.mp4"
'ENDELIG MANDAG!\n\n' +
'https://cdn.discordapp.com/attachments/678396498089738250/862853827278929940/hvorfor_de_rike_br_spises.mp4'
)
@aiocron.crontab("0 0 1 1 *")
@aiocron.crontab('0 0 1 1 *')
async def new_year():
"""Sends a message on New Year's Day at 00:00"""
channel = await self.uiog_server.fetch_channel(747542544291987597)
await channel.send(
"GODT NYTTÅR!\n\nNå, meld dere inn i UiO Gaming igjen <:ThisIsAThreat:874998234072903710>"
'GODT NYTTÅR!\n\nNå, meld dere inn i UiO Gaming igjen <:ThisIsAThreat:874998234072903710>'
)
async def setup(bot: commands.Bot):
"""
Add the cog to the bot on extension load
Parameters
----------
bot (commands.Bot): Bot instance
"""
await bot.add_cog(RepeatedMessages(bot))
+29 -1
View File
@@ -15,27 +15,55 @@ def get_color(discord_object: discord.User | discord.Member | discord.Role) -> d
-----------
(discord.Color): The user's displayed color
"""
if hasattr(discord_object, "color") and str(discord_object.color) != '#000000':
if hasattr(discord_object, 'color') and str(discord_object.color) != '#000000':
return discord_object.color
return discord.Colour(0x99AAB5)
class ScrollerButton(discord.ui.Button):
"""Button that scrolls through pages in a scroller view"""
def __init__(self, paginator: Paginator, button_action: callable, content_constructor: callable, label: str, disabled: bool = False):
"""
Parameters
-----------
paginator (Paginator): The paginator object that contains the data to be paginated
button_action (callable): The function that returns the requested page
content_constructor (callable): A function that takes a paginator object and a page number and returns an embed
"""
super().__init__(label=label, disabled=disabled)
self.paginator = paginator
self.button_action = button_action
self.content_constructor = content_constructor
async def callback(self, interaction: discord.Interaction):
"""
What to do when the button is pressed
Parameters
-----------
interaction (discord.Interaction): Slash command context object
"""
await interaction.response.defer()
content = self.content_constructor(self.paginator, self.button_action(), interaction.message.embeds[0])
await interaction.message.edit(embed=content, view=Scroller(self.paginator, self.content_constructor))
class Scroller(discord.ui.View):
"""View that allows scrolling through pages of data using the pagination module"""
def __init__(self, paginatior: Paginator, content_constructor: callable):
"""
Parameters
-----------
paginator (Paginator): The paginator object that contains the data to be paginated
content_constructor (callable): A function that takes a paginator object and a page number and returns an embed
"""
super().__init__()
self.paginator = paginatior
+12 -8
View File
@@ -7,16 +7,17 @@ def default_footer(interaction: discord.Interaction, embed: discord.Embed) -> di
Parameters
-----------
interaction (discord.Interaction): Discord interaction context
interaction (discord.Interaction): Slash command context object
embed (discord.Embed): An embed object to add the footer to
Returns
-----------
(discord.Embed): The passed in embed + footer
"""
return embed.set_footer(
icon_url=interaction.user.avatar,
text=f"{interaction.user.name}#{interaction.user.discriminator}"
text=f'{interaction.user.name}#{interaction.user.discriminator}'
)
@@ -26,14 +27,15 @@ def error_warning(interaction: discord.Interaction, text: str) -> discord.Embed:
Parameters
-----------
interaction (discord.Interaction): Discord interaction context
interaction (discord.Interaction): Slash command context object
text (str): The error message
Returns
-----------
(discord.Embed): An embed object based on the template with the specified text
"""
embed = discord.Embed(color=discord.Color.gold(), description=f"⚠️ {text}")
embed = discord.Embed(color=discord.Color.gold(), description=f'⚠️ {text}')
default_footer(interaction, embed)
return embed
@@ -45,14 +47,15 @@ def error_fatal(interaction: discord.Interaction, text: str) -> discord.Embed:
Parameters
-----------
interaction (discord.Interaction): Discord interaction context
interaction (discord.Interaction): Slash command context object
text (str): The error message
Returns
-----------
(discord.Embed): An embed object based on the template with the specified text
"""
embed = discord.Embed(color=discord.Color.red(), description=f"❌ {text}")
embed = discord.Embed(color=discord.Color.red(), description=f'❌ {text}')
default_footer(interaction, embed)
return embed
@@ -64,14 +67,15 @@ def success(interaction: discord.Interaction, text: str) -> discord.Embed:
Parameters
-----------
interaction (discord.Interaction): Discord interaction context
interaction (discord.Interaction): Slash command context object
text (str): The message
Returns
-----------
discord.Embed: An embed object based on the template with the specified text
"""
embed = discord.Embed(color=discord.Color.green(), description=f"✅ {text}")
embed = discord.Embed(color=discord.Color.green(), description=f'✅ {text}')
default_footer(interaction, embed)
return embed
+3 -6
View File
@@ -3,18 +3,15 @@ from math import ceil
@contextmanager
def ignore_exception(*exceptions) -> None:
def ignore_exception(*exceptions: Exception):
"""
Ignores the given exceptions
Parameters
----------
*exceptions: The exceptions you want to ignore
Returns
----------
None
*exceptions tuple[Exception]: The exceptions you want to ignore
"""
try:
yield
except exceptions:
+2
View File
@@ -3,6 +3,8 @@ import logging.handlers
class BotLogger:
"""Logging config for the bot"""
def __init__(self):
logger = logging.getLogger('discord')
logger.setLevel(logging.INFO)
+34 -32
View File
@@ -11,14 +11,16 @@ from logger import BotLogger
# Load config file
with codecs.open("./src/config/config.yaml", "r", encoding="utf8") as f:
with codecs.open('./src/config/config.yaml', 'r', encoding='utf8') as f:
config = yaml.load(f, Loader=yaml.SafeLoader)
class Bot(commands.Bot):
def __init__(self) -> None:
"""UiO Gaming Bot"""
def __init__(self):
super().__init__(
command_prefix=commands.when_mentioned_or(config["bot"]["prefix"]),
command_prefix=commands.when_mentioned_or(config['bot']['prefix']),
case_insensitive=True,
intents=discord.Intents.all()
)
@@ -26,28 +28,28 @@ class Bot(commands.Bot):
self.logger = BotLogger().logger # Initialize logger
# Connect to database
db = config.get("database", {})
db = config.get('database', {})
self.db_connection = psycopg2.connect(
host=db["host"],
dbname=db["dbname"],
user=db["username"],
password=db["password"],
host=db['host'],
dbname=db['dbname'],
user=db['username'],
password=db['password'],
)
# Fetch misc config values
self.mc_rcon_password = config["minecraft"]["rcon_password"]
self.presence = config["bot"].get("presence", {})
self.api_keys = config.get("api", {})
self.emoji = config.get("emoji", {})
self.misc = config.get("misc", {})
self.config_mode = config.get("mode")
self.mc_rcon_password = config['minecraft']['rcon_password']
self.presence = config['bot'].get('presence', {})
self.api_keys = config.get('api', {})
self.emoji = config.get('emoji', {})
self.misc = config.get('misc', {})
self.config_mode = config.get('mode')
async def setup_hook(self) -> None:
async def setup_hook(self):
# Load cogs
for file in listdir("./src/cogs"):
if file.endswith(".py"):
for file in listdir('./src/cogs'):
if file.endswith('.py'):
name = file[:-3]
await bot.load_extension(f"cogs.{name}")
await bot.load_extension(f'cogs.{name}')
# Sync slash commands to Discord
if self.config_mode == 'prod':
@@ -63,33 +65,33 @@ bot = Bot()
@bot.event
async def on_ready():
if not hasattr(bot, "uptime"):
if not hasattr(bot, 'uptime'):
bot.uptime = time()
# Print bot info
print(f"Username: {bot.user.name}")
print(f"ID: {bot.user.id}")
print(f"Version: {discord.__version__}")
print("." * 50 + "\n")
print(f'Username: {bot.user.name}')
print(f'ID: {bot.user.id}')
print(f'Version: {discord.__version__}')
print('.' * 50 + '\n')
# Set initial presence
# Presence status
status_types = {
"online": discord.Status.online,
"dnd": discord.Status.dnd,
"idle": discord.Status.idle,
"offline": discord.Status.offline,
'online': discord.Status.online,
'dnd': discord.Status.dnd,
'idle': discord.Status.idle,
'offline': discord.Status.offline,
}
status_type = status_types.get(bot.presence["type"].lower(), discord.Status.online)
status_type = status_types.get(bot.presence['type'].lower(), discord.Status.online)
# Presence actitivity
activities = {"playing": 0, "listening": 2, "watching": 3}
activity_type = activities.get(bot.presence["activity"].lower(), 0)
activities = {'playing': 0, 'listening': 2, 'watching': 3}
activity_type = activities.get(bot.presence['activity'].lower(), 0)
await bot.change_presence(
activity=discord.Activity(type=activity_type, name=bot.presence["message"]),
activity=discord.Activity(type=activity_type, name=bot.presence['message']),
status=status_type
)
bot.run(config["bot"]["token"], reconnect=True, log_handler=None)
bot.run(config['bot']['token'], reconnect=True, log_handler=None)