mirror of
https://github.com/UiO-Gaming/mustafa.git
synced 2026-11-05 13:56:48 +01:00
Merge pull request #9 from UiO-Gaming/discord.py-2.0-migration
This commit is contained in:
26 files changed
+3223
-2692
No files matched your search
+102
@@ -0,0 +1,102 @@
|
||||
# Bidragsguide
|
||||
|
||||
Heisann sveisann! Er du interessert i å bidra? Kult!
|
||||
|
||||
Det er derimot noen kodestilsregler jeg ønsker at skal følges. Dette dokumentet fungerer som en defacto regelbok for både meg og/eller andre.
|
||||
|
||||
## Sjekk koden din
|
||||
|
||||
Viktigst av alt er at koden din består flake8 sin PEP8-test. Dette kan du teste på egen maskin ved å installere flake8:
|
||||
|
||||
```
|
||||
pip install flake8
|
||||
```
|
||||
|
||||
for å så kjøre følgende kommando:
|
||||
|
||||
```
|
||||
flake8 --max-line-length=120 --show-source
|
||||
```
|
||||
|
||||
## Regler
|
||||
|
||||
### Typing
|
||||
|
||||
All kode skal være typet til beste evne. Dette betyr at man for eksempel også gjerne bør spesifisere typene innad i en dict eller lignende.
|
||||
|
||||
### Docstrings
|
||||
|
||||
Alle funksjoner skal ha docsstrings som følger denne stilen:
|
||||
|
||||
```python
|
||||
def greet(self, navn: str) -> str:
|
||||
"""
|
||||
Greets the invoking user using the inputted name
|
||||
|
||||
Parameters
|
||||
----------
|
||||
navn (str): The user's inputted name
|
||||
|
||||
Returns
|
||||
----------
|
||||
(str): A greeting
|
||||
"""
|
||||
|
||||
return f'Hello, {name}'
|
||||
```
|
||||
|
||||
Sløyf alt som ikke brukes.
|
||||
|
||||
### Sortering av imports
|
||||
|
||||
Alle imports skal være gruppert på følgende måte:
|
||||
|
||||
1. Standardbibliotek
|
||||
2. Tredjepartsbibliotek
|
||||
3. Lokal kode
|
||||
|
||||
Innad i hver gruppe skal importeringer sortert alfabetisk med vekt på forelderpakken. Det vil si at hvis du importerer bare en del av en pakke skal den fortsatt være sortert i henhold til forelderpakkens navn.
|
||||
|
||||
### Rekkefølge på kommandosjekker (decorators)
|
||||
|
||||
Hver kommando er en funksjon som har et eller flere decorators over seg. Dette er sjekker som utføres før kommandoen kjøres. En av disse konverterer også funksjonen til en faktisk kommando som vi kan kjøre gjennom Discord.
|
||||
|
||||
Decorators skal sorteres som følgende:
|
||||
|
||||
1. is owner
|
||||
2. Guild only
|
||||
3. Bot permissions
|
||||
4. User permissions
|
||||
5. Cooldown
|
||||
6. Kommando (denne må alltid være med)
|
||||
|
||||
Merk deg at ikke alle disse trenger å være med, og ikke alle sjekker som finnes er nevnt her. Bruk hodet og tenk hva som er logisk for deg om du møter på en slik situasjon.
|
||||
|
||||
### Quotation marks
|
||||
|
||||
Ta i bruk enkle quotation marks `'` der det er mulig. Multiline comments skal skrives med dobble quotation marks `"`.
|
||||
|
||||
### Newline mellom docstring og kode samt mellom siste kodelinje returstatement
|
||||
|
||||
Ja, det tittelen sier. Det er et unntak for returstatements hvis det er tatt i bruk early returning.
|
||||
|
||||
### Norske parameternavn i kommandoer
|
||||
|
||||
Selv om Discord.py 2.0 støtter oversettelser, er ikke dette noe vi implementerer. Med tanke på at botten er norsk og for norske brukere må dette reflekteres i parameternavn siden dette er hva Discord bruker som grensesnitt for kommandoer.
|
||||
|
||||
### Engelsk for alt annet
|
||||
|
||||
All annen kode holdes på engelsk. Dette inkluderer kommentarer.
|
||||
|
||||
Et tips er å ha et engelsk funksjonsnavn, men spesifisere i decoratoren over med navnparameteren.
|
||||
|
||||
### Avhengigheter
|
||||
|
||||
Hvis en ny avhengighet trengs, sørg for å spesifisere major og minor versjon i requirementsfila.
|
||||
|
||||
|
||||
## Ønsket utforming av ny funksjonalitet
|
||||
|
||||
- Bruk embeds til feilmeldinger og som respons om mulig.
|
||||
- Sett cooldown til 5 sekunder for kommandoer som krever eksterne API kall eller særlig mye prosessering.
|
||||
- Ellers, settes denne til 2 sekunder.
|
||||
@@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
UiO Gaming's multi-purpose Discord bot
|
||||
Copyright (C) 2022 Leander West Furumo
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
uiogaming-bot Copyright (C) 2022 Leander West Furumo
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
# UiO Gaming Discord Bot
|
||||
|
||||
UiO Gaming Discord Bot er en chattebot for ulike formål. Den skal hjelpe oss med ulike oppgaver og ha mange ulike funksjoner
|
||||
UiO Gaming Discord Bot er en chattebot for ulike formål. Hvilke formål det er, er jeg ikke helt sikker på.
|
||||
|
||||
Mer dokumentasjon kommer snart™
|
||||
## Installasjon
|
||||
|
||||
1. Fjern `.example` fra [config.yaml.example](src/config/config.yaml) i configmappen
|
||||
|
||||
2. Fyll inn verdiene i denne configfilen
|
||||
|
||||
Du kan så bevege deg videre til ett av to alternativer.
|
||||
|
||||
### Valgmulighet 1 - Manuelt
|
||||
|
||||
Du bør ha gjort følgende:
|
||||
|
||||
- Installert Python 3.10+
|
||||
- Ha en Postgresql database satt opp
|
||||
|
||||
|
||||
1. Installer avhengigheter
|
||||
|
||||
```
|
||||
pip install -r requirements.txt -U
|
||||
```
|
||||
|
||||
2. Kjør bot
|
||||
|
||||
```
|
||||
python src/run.py
|
||||
```
|
||||
|
||||
### Valgmulighet 2 - Docker
|
||||
|
||||
```
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
## Bidra
|
||||
|
||||
Se [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
+9
-9
@@ -1,9 +1,9 @@
|
||||
discord.py
|
||||
pyyaml
|
||||
requests
|
||||
asyncio
|
||||
psutil
|
||||
pillow
|
||||
aiocron
|
||||
psycopg2
|
||||
mcrcon
|
||||
aiocron==1.8.*
|
||||
asyncio==3.4.*
|
||||
discord.py==2.1.*
|
||||
mcrcon==0.7.*
|
||||
pillow==9.3.*
|
||||
psutil==5.9.*
|
||||
psycopg2==2.9.*
|
||||
pyyaml==6.0.*
|
||||
requests==2.28.*
|
||||
+1127
-1161
File diff suppressed because it is too large.
Load diff
+222
-93
@@ -1,21 +1,30 @@
|
||||
from discord.ext import commands
|
||||
import discord
|
||||
|
||||
import psycopg2
|
||||
import aiocron
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from cogs.utils import embed_templates, discord_utils
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
import psycopg2
|
||||
|
||||
from cogs.utils import discord_utils, embed_templates
|
||||
|
||||
|
||||
class Birthday(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
"""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"""
|
||||
|
||||
self.cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS birthdays (
|
||||
@@ -26,22 +35,61 @@ class Birthday(commands.Cog):
|
||||
)
|
||||
self.bot.db_connection.commit()
|
||||
|
||||
def _fetch_user_birthday(self, user_id):
|
||||
self.cursor.execute("SELECT birthday FROM birthdays WHERE discord_id = (%s)", (user_id,))
|
||||
return self.cursor.fetchone()
|
||||
def __fetch_user_birthday(self, user_id: int) -> datetime | None:
|
||||
"""
|
||||
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 for a user
|
||||
|
||||
Parameters
|
||||
----------
|
||||
user_id (int): The Discord user ID
|
||||
|
||||
Returns
|
||||
----------
|
||||
(datetime): The date of the next birthday
|
||||
"""
|
||||
|
||||
def _fetch_user_next_birthday(self, user_id):
|
||||
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,)
|
||||
)
|
||||
return self.cursor.fetchone()
|
||||
results = self.cursor.fetchone()
|
||||
if results:
|
||||
birthday = results[2]
|
||||
return datetime(birthday.year, birthday.month, birthday.day)
|
||||
else:
|
||||
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
|
||||
|
||||
Returns
|
||||
----------
|
||||
(list[tuple[int, datetime, datetime]]): A list of tuples containing the user ID, the date of birth and the next birthday
|
||||
"""
|
||||
|
||||
def _fetch_next_birthdays(self):
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT *, CAST(birthday + ((EXTRACT(YEAR FROM AGE(birthday)) + 1) * interval '1' YEAR) AS DATE) AS next_birthday
|
||||
@@ -50,124 +98,205 @@ class Birthday(commands.Cog):
|
||||
LIMIT 5
|
||||
"""
|
||||
)
|
||||
return self.cursor.fetchall()
|
||||
results = self.cursor.fetchall()
|
||||
|
||||
# Convert date objects to datetime objects
|
||||
for result in results:
|
||||
_, birthday, next_birthday = result
|
||||
birthday = datetime(birthday.year, birthday.month, birthday.day)
|
||||
next_birthday = datetime(next_birthday.year, next_birthday.month, next_birthday.day)
|
||||
|
||||
return results
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
def _set_user_birthday(self, user_id, birthday):
|
||||
try:
|
||||
self.cursor.execute("INSERT INTO birthdays (discord_id, birthday) VALUES (%s, %s)", (user_id, birthday))
|
||||
self.cursor.execute(
|
||||
"""
|
||||
INSERT INTO birthdays (discord_id, birthday)
|
||||
VALUES (%s, %s)
|
||||
""", (user_id, birthday))
|
||||
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 * * *")
|
||||
async def _check_birthdays(self):
|
||||
await asyncio.sleep(1)
|
||||
self.cursor.execute(
|
||||
"""
|
||||
SELECT *
|
||||
FROM birthdays
|
||||
WHERE EXTRACT(MONTH FROM birthday) = EXTRACT(MONTH FROM current_date)
|
||||
AND EXTRACT(DAY FROM birthday) = EXTRACT(DAY FROM current_date);
|
||||
"""
|
||||
)
|
||||
# @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
|
||||
#
|
||||
# self.cursor.execute(
|
||||
# """
|
||||
# SELECT *
|
||||
# FROM birthdays
|
||||
# WHERE EXTRACT(MONTH FROM birthday) = EXTRACT(MONTH FROM current_date)
|
||||
# AND EXTRACT(DAY FROM birthday) = EXTRACT(DAY FROM current_date);
|
||||
# """
|
||||
# )
|
||||
#
|
||||
# birthdays = self.cursor.fetchall()
|
||||
# if birthdays:
|
||||
# guild = self.bot.get_guild(747542543750660178)
|
||||
# channel = guild.get_channel(747542544291987597)
|
||||
# for birthday in birthdays:
|
||||
# user = self.bot.get_user(birthday[0])
|
||||
# if user:
|
||||
# await channel.send(f'Gratulrer med dagen {user.mention}!')
|
||||
|
||||
birthdays = self.cursor.fetchall()
|
||||
if birthdays:
|
||||
guild = self.bot.get_guild(747542543750660178)
|
||||
channel = guild.get_channel(747542544291987597)
|
||||
for birthday in birthdays:
|
||||
user = self.bot.get_user(birthday[0])
|
||||
if user:
|
||||
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(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.
|
||||
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
@commands.command()
|
||||
async def settbursdag(self, ctx, date):
|
||||
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.strptime(date, "%d.%m.%Y")
|
||||
date = datetime(år, måned, dag)
|
||||
except ValueError:
|
||||
return await ctx.send(embed=embed_templates.error_fatal(ctx, text="Feil format, gjøk!"))
|
||||
return await interaction.response.send_message(
|
||||
embed=embed_templates.error_fatal(interaction, text='ikke en gyldig dato, gjøk!'),
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
if date.year < 1970:
|
||||
return await ctx.send(
|
||||
embed=embed_templates.error_fatal(ctx, text="Ok boomer, men nei. Hvorfor? Unix timestamps. Google it")
|
||||
return await interaction.response.send_message(
|
||||
embed=embed_templates.error_fatal(interaction, text='Ok boomer, men nei. Hvorfor? Unix timestamps. Google it'),
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
self._set_user_birthday(ctx.author.id, date)
|
||||
if date > datetime.now():
|
||||
return await interaction.response.send_message(
|
||||
embed=embed_templates.error_fatal(interaction, text='Du kan ikke sette en fremtidig dato!'),
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
embed = embed_templates.success(ctx, text=f"Bursdag satt til <t:{int(date.timestamp())}:D>")
|
||||
await ctx.send(embed=embed)
|
||||
self.__set_user_birthday(interaction.user.id, date)
|
||||
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
@commands.command()
|
||||
async def fjernbursdag(self, ctx):
|
||||
embed = embed_templates.success(interaction, text=f'Bursdag satt til {discord.utils.format_dt(date, style="D")}')
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
self.cursor.execute("DELETE FROM birthdays WHERE discord_id = (%s)", (ctx.author.id,))
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 5)
|
||||
@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(ctx, text="Bursdag fjernet")
|
||||
await ctx.send(embed=embed)
|
||||
embed = embed_templates.success(interaction, text='Bursdag fjernet')
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
@commands.command()
|
||||
async def bursdag(self, ctx, *, bruker: discord.Member = None):
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 5)
|
||||
@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 = ctx.author
|
||||
bruker = interaction.user
|
||||
|
||||
user = self._fetch_user_birthday(bruker.id)
|
||||
user = self.__fetch_user_birthday(bruker.id)
|
||||
|
||||
if not user:
|
||||
return await ctx.send(
|
||||
embed=embed_templates.error_fatal(ctx, text="Brukeren har ikke registrert bursdagen sin")
|
||||
return await interaction.response.send_message(
|
||||
embed=embed_templates.error_fatal(interaction, text='Brukeren har ikke registrert bursdagen sin')
|
||||
)
|
||||
|
||||
birthday = datetime(user[0].year, user[0].month, user[0].day)
|
||||
# Current age information
|
||||
birthday = datetime(user.year, user.month, user.day)
|
||||
days_old = (datetime.now() - birthday).days
|
||||
years_old = relativedelta(datetime.now(), birthday).years
|
||||
|
||||
# Next birthday
|
||||
birthday_current_year = birthday.replace(year=datetime.now().year)
|
||||
if (datetime.now() - birthday_current_year).days < 0:
|
||||
next_birthday = birthday_current_year
|
||||
else:
|
||||
next_birthday = birthday_current_year.replace(year=datetime.now().year + 1)
|
||||
# Next birthday information
|
||||
next_birthday = self.__fetch_user_next_birthday(bruker.id)
|
||||
next_birthday_days = (next_birthday - datetime.now()).days
|
||||
|
||||
embed = discord.Embed(description=bruker.mention, color=discord_utils.get_user_color(bruker))
|
||||
embed.set_thumbnail(url=bruker.avatar_url)
|
||||
embed.set_author(name=bruker.name, icon_url=bruker.avatar_url)
|
||||
embed.add_field(name="Bursdag", value=f"<t:{int(birthday.timestamp())}: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(ctx, embed)
|
||||
await ctx.send(embed=embed)
|
||||
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_templates.default_footer(interaction, embed)
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
@commands.command()
|
||||
async def kommendebursdager(self, ctx):
|
||||
@app_commands.guild_only()
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 5)
|
||||
@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.
|
||||
|
||||
next_birthdays = self._fetch_next_birthdays()
|
||||
Parameters
|
||||
----------
|
||||
interaction (discord.Interaction): Slash command context object
|
||||
"""
|
||||
|
||||
next_birthdays = self.__fetch_next_birthdays()
|
||||
|
||||
if not next_birthdays:
|
||||
return await ctx.send(embed=embed_templates.error_fatal(ctx, 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:
|
||||
discord_user = ctx.guild.get_member(user[0])
|
||||
if not discord_user:
|
||||
user_id, _, next_birthday = user
|
||||
try:
|
||||
discord_user = await interaction.guild.fetch_member(user_id) # Guild should always be available because of guild_only
|
||||
except (discord.NotFound, discord.HTTPException):
|
||||
continue
|
||||
|
||||
next_birthday = datetime(user[2].year, user[2].month, user[2].day)
|
||||
next_birthday_days = (next_birthday - datetime.now()).days
|
||||
birthday_string += f"{discord_user.name}#{discord_user.discriminator} - <t:{int(next_birthday.timestamp())}:D> ({next_birthday_days} dager)\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'
|
||||
|
||||
embed = discord.Embed(title="Kommende bursdager", description=birthday_string)
|
||||
embed_templates.default_footer(ctx, embed)
|
||||
await ctx.send(embed=embed)
|
||||
if not birthday_string:
|
||||
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_templates.default_footer(interaction, embed)
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Birthday(bot))
|
||||
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))
|
||||
+97
-71
@@ -1,48 +1,55 @@
|
||||
from discord.ext import commands
|
||||
import discord
|
||||
|
||||
from time import time, perf_counter
|
||||
from os import environ, getpid
|
||||
import platform
|
||||
from os import getpid, environ
|
||||
from time import time
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
from psutil import Process
|
||||
|
||||
from cogs.utils import embed_templates
|
||||
|
||||
|
||||
class BotInfo(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
"""View information about the bot"""
|
||||
|
||||
def __init__(self, bot: commands.Bot):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
bot (commands.Bot): The bot instance
|
||||
"""
|
||||
|
||||
self.bot = bot
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True, external_emojis=True)
|
||||
@commands.cooldown(1, 2, commands.BucketType.guild)
|
||||
@commands.command(aliases=['info', 'about', 'om'])
|
||||
async def botinfo(self, ctx):
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True, external_emojis=True)
|
||||
@app_commands.checks.cooldown(1, 2)
|
||||
@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)
|
||||
|
||||
# Ping
|
||||
start = perf_counter()
|
||||
status_msg = await ctx.send('Beregner ping...')
|
||||
end = perf_counter()
|
||||
ping = int((end - start) * 1000)
|
||||
|
||||
# Memory usage
|
||||
process = Process(getpid())
|
||||
memory_usage = round(process.memory_info().rss / 1000000, 1)
|
||||
|
||||
# Member stats
|
||||
"""
|
||||
This is a pretty stupid way of doing things but it's the best I can come up with.
|
||||
Using curly brackets for both dicts and sets is retarded becuase
|
||||
I have to do this shit in order to create a fucking empty set.
|
||||
|
||||
Apparently you can't access user presences, only member presences
|
||||
Because of that I have to use sets instead of ints in order to not count duplicate users.
|
||||
Fucking hell discord...
|
||||
"""
|
||||
#
|
||||
# This is a pretty stupid way of doing things but it's the best I can come up with.
|
||||
# Using curly brackets for both dicts and sets is retarded becuase
|
||||
# I have to do this shit in order to create a fucking empty set.
|
||||
#
|
||||
# Apparently you can't access user presences, only member presences
|
||||
# Because of that I have to use sets instead of ints in order to not count duplicate users.
|
||||
# Fucking hell discord...
|
||||
total_members = set([])
|
||||
online_members = set([])
|
||||
idle_members = set([])
|
||||
@@ -61,12 +68,12 @@ class BotInfo(commands.Cog):
|
||||
offline_members.add(member.id)
|
||||
|
||||
# Build embed
|
||||
embed = discord.Embed(color=ctx.me.color, url=self.bot.misc['website'])
|
||||
embed.set_author(name=dev.name, icon_url=dev.avatar_url)
|
||||
embed.set_thumbnail(url=self.bot.user.avatar_url)
|
||||
embed = discord.Embed(color=interaction.client.user.color, url=self.bot.misc['website'])
|
||||
embed.set_author(name=dev.name, icon_url=dev.display_avatar)
|
||||
embed.set_thumbnail(url=self.bot.user.display_avatar)
|
||||
embed.add_field(name='Dev', value=f'{dev.mention}\n{dev.name}#{dev.discriminator}')
|
||||
embed.add_field(name='Oppetid', value=self.get_uptime())
|
||||
embed.add_field(name='Ping', value=f'Ekte ping: {ping} ms\nWebsocket ping: {int(self.bot.latency * 1000)} ms')
|
||||
embed.add_field(name='Oppetid', value=self.__get_uptime())
|
||||
embed.add_field(name='Ping', value=f'Websocket ping: {self.__get_ping()} ms')
|
||||
embed.add_field(name='Servere', value=len(self.bot.guilds))
|
||||
embed.add_field(name='Discord.py', value=discord.__version__)
|
||||
embed.add_field(name='Python', value=platform.python_version())
|
||||
@@ -81,49 +88,60 @@ class BotInfo(commands.Cog):
|
||||
f'{self.bot.emoji["offline"]}{len(offline_members)}')
|
||||
embed.add_field(name='Lenker', value=f'[Nettside]({self.bot.misc["website"]}) | ' +
|
||||
f'[Kildekode]({self.bot.misc["source_code"]})')
|
||||
embed_templates.default_footer(ctx, embed)
|
||||
await status_msg.edit(embed=embed, content=None)
|
||||
embed_templates.default_footer(interaction, embed)
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.cooldown(1, 2, commands.BucketType.guild)
|
||||
@commands.command(aliases=['uptime'])
|
||||
async def oppetid(self, ctx):
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 2)
|
||||
@app_commands.command(name='oppetid', description='Se hvor lenge botten har kjørt')
|
||||
async def uptime(self, interaction: discord.Interaction):
|
||||
"""
|
||||
Viser hvor lenge bot har vært kjørende
|
||||
"""
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color)
|
||||
embed.add_field(name='🔌 Oppetid', value=self.get_uptime())
|
||||
embed_templates.default_footer(ctx, embed)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.cooldown(1, 2, commands.BucketType.guild)
|
||||
@commands.command()
|
||||
async def ping(self, ctx):
|
||||
"""
|
||||
Viser bot sin ping
|
||||
"""
|
||||
|
||||
start = perf_counter()
|
||||
status_msg = await ctx.send('Pinging...')
|
||||
end = perf_counter()
|
||||
ping = int((end - start) * 1000)
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color)
|
||||
embed.add_field(
|
||||
name='📶 Ping',
|
||||
value=f'**Ekte ping:** {ping} ms\n**Websocket ping:** {int(self.bot.latency * 1000)} ms'
|
||||
)
|
||||
embed_templates.default_footer(ctx, embed)
|
||||
await status_msg.edit(embed=embed, content=None)
|
||||
|
||||
def get_uptime(self) -> str:
|
||||
"""
|
||||
Returns the current uptime of the bot in string format
|
||||
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())
|
||||
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, 2)
|
||||
@app_commands.command(name='ping', description='Se botten sin nåværende ping')
|
||||
async def ping(self, interaction: discord.Interaction):
|
||||
"""
|
||||
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',
|
||||
value=f'**Websocket ping:** {self.__get_ping()} ms'
|
||||
)
|
||||
embed_templates.default_footer(interaction, embed)
|
||||
await interaction.response.send_message(embed=embed, content=None)
|
||||
|
||||
def __get_ping(self) -> int:
|
||||
"""
|
||||
Get the bot's ping in milliseconds
|
||||
|
||||
Returns
|
||||
----------
|
||||
(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
|
||||
|
||||
Returns
|
||||
----------
|
||||
@@ -139,5 +157,13 @@ class BotInfo(commands.Cog):
|
||||
return f'{days}d, {hours}t, {minutes}m, {seconds}s'
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(BotInfo(bot))
|
||||
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))
|
||||
@@ -4,7 +4,7 @@ import asyncio
|
||||
|
||||
|
||||
class CameraChannel(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
def __init__(self, bot: commands.Bot):
|
||||
self.bot = bot
|
||||
|
||||
async def on_voice_state_update(self, member, before, after):
|
||||
@@ -20,7 +20,7 @@ class CameraChannel(commands.Cog):
|
||||
await member.move_to(channel=None)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
async def setup(bot: commands.Bot):
|
||||
#bot.add_listener(CameraChannel(bot).on_voice_state_update, 'on_voice_state_update')
|
||||
#bot.add_cog(CameraChannel(bot))
|
||||
#await bot.add_cog(CameraChannel(bot))
|
||||
pass
|
||||
@@ -47,7 +47,7 @@ class CreditUser:
|
||||
|
||||
|
||||
class SocialCredit(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
def __init__(self, bot: commands.Bot):
|
||||
self.bot = bot
|
||||
self.fuck_uwu.start()
|
||||
|
||||
@@ -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,15 +259,15 @@ 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)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(SocialCredit(bot))
|
||||
async def setup(bot: commands.Bot):
|
||||
await bot.add_cog(SocialCredit(bot))
|
||||
@@ -7,10 +7,10 @@ import json
|
||||
|
||||
|
||||
class Vær(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
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,9 +19,9 @@ 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.set_author(name=dev.name, icon_url=dev.avatar_url)
|
||||
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
|
||||
klokkeslett = 0
|
||||
@@ -35,12 +35,12 @@ 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)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Vær(bot))
|
||||
async def setup(bot: commands.Bot):
|
||||
await bot.add_cog(Vær(bot))
|
||||
@@ -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,11 +15,11 @@ 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)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Wiki(bot))
|
||||
async def setup(bot: commands.Bot):
|
||||
await bot.add_cog(Wiki(bot))
|
||||
+195
-270
@@ -1,251 +1,63 @@
|
||||
from discord.ext import commands
|
||||
import discord
|
||||
|
||||
import asyncio
|
||||
from sys import exit
|
||||
from os import listdir, system
|
||||
import socket
|
||||
from requests import get
|
||||
from os import listdir
|
||||
import requests
|
||||
|
||||
from cogs.utils import misc_utils, embed_templates
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
from cogs.utils import embed_templates
|
||||
|
||||
|
||||
class DevTools(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
"""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.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command(aliases=['shutdown', 'stoppbått'])
|
||||
async def stoppbot(self, ctx):
|
||||
"""
|
||||
Log out and shut down the bot
|
||||
"""
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color, description='Logger av...')
|
||||
await ctx.send(embed=embed)
|
||||
await self.bot.logout()
|
||||
exit('Bot stopped through command')
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command()
|
||||
async def custommsg(self, ctx, channel: int, *text):
|
||||
@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)
|
||||
await channel.send(custommessage)
|
||||
|
||||
# Send confirmation message to the invoker
|
||||
embed = discord.Embed(color=ctx.me.color)
|
||||
embed.add_field(name='Sent', value=custommessage)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.is_owner()
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command(aliases=['listservers'])
|
||||
async def listguilds(self, ctx, page=0):
|
||||
"""
|
||||
Lists all guilds the bot is a member of
|
||||
"""
|
||||
|
||||
guild_list = [f'{guild.name} - {guild.id}' for guild in self.bot.guilds]
|
||||
|
||||
page_data = misc_utils.paginator(guild_list, int(page))
|
||||
page = page_data['page']
|
||||
pagecount = page_data['pagecount']
|
||||
guilds = '\n'.join(page_data['page_content'])
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color)
|
||||
embed.add_field(name='Guilds', value=guilds)
|
||||
embed.set_footer(text=f'page: {page}/{pagecount}')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command()
|
||||
async def listusers(self, ctx, page=0):
|
||||
"""
|
||||
Lists all users the bot has access to
|
||||
"""
|
||||
|
||||
user_list = [f'{user.name}#{user.discriminator} - {user.id}' for user in self.bot.users]
|
||||
page_data = misc_utils.paginator(user_list, int(page))
|
||||
|
||||
pagecount = page_data['pagecount']
|
||||
page = page_data['page']
|
||||
users = '\n'.join(page_data['page_content'])
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color)
|
||||
embed.add_field(name='Users', value=users)
|
||||
embed.set_footer(text=f'page: {page}/{pagecount}')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command(alises=['unloadcog', 'disablecog'])
|
||||
async def unload(self, ctx, cog: str):
|
||||
"""
|
||||
Disables a specified cog
|
||||
"""
|
||||
|
||||
for file in listdir('./src/cogs'):
|
||||
if file.endswith('.py'):
|
||||
name = file[:-3]
|
||||
if name == cog:
|
||||
self.bot.unload_extension(f'cogs.{name}')
|
||||
embed = discord.Embed(color=ctx.me.color, description=f'{cog} has been disabled')
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command(aliases=['loadcog', 'enablecog'])
|
||||
async def load(self, ctx, cog):
|
||||
"""
|
||||
Enables a speicifed cog
|
||||
"""
|
||||
|
||||
for file in listdir('./src/cogs'):
|
||||
if file.endswith('.py'):
|
||||
name = file[:-3]
|
||||
if name == cog:
|
||||
self.bot.load_extension(f'cogs.{name}')
|
||||
embed = discord.Embed(color=ctx.me.color, description=f'{cog} loaded')
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command(aliases=['reloadcog'])
|
||||
async def reload(self, ctx, cog):
|
||||
"""
|
||||
Reloads a specified cog
|
||||
"""
|
||||
|
||||
for file in listdir('./src/cogs'):
|
||||
if file.endswith('.py'):
|
||||
name = file[:-3]
|
||||
if name == cog:
|
||||
self.bot.reload_extension(f'cogs.{name}')
|
||||
embed = discord.Embed(color=ctx.me.color, description=f'{cog} has been reloaded')
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command()
|
||||
async def reloadcommand(self, ctx, cog):
|
||||
"""
|
||||
Reloads a specified cog
|
||||
"""
|
||||
|
||||
for file in listdir('./src/cogs'):
|
||||
if file.endswith('.py'):
|
||||
name = file[:-3]
|
||||
if name == cog:
|
||||
self.bot.reload_extension(f'cogs.{name}')
|
||||
embed = discord.Embed(color=ctx.me.color, description=f'{cog} has been reloaded')
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command(aliases=['reloadunloadedcogs'])
|
||||
async def reloadunloaded(self, ctx):
|
||||
"""
|
||||
Reloads all cogs, including previously disabled ones
|
||||
"""
|
||||
|
||||
for file in listdir('./src/cogs'):
|
||||
if file.endswith('.py'):
|
||||
name = file[:-3]
|
||||
self.bot.unload_extension(f'cogs.{name}')
|
||||
|
||||
for file in listdir('./src/cogs'):
|
||||
if file.endswith('.py'):
|
||||
name = file[:-3]
|
||||
self.bot.load_extension(f'cogs.{name}')
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color, description='Reloaded all cogs')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command(aliases=['reloadallcogs'])
|
||||
async def reloadall(self, ctx):
|
||||
"""
|
||||
Reloads all previously enabled cogs
|
||||
"""
|
||||
|
||||
for file in listdir('./src/cogs'):
|
||||
if file.endswith('.py'):
|
||||
name = file[:-3]
|
||||
self.bot.reload_extension(f'cogs.{name}')
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color, description='Reloaded all previously enabled cogs')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.is_owner()
|
||||
@commands.command()
|
||||
async def cmd(self, ctx, *, command: str):
|
||||
"""
|
||||
Execute terminal commands
|
||||
"""
|
||||
|
||||
system(command)
|
||||
await ctx.send('Done!')
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command()
|
||||
async def localip(self, ctx):
|
||||
"""
|
||||
Sends LAN IP-address
|
||||
"""
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.connect(('8.8.8.8', 80))
|
||||
embed = discord.Embed(color=ctx.me.color)
|
||||
embed.add_field(name='LAN IP-address', value=s.getsockname()[0])
|
||||
await ctx.send(embed=embed)
|
||||
s.close()
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command()
|
||||
async def publicip(self, ctx):
|
||||
"""
|
||||
Sends WAN IP-address
|
||||
inb4 I leak my IP-address
|
||||
"""
|
||||
|
||||
data = get('https://wtfismyip.com/json').json()
|
||||
ip = data['YourFuckingIPAddress']
|
||||
location = data['YourFuckingLocation']
|
||||
isp = data['YourFuckingISP']
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color)
|
||||
embed.add_field(name='WAN IP-address', value=f'{ip}\n{location}\n{isp}')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.cooldown(1, 10, commands.BucketType.guild)
|
||||
@commands.command()
|
||||
async def changepresence(self, ctx, activity_type, message, status_type):
|
||||
@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 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 = {
|
||||
@@ -253,10 +65,7 @@ class DevTools(commands.Cog):
|
||||
'listening': 2,
|
||||
'watching': 3
|
||||
}
|
||||
if activity_type in activities:
|
||||
activity_type = activities[activity_type]
|
||||
else:
|
||||
activity_type = 0
|
||||
activity_type = activities.get(activity_type, 0)
|
||||
|
||||
status_types = {
|
||||
'online': discord.Status.online,
|
||||
@@ -264,45 +73,49 @@ class DevTools(commands.Cog):
|
||||
'idle': discord.Status.idle,
|
||||
'offline': discord.Status.offline
|
||||
}
|
||||
if status_type in status_types:
|
||||
status_type = status_types[status_type]
|
||||
else:
|
||||
status_type = discord.Status.online
|
||||
status_type = status_types.get(status_type, discord.Status.online)
|
||||
|
||||
await self.bot.change_presence(
|
||||
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.bot_has_permissions(embed_links=True, add_reactions=True)
|
||||
@commands.is_owner()
|
||||
@commands.command()
|
||||
async def leave(self, ctx, *guild_id: int):
|
||||
@commands.bot_has_permissions(embed_links=True, add_reactions=True)
|
||||
@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 guild_id == ():
|
||||
guild_id = ctx.guild.id
|
||||
else:
|
||||
guild_id = guild_id
|
||||
# If no guild id is specified, leave the current guild
|
||||
guild_id = guild_id if guild_id else ctx.guild.id
|
||||
|
||||
# Get guild
|
||||
try:
|
||||
guild = await self.bot.fetch_guild(guild_id)
|
||||
except discord.errors.Forbidden:
|
||||
embed = embed_templates.error_fatal(ctx, text='Bot is not a member of this guild')
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
# Send confirmation message for leaving
|
||||
confirmation_msg = await ctx.send(f'Do you want to leave {guild.name} (`{guild.id}`)?')
|
||||
await confirmation_msg.add_reaction('✅')
|
||||
|
||||
def comfirm(reaction, user):
|
||||
# Check confirmation
|
||||
def comfirm(reaction: discord.Reaction, user: discord.Member):
|
||||
return user == ctx.author and str(reaction.emoji) == '✅'
|
||||
|
||||
try:
|
||||
reaction, user = await self.bot.wait_for('reaction_add', timeout=15.0, check=comfirm)
|
||||
await self.bot.wait_for('reaction_add', timeout=15.0, check=comfirm)
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.message.delete()
|
||||
await confirmation_msg.delete()
|
||||
@@ -314,46 +127,158 @@ class DevTools(commands.Cog):
|
||||
except discord.errors.Forbidden:
|
||||
pass
|
||||
|
||||
@commands.is_owner()
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.is_owner()
|
||||
@commands.command()
|
||||
async def resetcooldown(self, ctx, command: str):
|
||||
@commands.command(name='publicip', description='Hent den offentlige IP-adressen til serveren botten kjører på')
|
||||
async def publicip(self, ctx: commands.Context):
|
||||
"""
|
||||
Resets the cooldown period for a specified command
|
||||
Sends WAN IP-address. Inb4 I leak my IP-address
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ctx (commands.Context): Context object
|
||||
"""
|
||||
|
||||
try:
|
||||
self.bot.get_command(command).reset_cooldown(ctx)
|
||||
except AttributeError:
|
||||
embed = embed_templates.error_fatal(ctx, text=f'{command} is not a command')
|
||||
return await ctx.send(embed=embed)
|
||||
data = requests.get('https://wtfismyip.com/json', timeout=10).json()
|
||||
ip = data['YourFuckingIPAddress']
|
||||
location = data['YourFuckingLocation']
|
||||
isp = data['YourFuckingISP']
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color, description='Cooldown reset!')
|
||||
embed = discord.Embed(color=ctx.me.color)
|
||||
embed.add_field(name='WAN IP-address', value=f'{ip}\n{location}\n{isp}')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True, external_emojis=True)
|
||||
@commands.is_owner()
|
||||
@commands.command()
|
||||
async def allemoji(self, ctx):
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.group(name='cogs', description='Administrer cogs')
|
||||
async def cogs(self, ctx: commands.Context):
|
||||
"""
|
||||
Sends all emoji the bot has access to
|
||||
Cog management commands
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ctx (commands.Context): Context object
|
||||
"""
|
||||
|
||||
embed = discord.Embed(colour=ctx.me.color)
|
||||
if not ctx.invoked_subcommand:
|
||||
await ctx.send_help(ctx.command)
|
||||
|
||||
emoji_string = ''
|
||||
for guild in self.bot.guilds:
|
||||
emoji_string += f'\n**{guild.name}**\n'
|
||||
for emoji in guild.emojis:
|
||||
if len(emoji_string) > 2000:
|
||||
embed.description = emoji_string
|
||||
await ctx.send(embed=embed)
|
||||
emoji_string = f'\n**{guild.name}**\n'
|
||||
emoji_string += f'{emoji} '
|
||||
@cogs.command(name='unload', description='Avslutt en cog')
|
||||
async def cogs_unload(self, ctx: commands.Context, cog: str):
|
||||
"""
|
||||
Disables a specified cog
|
||||
|
||||
embed.description = emoji_string
|
||||
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]
|
||||
if name == cog:
|
||||
await self.bot.unload_extension(f'cogs.{name}')
|
||||
embed = discord.Embed(color=ctx.me.color, description=f'{cog} has been disabled')
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@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]
|
||||
if name == cog:
|
||||
await self.bot.load_extension(f'cogs.{name}')
|
||||
embed = discord.Embed(color=ctx.me.color, description=f'{cog} loaded')
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@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]
|
||||
if name == cog:
|
||||
await self.bot.reload_extension(f'cogs.{name}')
|
||||
embed = discord.Embed(color=ctx.me.color, description=f'{cog} has been reloaded')
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@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'):
|
||||
name = file[:-3]
|
||||
await self.bot.unload_extension(f'cogs.{name}')
|
||||
|
||||
# Load all cogs
|
||||
for file in listdir('./src/cogs'):
|
||||
if file.endswith('.py'):
|
||||
name = file[:-3]
|
||||
await self.bot.load_extension(f'cogs.{name}')
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color, description='Reloaded all cogs')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@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]
|
||||
await self.bot.reload_extension(f'cogs.{name}')
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color, description='Reloaded all previously enabled cogs')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(DevTools(bot))
|
||||
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))
|
||||
+113
-38
@@ -1,38 +1,71 @@
|
||||
from discord.ext import commands
|
||||
import discord
|
||||
|
||||
import traceback
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
|
||||
from cogs.utils import embed_templates
|
||||
from cogs.utils.misc_utils import ignore_exception
|
||||
|
||||
|
||||
class Errors(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
"""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 # Set error handler for slash commands
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_command(self, ctx):
|
||||
async def on_command(self, ctx: commands.Context):
|
||||
"""
|
||||
Prints command execution metadata
|
||||
Logs prefix command execution metadata
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ctx (commands.Context): Context object
|
||||
"""
|
||||
|
||||
print(
|
||||
f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")} | ' +
|
||||
f'{"❌ " if ctx.command_failed else "✔ "} {ctx.command} - ' +
|
||||
self.bot.logger.info(
|
||||
f'{"❌ " if ctx.command_failed else "✔ "} {ctx.command} | ' +
|
||||
f'{ctx.author.name}#{ctx.author.discriminator} ({ctx.author.id}) | ' +
|
||||
f'{ctx.guild.id}-{ctx.channel.id}-{ctx.message.id}'
|
||||
)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_command_error(self, ctx, error):
|
||||
async def on_app_command_completion(self, interaction: discord.Interaction, command: app_commands.Command | app_commands.ContextMenu):
|
||||
"""
|
||||
Returns something based on the type of command error
|
||||
Logs slash command execution metadata
|
||||
|
||||
Parameters
|
||||
----------
|
||||
interaction (discord.Interaction): Slash command context object
|
||||
command (app_commands.Command | app_commands.ContextMenu): Command object
|
||||
"""
|
||||
|
||||
# Reset cooldown if command throws an error
|
||||
self.bot.logger.info(
|
||||
f'{"❌ " if interaction.command_failed else "✔ "} {command.name} | ' +
|
||||
f'{interaction.user.name}#{interaction.user.discriminator} ({interaction.user.id}) | ' +
|
||||
f'{interaction.guild_id}-{interaction.channel_id}-{interaction.id}'
|
||||
)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_command_error(self, ctx: commands.Context, error: commands.CommandError):
|
||||
"""
|
||||
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)
|
||||
|
||||
@@ -57,31 +90,31 @@ class Errors(commands.Cog):
|
||||
|
||||
elif isinstance(error, commands.BotMissingPermissions):
|
||||
permissions = ', '.join(error.missing_perms)
|
||||
embed = embed_templates.error_warning(ctx, text='Jeg mangler følgende tillatelser:\n\n' +
|
||||
f'```\n{permissions}\n```')
|
||||
return await ctx.send(embed=embed)
|
||||
text = 'Jeg mangler følgende tillatelser:\n\n' + \
|
||||
f'```\n{permissions}\n```'
|
||||
return await ctx.send(text)
|
||||
|
||||
elif isinstance(error, commands.MissingPermissions):
|
||||
permissions = ', '.join(error.missing_perms)
|
||||
embed = embed_templates.error_warning(ctx, text='Du mangler følgende tillatelser\n\n' +
|
||||
f'```\n{permissions}\n```')
|
||||
return await ctx.send(embed=embed)
|
||||
text = 'Du mangler følgende tillatelser\n\n' + \
|
||||
f'```\n{permissions}\n```'
|
||||
return await ctx.send(text)
|
||||
|
||||
elif isinstance(error, commands.NotOwner):
|
||||
embed = embed_templates.error_fatal(ctx, text='Bare boteieren kan gjøre dette')
|
||||
return await ctx.send(embed=embed)
|
||||
text = 'Bare boteieren kan gjøre dette'
|
||||
return await ctx.send(text)
|
||||
|
||||
elif isinstance(error, commands.CommandOnCooldown):
|
||||
embed = embed_templates.error_warning(ctx, text='Kommandoen har nettopp blitt brukt' +
|
||||
f'Prøv igjen om `{error.retry_after:.1f}` sekunder.')
|
||||
return await ctx.send(embed=embed)
|
||||
text = 'Kommandoen har nettopp blitt brukt' + \
|
||||
f'Prøv igjen om `{error.retry_after:.1f}` sekunder.'
|
||||
return await ctx.send(text)
|
||||
|
||||
elif isinstance(error, commands.NoPrivateMessage):
|
||||
try:
|
||||
embed = embed_templates.error_fatal(ctx, text='Denne kommandoen kan bare utføres i servere')
|
||||
return await ctx.send(embed=embed)
|
||||
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
|
||||
@@ -92,15 +125,57 @@ class Errors(commands.Cog):
|
||||
embed = embed_templates.error_fatal(ctx, text='En ukjent feil oppstod!')
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
# Print full exception to console
|
||||
print(f'Ignoring exception in command {ctx.command}:', file=sys.stderr)
|
||||
traceback.print_exception(
|
||||
type(error),
|
||||
error,
|
||||
error.__traceback__,
|
||||
file=sys.stderr
|
||||
)
|
||||
# Log full exception to file
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
if isinstance(error, commands.BotMissingPermissions):
|
||||
permissions = ', '.join(error.missing_perms)
|
||||
embed = embed_templates.error_warning(interaction, text='Jeg mangler følgende tillatelser:\n\n' +
|
||||
f'```\n{permissions}\n```')
|
||||
return await interaction.response.send_message(embed=embed)
|
||||
|
||||
elif isinstance(error, commands.MissingPermissions):
|
||||
permissions = ', '.join(error.missing_perms)
|
||||
embed = embed_templates.error_warning(interaction, text='Du mangler følgende tillatelser\n\n' +
|
||||
f'```\n{permissions}\n```')
|
||||
return await interaction.response.send_message(embed=embed)
|
||||
|
||||
elif isinstance(error, commands.NotOwner):
|
||||
embed = embed_templates.error_fatal(interaction, text='Bare boteieren kan gjøre dette')
|
||||
return await interaction.response.send_message(embed=embed)
|
||||
|
||||
elif isinstance(error, commands.CommandOnCooldown):
|
||||
embed = embed_templates.error_warning(interaction, text='Kommandoen har nettopp blitt brukt' +
|
||||
f'Prøv igjen om `{error.retry_after:.1f}` sekunder.')
|
||||
return await interaction.response.send_message(embed=embed)
|
||||
|
||||
embed = embed_templates.error_fatal(interaction, text='En ukjent feil oppstod!')
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
# Log full exception to file
|
||||
self.bot.logger.error(''.join(traceback.format_exception(type(error), error, error.__traceback__)))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Errors(bot))
|
||||
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))
|
||||
+77
-14
@@ -2,44 +2,107 @@ from discord.ext import commands
|
||||
|
||||
|
||||
class Fun(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
"""Simple commands that return short strings for the memes"""
|
||||
|
||||
@commands.cooldown(1, 2, commands.BucketType.guild)
|
||||
@commands.command()
|
||||
async def norskeuniversiteter(self, ctx):
|
||||
@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()
|
||||
async def informatikkuio(self, ctx):
|
||||
@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()
|
||||
async def informatikkuio2(self, ctx):
|
||||
@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 informatikkuio3(self, ctx):
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
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')
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Fun(bot))
|
||||
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))
|
||||
+76
-18
@@ -1,31 +1,89 @@
|
||||
from discord.ext import commands
|
||||
|
||||
import random
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
|
||||
class FunReplies(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
"""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
|
||||
|
||||
async def react(self, message):
|
||||
# Cooldowns for trigger words
|
||||
#
|
||||
# This is kind of a shitty way to do it but I'm too lazy to implement anything good right now
|
||||
self.cooldown_seconds = 120
|
||||
initial_datetime = datetime(2000, 9, 11) # Set initial datetime far in the past to allow triggering right after boot
|
||||
self.previous_invokations = {
|
||||
'borgerlønn': initial_datetime,
|
||||
'olof palme': initial_datetime,
|
||||
'lesgo': initial_datetime,
|
||||
'neuf': initial_datetime,
|
||||
'yeet': initial_datetime
|
||||
}
|
||||
|
||||
async def reply_to_triggers(self, message: discord.Message):
|
||||
"""
|
||||
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
|
||||
|
||||
if re.findall(r'(^|\W)borgerlønn(\W|$)', message.clean_content.lower()) != []:
|
||||
await message.channel.send('<@267415183931080715> DE SNAKKER OM BORGERLØNN')
|
||||
message_content = message.content.lower()
|
||||
|
||||
elif re.findall(r'(^|\W)olof palme(\W|$)', message.clean_content.lower()) != []:
|
||||
await message.channel.send('Jeg vet hvem som drepte Olof Palme 👀')
|
||||
if re.search(r'(^|\W)borgerlønn(\W|$)', message_content, flags=re.IGNORECASE):
|
||||
if (datetime.now() - self.previous_invokations['borgerlønn']).seconds > self.cooldown_seconds:
|
||||
await message.channel.send('<@267415183931080715> DE SNAKKER OM BORGERLØNN')
|
||||
self.previous_invokations['borgerlønn'] = datetime.now()
|
||||
|
||||
# The Ultimate spaghetti
|
||||
elif (
|
||||
re.match(r'(\W|\s)*lesgo{1}(\s|\W)*', message.clean_content.lower()) or
|
||||
message.clean_content.lower() == 'lesgo'
|
||||
):
|
||||
await message.channel.send('https://cdn.discordapp.com/attachments/750052141346979850/' +
|
||||
'824764933513281596/3xhpwbakz2361.png')
|
||||
elif re.search(r'(^|\W)olof palme(\W|$)', message_content, flags=re.IGNORECASE):
|
||||
if (datetime.now() - self.previous_invokations['olof palme']).seconds > self.cooldown_seconds:
|
||||
await message.channel.send('Jeg vet hvem som drepte Olof Palme 👀')
|
||||
self.previous_invokations['olof palme'] = datetime.now()
|
||||
|
||||
elif re.search(r'(\W|\s)*le+s+go+(\s|\W)*', message_content):
|
||||
if (datetime.now() - self.previous_invokations['lesgo']).seconds > self.cooldown_seconds:
|
||||
await message.channel.send('https://cdn.discordapp.com/attachments/750052141346979850/' +
|
||||
'824764933513281596/3xhpwbakz2361.png')
|
||||
self.previous_invokations['lesgo'] = datetime.now()
|
||||
|
||||
elif re.search(r'^((er det|hvor)\s+)*(noen|folk|mange)\s+på\s+(rommet|neuf|kontoret)\?*$', message_content, flags=re.IGNORECASE):
|
||||
if (datetime.now() - self.previous_invokations['neuf']).seconds > self.cooldown_seconds:
|
||||
# Choose a random user to ping
|
||||
pingable = ["<@554977854971183125>", "<@276061121776058370>"]
|
||||
to_be_pinged = random.choice(pingable)
|
||||
await message.channel.send(f'Ja, {to_be_pinged} bor der')
|
||||
|
||||
self.previous_invokations['neuf'] = datetime.now()
|
||||
|
||||
elif re.search(r'(^|\W)+ye+et($|\W)+', message_content, flags=re.IGNORECASE):
|
||||
if (datetime.now() - self.previous_invokations['yeet']).seconds > self.cooldown_seconds:
|
||||
await message.channel.send('<:Nei:826593267642662912>')
|
||||
self.previous_invokations['yeet'] = datetime.now()
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_listener(FunReplies(bot).react, 'on_message')
|
||||
bot.add_cog(FunReplies(bot))
|
||||
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))
|
||||
+552
-567
File diff suppressed because it is too large.
Load diff
+58
-22
@@ -1,19 +1,29 @@
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
|
||||
import requests
|
||||
import json
|
||||
from mcrcon import MCRcon
|
||||
import requests
|
||||
|
||||
from cogs.utils import embed_templates
|
||||
|
||||
|
||||
class MCWhitelist(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
"""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 (
|
||||
@@ -24,49 +34,75 @@ class MCWhitelist(commands.Cog):
|
||||
)
|
||||
self.bot.db_connection.commit()
|
||||
|
||||
@commands.cooldown(1, 10, commands.BucketType.user)
|
||||
@commands.command()
|
||||
async def whitelist(self, ctx, minecraftbrukernavn):
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 5)
|
||||
@app_commands.command(name='whitelist', description='Whitelist minecraftbrukeren din på serveren vår')
|
||||
async def whitelist(self, interaction: discord.Interaction, minecraftbrukernavn: str):
|
||||
"""
|
||||
Whitelist a minecraft user on the Minecraft server
|
||||
|
||||
# fetch minecraft uuid from api
|
||||
data = requests.get(f"https://api.mojang.com/users/profiles/minecraft/{minecraftbrukernavn}")
|
||||
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()
|
||||
if data.status_code != 200:
|
||||
return await ctx.send(
|
||||
embed=embed_templates.error_fatal(ctx, text=f"Brukeren `{minecraftbrukernavn}` finnes ikk på minecraft")
|
||||
return await interaction.response.send_message(
|
||||
embed=embed_templates.error_fatal(interaction, text=f'Brukeren `{minecraftbrukernavn}` finnes ikke på minecraft'),
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
data = data.json()
|
||||
|
||||
# check if the discord user or minecraft user is in the db
|
||||
self.cursor.execute(
|
||||
"SELECT * FROM mc_whitelist WHERE minecraft_id = %s OR discord_id = %s", (data["id"], ctx.author.id)
|
||||
"""
|
||||
SELECT *
|
||||
FROM mc_whitelist
|
||||
WHERE minecraft_id = %s OR discord_id = %s
|
||||
""", (data['id'], interaction.user.id)
|
||||
)
|
||||
if self.cursor.fetchone():
|
||||
return await ctx.send(
|
||||
return await interaction.response.send_message(
|
||||
embed=embed_templates.error_fatal(
|
||||
ctx, text="Du har allerede whitelisted en bruker eller så er brukeren du oppga whitelisted"
|
||||
interaction,
|
||||
text='Du har allerede whitelisted en bruker eller så er brukeren du oppga whitelisted'
|
||||
)
|
||||
)
|
||||
|
||||
with MCRcon(host="192.168.0.24", password="hallaballayeet", port=25575) as mcr:
|
||||
mcr.command(f"whitelist add {data['name']}")
|
||||
mcr.command("whitelist reload")
|
||||
# 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')
|
||||
|
||||
# Add user to db
|
||||
self.cursor.execute(
|
||||
"""
|
||||
INSERT INTO mc_whitelist (discord_id, minecraft_id)
|
||||
VALUES (%s, %s)
|
||||
""",
|
||||
(ctx.author.id, data["id"]),
|
||||
(interaction.user.id, data['id']),
|
||||
)
|
||||
self.bot.db_connection.commit()
|
||||
|
||||
await ctx.send(
|
||||
await interaction.response.send_message(
|
||||
embed=embed_templates.success(
|
||||
ctx, text=f"`{data['name']}` er nå tilknyttet din discordbruker og whitelisted!"
|
||||
interaction, text=f'`{data["name"]}` er nå tilknyttet din discordbruker og whitelisted!'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(MCWhitelist(bot))
|
||||
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))
|
||||
+224
-191
@@ -1,271 +1,304 @@
|
||||
from discord.ext import commands
|
||||
import discord
|
||||
|
||||
from re import sub
|
||||
from datetime import datetime
|
||||
import requests
|
||||
import json
|
||||
from asyncio import sleep
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import re
|
||||
from os import remove
|
||||
import urllib
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import requests
|
||||
|
||||
from cogs.utils import embed_templates
|
||||
from cogs.utils.misc_utils import ignore_exception
|
||||
|
||||
|
||||
class Misc(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
"""Miscellaneous commands that don't fit anywhere else"""
|
||||
|
||||
def __init__(self, bot: commands.Bot):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
bot (commands.Bot): The bot instance
|
||||
"""
|
||||
|
||||
self.bot = bot
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.cooldown(1, 2, commands.BucketType.guild)
|
||||
@commands.command()
|
||||
async def weeb(self, ctx):
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 2)
|
||||
@app_commands.command(name='weeb', description='Kjeft på weebs')
|
||||
async def weeb(self, interaction: discord.Interaction):
|
||||
"""
|
||||
Kjeft på weebs
|
||||
Call out weebs
|
||||
|
||||
Parameters
|
||||
----------
|
||||
interaction (discord.Interaction): Slash command context object
|
||||
"""
|
||||
|
||||
await ctx.send("<:sven:762725919604473866> Weebs 👉 <#803596668129509417>")
|
||||
await interaction.response.send_message('<:sven:762725919604473866> Weebs 👉 <#803596668129509417>')
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.cooldown(1, 2, commands.BucketType.guild)
|
||||
@commands.command(aliases=["owoify", "uwu"])
|
||||
async def owo(self, ctx, *, tekst: str):
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 2)
|
||||
@app_commands.command(name='kweeb', description='김정운, 최고도')
|
||||
async def kweeb(self, interaction: discord.Interaction):
|
||||
"""
|
||||
Oversetter teksten din til owo
|
||||
Call out kweebs
|
||||
|
||||
Parameters
|
||||
----------
|
||||
interaction (discord.Interaction): Slash command context object
|
||||
"""
|
||||
|
||||
owo_rules = {"r": "w", "l": "w", "R": "W", "L": "W", "n": "ny", "N": "Ny", "ove": "uv"}
|
||||
await interaction.response.send_message(
|
||||
"""
|
||||
Melding du nettopp sendte ga muligens følgende vibber for brukeren som brukte denne kommandoen:
|
||||
|
||||
> KOREA NUMBER ONE!
|
||||
> OMG I LUUUUV JUNGKOK!!! 🥰😍🥰 STAN JUNGKOOK! 🤞🤞🤞 사랑해!!! ♥♥♥
|
||||
> JEG EEEEELSKER 김치
|
||||
> OP OP OP OPPAN GANGNAM STYLE!
|
||||
|
||||
Så da kan man spørre seg selv? Hva faen skjedde med god gammeldags weebdom?
|
||||
Til vår skuffelse finnes den fortsatt, men ble det for mainstream å være weeb.
|
||||
Så da beveger massen seg til det neste hyperkapitalistiske øst-asiatiske staten med økonomisk boom.
|
||||
Så hvor ble da av weebsa? Denne videoen svarer ganske godt på det
|
||||
https://cdn.discordapp.com/attachments/448502155184439297/1027355652059832351/THEY_WENT_TO_KOREA.mp4
|
||||
|
||||
Du har nå blitt kalt en kweeb. Det er over for deg.
|
||||
Våkne!
|
||||
https://cdn.discordapp.com/attachments/674726496878723082/1042631569396990004/kweeb_er_den_nye_weeb.png
|
||||
"""
|
||||
)
|
||||
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 2)
|
||||
@app_commands.command(name='owo', description='Oversetter teksten din til owo (we_eb)')
|
||||
async def owo(self, interaction: discord.Interaction, tekst: str):
|
||||
"""
|
||||
Translate text into owo (we_eb)
|
||||
|
||||
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 = sub(key, value, tekst)
|
||||
tekst = re.sub(key, value, tekst)
|
||||
# https://kaomoji.moe/
|
||||
|
||||
if not tekst or len(tekst) >= 1000:
|
||||
embed = embed_templates.error_warning(ctx, text="Teksten er for lang")
|
||||
return await ctx.send(embed=embed)
|
||||
if len(tekst) >= 1000:
|
||||
embed = embed_templates.error_warning(interaction, text='Teksten er for lang')
|
||||
return await interaction.response.send_message(embed=embed)
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color, description=tekst)
|
||||
embed = embed_templates.default_footer(ctx, embed)
|
||||
await ctx.send(embed=embed)
|
||||
embed = discord.Embed(color=interaction.client.user.color, description=tekst)
|
||||
embed_templates.default_footer(interaction, embed)
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
@commands.command()
|
||||
async def emne(self, ctx, emnekode: str):
|
||||
@app_commands.checks.cooldown(1, 5)
|
||||
@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
|
||||
|
||||
data = requests.get(f"https://data.uio.no/studies/v1/course/{emnekode}")
|
||||
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 ctx.send(embed=embed_templates.error_fatal(ctx, text="Fant ikke emnekode"))
|
||||
return await interaction.response.send_message(embed=embed_templates.error_fatal(interaction, text='Fant ikke emnekode'))
|
||||
|
||||
emne = data.json()["info"]["name"]
|
||||
await ctx.send(emne)
|
||||
await interaction.response.send_message(data.json()['info']['name'])
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.cooldown(1, 2, commands.BucketType.guild)
|
||||
@commands.command(aliases=["clapify"])
|
||||
async def klappifiser(self, ctx, *, tekst):
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 2)
|
||||
@app_commands.command(name='klappifiser', description='Klappifiser tekst')
|
||||
async def clapify(self, interation: discord.Interaction, tekst: str):
|
||||
"""
|
||||
Klapppifiserer teksten din
|
||||
Add clap emoji between every word of a string
|
||||
|
||||
Parameters
|
||||
----------
|
||||
interaction (discord.Interaction): Slash command context object
|
||||
tekst (str): Text to clapify
|
||||
"""
|
||||
|
||||
if not tekst or len(tekst) >= 1000:
|
||||
embed = embed_templates.error_warning(ctx, text="Teksten er for lang")
|
||||
return await ctx.send(embed=embed)
|
||||
if len(tekst) >= 1000:
|
||||
embed = embed_templates.error_warning(interation, text='Teksten er for lang')
|
||||
return await interation.response.send_message(embed=embed)
|
||||
|
||||
tekst = sub(" ", "👏", tekst)
|
||||
tekst = re.sub(' ', '👏', tekst)
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color, description=f"**{tekst.upper()}**")
|
||||
embed = embed_templates.default_footer(ctx, embed)
|
||||
await ctx.send(embed=embed)
|
||||
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)
|
||||
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
@commands.command(aliases=["filmsøk"])
|
||||
async def imdb(self, ctx, *, film):
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 5)
|
||||
@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
|
||||
"""
|
||||
|
||||
url = "http://www.omdbapi.com/?" + urllib.parse.urlencode({"s": film, "apikey": self.bot.api_keys["omdb"]})
|
||||
search = requests.get(url).json()
|
||||
# Search for movie/show
|
||||
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(ctx, text="Fant ikke filmen!")
|
||||
return await ctx.send(embed=embed)
|
||||
embed = embed_templates.error_fatal(interaction, text='Fant ikke filmen!')
|
||||
return await interaction.response.send_message(embed=embed)
|
||||
|
||||
data = requests.get(f'http://www.omdbapi.com/?i={best_result_id}&apikey={self.bot.api_keys["omdb"]}').json()
|
||||
|
||||
acceptable_media_types = ["movie", "series", "episode"]
|
||||
if data["Type"] not in acceptable_media_types:
|
||||
embed = embed_templates.error_fatal(ctx, text="Fant ikke filmen!")
|
||||
return await ctx.send(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!')
|
||||
return await interaction.response.send_message(embed=embed)
|
||||
|
||||
embed = discord.Embed(
|
||||
title=f'{data["Title"]} ({data["Year"]})',
|
||||
color=0xF5C518,
|
||||
url=f'https://www.imdb.com/title/{data["imdbID"]}/',
|
||||
)
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url)
|
||||
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')
|
||||
embed.set_footer(text=f'Utgitt: {data["Released"]}')
|
||||
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_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 ctx.send(embed=embed)
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.cooldown(1, 5, commands.BucketType.guild)
|
||||
@commands.command(aliases=["identify"])
|
||||
async def identifiser(self, ctx, bilde=None):
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 5)
|
||||
@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):
|
||||
"""
|
||||
Beskriver hva som er på bildet
|
||||
Get holidays for a country for a given year
|
||||
|
||||
Parameters
|
||||
----------
|
||||
interaction (discord.Interaction): Slash command context object
|
||||
land (str): Country code
|
||||
år (int): Year
|
||||
"""
|
||||
|
||||
if ctx.message.attachments != []:
|
||||
bilde = ctx.message.attachments[0].url
|
||||
land = land.upper()
|
||||
aar = datetime.now().year if not år else int(år)
|
||||
|
||||
if bilde is None:
|
||||
embed = embed_templates.error_fatal(ctx, text="Du må gi meg et bilde!")
|
||||
|
||||
async with ctx.channel.typing():
|
||||
|
||||
payload = {"inputs": [{"data": {"image": {"url": bilde}}}]}
|
||||
header = {"Authorization": f'Key {self.bot.api_keys["clarifai"]}'}
|
||||
url = (
|
||||
"https://api.clarifai.com/v2/models/aaa03c23b3724a16a56b629203edc62c"
|
||||
+ "/versions/aa7f35c01e0642fda5cf400f543e7c40/outputs"
|
||||
)
|
||||
data = requests.post(url, data=json.dumps(payload), headers=header)
|
||||
if data.status_code != 200:
|
||||
embed = embed_templates.default_footer("API request feilet")
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
data = data.json()
|
||||
|
||||
words = []
|
||||
for i, concepts in enumerate(data["outputs"][0]["data"]["concepts"]):
|
||||
words.append(concepts["name"])
|
||||
if i >= 5:
|
||||
break
|
||||
|
||||
words = ", ".join(words)
|
||||
|
||||
await sleep(2)
|
||||
|
||||
embed = discord.Embed(color=ctx.me.color)
|
||||
embed.set_author(name="Clarifai AI", icon_url="https://github.com/Clarifai.png")
|
||||
embed.description = f"**Ord som beskriver dette bildet:**\n\n{words}"
|
||||
embed.set_image(url=bilde)
|
||||
embed = embed_templates.default_footer(ctx, embed)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.cooldown(1, 5, commands.BucketType.guild)
|
||||
@commands.command(aliases=["holidays", "fridager", "ferie"])
|
||||
async def helligdager(self, ctx, land=None, aar=None):
|
||||
"""
|
||||
Se hellidagene i et land
|
||||
"""
|
||||
|
||||
if not land:
|
||||
land = "NO"
|
||||
else:
|
||||
land = land.upper()
|
||||
|
||||
if not aar:
|
||||
aar = datetime.now().year
|
||||
else:
|
||||
int(aar)
|
||||
|
||||
data = requests.get(f"https://date.nager.at/api/v2/publicholidays/{aar}/{land}")
|
||||
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(
|
||||
ctx, text="Ugyldig land\nHusk å bruke landskoder\n" + "For eksempel: `NO`"
|
||||
interaction, text='Ugyldig land\nHusk å bruke landskoder\n' + 'For eksempel: `NO`'
|
||||
)
|
||||
return await ctx.send(embed=embed)
|
||||
return await interaction.response.send_message(embed=embed)
|
||||
|
||||
data = data.json()
|
||||
|
||||
country = data[0]["countryCode"].lower()
|
||||
holiday_str = ""
|
||||
country = data[0]['countryCode'].lower()
|
||||
|
||||
# Construct output
|
||||
holiday_str = ''
|
||||
for day in data:
|
||||
date = day["date"]
|
||||
date = datetime.strptime(date, "%Y-%m-%d").strftime("%d. %B")
|
||||
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=ctx.me.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 = embed_templates.default_footer(ctx, embed)
|
||||
await ctx.send(embed=embed)
|
||||
embed_templates.default_footer(interaction, embed)
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
@commands.bot_has_permissions(embed_links=True)
|
||||
@commands.cooldown(1, 5, commands.BucketType.guild)
|
||||
@commands.command()
|
||||
async def match(self, ctx, *, bruker: discord.Member = None):
|
||||
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||
@app_commands.checks.cooldown(1, 5)
|
||||
@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 not bruker:
|
||||
embed = embed_templates.error_warning(ctx, text="Du må gi meg en bruker")
|
||||
return await ctx.send(embed=embed)
|
||||
if bruker == ctx.author:
|
||||
if bruker == interaction.user:
|
||||
embed = embed_templates.error_warning(
|
||||
ctx, 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 ctx.send(embed=embed)
|
||||
return await interaction.response.send_message(embed=embed)
|
||||
|
||||
async with ctx.channel.typing():
|
||||
invoker_id = int(str(interaction.user.id)[11:14])
|
||||
user_id = int(str(bruker.id)[11:14])
|
||||
|
||||
invoker_id = int(str(ctx.author.id)[11:14])
|
||||
user_id = int(str(bruker.id)[11:14])
|
||||
match_percent = int((invoker_id + user_id) % 100)
|
||||
|
||||
match_percent = int((invoker_id + user_id) % 100)
|
||||
if bruker.id == self.bot.user.id:
|
||||
match_percent = 100
|
||||
|
||||
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 ctx.author.avatar_url_as(format="png").save(fp=f"./src/assets/temp/{ctx.author.id}_raw.png")
|
||||
await bruker.avatar_url_as(format="png").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 = invoker.resize((389, 389), Image.ANTIALIAS)
|
||||
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')
|
||||
|
||||
invoker = Image.open(f"./src/assets/temp/{ctx.author.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 = user.resize((389, 389), Image.ANTIALIAS)
|
||||
heart = Image.open("./src/assets/misc/heart.png")
|
||||
mask = Image.open("./src/assets/misc/heart.png", "r")
|
||||
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_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))
|
||||
|
||||
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_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))
|
||||
image.save(f'./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png')
|
||||
|
||||
image.save(f"./src/assets/temp/{ctx.author.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_templates.default_footer(interaction, embed)
|
||||
await interaction.response.send_message(embed=embed, file=f)
|
||||
|
||||
f = discord.File(f"./src/assets/temp/{ctx.author.id}_{bruker.id}_edit.png")
|
||||
embed = discord.Embed()
|
||||
embed.set_image(url=f"attachment://{ctx.author.id}_{bruker.id}_edit.png")
|
||||
embed = embed_templates.default_footer(ctx, embed)
|
||||
await ctx.send(embed=embed, file=f)
|
||||
|
||||
with ignore_exception(OSError):
|
||||
remove(f"./src/assets/temp/{bruker.id}_raw.png")
|
||||
remove(f"./src/assets/temp/{ctx.author.id}_raw.png")
|
||||
remove(f"./src/assets/temp/{ctx.author.id}_{bruker.id}_edit.png")
|
||||
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')
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Misc(bot))
|
||||
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))
|
||||
@@ -1,67 +0,0 @@
|
||||
from discord.ext import commands
|
||||
import discord
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from cogs.utils import embed_templates
|
||||
|
||||
|
||||
class Mod(commands.Cog):
|
||||
def __init__(self, bot) -> None:
|
||||
self.bot = bot
|
||||
|
||||
@commands.bot_has_permissions(ban_members=True)
|
||||
@commands.has_permissions(ban_members=True)
|
||||
@commands.guild_only()
|
||||
@commands.command()
|
||||
async def hackban(self, ctx, brukerid, *, begrunnelse=None):
|
||||
"""
|
||||
Bannlys en bruker før de i det hele tatt har blitt med i serveren
|
||||
"""
|
||||
|
||||
try:
|
||||
brukerid = int(brukerid)
|
||||
except ValueError:
|
||||
embed = embed_templates.error_warning(ctx, text='Du må gi meg en bruker-id')
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
user = discord.Object(id=brukerid)
|
||||
|
||||
for banentry in await ctx.guild.bans():
|
||||
if banentry.user.id == user.id:
|
||||
embed = embed_templates.error_warning(ctx, text='Denne brukeren er allerede bannlyst fra serveren!')
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
if begrunnelse is None:
|
||||
begrunnelse = 'Ingen grunn angitt'
|
||||
|
||||
date = datetime.now().strftime('%d. %b. %Y - %H:%M')
|
||||
|
||||
try:
|
||||
await ctx.guild.ban(
|
||||
user,
|
||||
reason=f'{date} | {ctx.author.name}#{ctx.author.discriminator} ({ctx.author.id}): {begrunnelse}'
|
||||
)
|
||||
except discord.errors.NotFound:
|
||||
embed = embed_templates.error_warning(ctx, text='Bruker finnes ikke!')
|
||||
return await ctx.send(embed=embed)
|
||||
|
||||
user_object = self.bot.get_user(brukerid)
|
||||
|
||||
embed = discord.Embed(color=discord.Color.red(), title='🔨 Bruker utestengt!')
|
||||
if begrunnelse != 'Ingen grunn angitt':
|
||||
embed.description = f'`{begrunnelse}`'
|
||||
if user_object:
|
||||
user = user_object
|
||||
embed.set_thumbnail(url=user.avatar_url)
|
||||
embed.set_author(name=f'{user.name}#{user.discriminator}', icon_url=user.avatar_url)
|
||||
embed.add_field(name='Bruker', value=f'{user.name}#{user.discriminator}\n{user.mention}', inline=False)
|
||||
else:
|
||||
embed.add_field(name='Bruker', value=f'`{user.id}`', inline=False)
|
||||
embed.add_field(name='Av', value=f'{ctx.author.name}#{ctx.author.discriminator}\n{ctx.author.mention}')
|
||||
embed = embed_templates.default_footer(ctx, embed)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Mod(bot))
|
||||
@@ -1,38 +1,51 @@
|
||||
from discord.ext import commands
|
||||
|
||||
import aiocron
|
||||
from discord.ext import commands
|
||||
|
||||
|
||||
class RepeatedMessages(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
"""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():
|
||||
guild = self.bot.get_guild(747542543750660178)
|
||||
channel = guild.get_channel(747542544291987597)
|
||||
"""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():
|
||||
guild = self.bot.get_guild(747542543750660178)
|
||||
channel = guild.get_channel(747542544291987597)
|
||||
"""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():
|
||||
guild = self.bot.get_guild(747542543750660178)
|
||||
channel = guild.get_channel(747542544291987597)
|
||||
"""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>\nhttps://youtu.be/5qXkEvHrZ-0"
|
||||
'GODT NYTTÅR!\n\nNå, meld dere inn i UiO Gaming igjen <:ThisIsAThreat:874998234072903710>'
|
||||
)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(RepeatedMessages(bot))
|
||||
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))
|
||||
@@ -1,18 +1,73 @@
|
||||
import discord
|
||||
|
||||
from .misc_utils import Paginator
|
||||
|
||||
def get_user_color(user: discord.User) -> discord.Color:
|
||||
|
||||
def get_color(discord_object: discord.User | discord.Member | discord.Role) -> discord.Color:
|
||||
"""
|
||||
Returns the user's top role color
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
user (discord.User): A discord user or member object
|
||||
discord_object (discord.User|discord.Member|discord.Role): A discord object that has a color attribute
|
||||
|
||||
Returns
|
||||
-----------
|
||||
(discord.Color): The user's displayed color
|
||||
"""
|
||||
|
||||
if str(user.color) != '#000000':
|
||||
return user.color
|
||||
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
|
||||
|
||||
self.add_item(ScrollerButton(self.paginator, self.paginator.first_page, content_constructor, label='<<', disabled=self.paginator.current_page == 1))
|
||||
self.add_item(ScrollerButton(self.paginator, self.paginator.previous_page, content_constructor, label='<', disabled=self.paginator.current_page == 1))
|
||||
self.add_item(ScrollerButton(self.paginator, self.paginator.next_page, content_constructor, label='>', disabled=self.paginator.current_page == self.paginator.total_page_count))
|
||||
self.add_item(ScrollerButton(self.paginator, self.paginator.last_page, content_constructor, label='>>', disabled=self.paginator.current_page == self.paginator.total_page_count))
|
||||
@@ -1,70 +1,81 @@
|
||||
import discord
|
||||
|
||||
|
||||
def default_footer(ctx: discord.ext.commands.Context, embed: discord.Embed) -> discord.Embed:
|
||||
def default_footer(interaction: discord.Interaction, embed: discord.Embed) -> discord.Embed:
|
||||
"""
|
||||
Sets a footer containing the command invoker's name, discriminator and avatar
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
ctx (discord.ext.commands.Context): The current Discord context
|
||||
interaction (discord.Interaction): Slash command context object
|
||||
embed (discord.Embed): An embed object to add the footer to
|
||||
|
||||
Returns
|
||||
-----------
|
||||
(discord.Embed): The sent in embed + footer
|
||||
(discord.Embed): The passed in embed + footer
|
||||
"""
|
||||
|
||||
return embed.set_footer(icon_url=ctx.author.avatar_url, text=f"{ctx.author.name}#{ctx.author.discriminator}")
|
||||
return embed.set_footer(
|
||||
icon_url=interaction.user.avatar,
|
||||
text=f'{interaction.user.name}#{interaction.user.discriminator}'
|
||||
)
|
||||
|
||||
|
||||
def error_warning(ctx: discord.ext.commands.Context, text: str) -> discord.Embed:
|
||||
def error_warning(interaction: discord.Interaction, text: str) -> discord.Embed:
|
||||
"""
|
||||
Creates an embed with a specified error message based on a warning template
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
ctx (discord.ext.commands.Context): The current Discord 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}")
|
||||
default_footer(ctx, embed)
|
||||
embed = discord.Embed(color=discord.Color.gold(), description=f'⚠️ {text}')
|
||||
default_footer(interaction, embed)
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def error_fatal(ctx: discord.ext.commands.Context, text: str) -> discord.Embed:
|
||||
def error_fatal(interaction: discord.Interaction, text: str) -> discord.Embed:
|
||||
"""
|
||||
Creates an embed with a specified error message based on a warning template
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
ctx (discord.ext.commands.Context): The current Discord 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}")
|
||||
default_footer(ctx, embed)
|
||||
embed = discord.Embed(color=discord.Color.red(), description=f'❌ {text}')
|
||||
default_footer(interaction, embed)
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def success(ctx: discord.ext.commands.Context, text: str) -> discord.Embed:
|
||||
def success(interaction: discord.Interaction, text: str) -> discord.Embed:
|
||||
"""
|
||||
Creates an embed with a specified message using a template signifying success.
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
ctx (discord.ext.commands.Context): The current Discord 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}")
|
||||
default_footer(ctx, embed)
|
||||
embed = discord.Embed(color=discord.Color.green(), description=f'✅ {text}')
|
||||
default_footer(interaction, embed)
|
||||
|
||||
return embed
|
||||
@@ -1,56 +1,99 @@
|
||||
from typing import Union, Dict
|
||||
from math import ceil
|
||||
from contextlib import contextmanager
|
||||
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):
|
||||
except exceptions:
|
||||
pass
|
||||
|
||||
|
||||
def paginator(content: list, page: int) -> Dict[str, Union[int, str]]:
|
||||
"""
|
||||
Divides content into 10 element pages
|
||||
class Paginator:
|
||||
def __init__(self, content: list):
|
||||
self.content = content
|
||||
self.total_page_count = ceil(len(content) / 10)
|
||||
self.current_page = 1
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
content: A list of strings
|
||||
page: The page
|
||||
def get_page(self, page: int) -> list | None:
|
||||
"""
|
||||
Returns the page of the paginator
|
||||
|
||||
Returns
|
||||
-----------
|
||||
(dict): A dictionay containing content and metadata
|
||||
keys: pagecount, page, page_content
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
page (int): The page you want to get
|
||||
|
||||
pagecount = ceil(len(content) / 10)
|
||||
Returns
|
||||
----------
|
||||
(list|None): The page you requested
|
||||
"""
|
||||
if page < 1 or page > self.total_page_count:
|
||||
return None
|
||||
|
||||
if not page or page <= 0 or page > pagecount:
|
||||
page = 1
|
||||
start_index = (page - 1) * 10
|
||||
end_index = page * 10
|
||||
|
||||
start_index = (page - 1) * 10
|
||||
end_index = page * 10
|
||||
return self.content[start_index:end_index]
|
||||
|
||||
page_content = content[start_index:end_index]
|
||||
def get_current_page(self) -> list:
|
||||
"""
|
||||
Returns the current page of the paginator
|
||||
|
||||
page_data = {
|
||||
'pagecount': pagecount,
|
||||
'page': page,
|
||||
'page_content': page_content
|
||||
}
|
||||
return page_data
|
||||
Returns
|
||||
----------
|
||||
(list): The current page of the paginator
|
||||
"""
|
||||
return self.get_page(self.current_page)
|
||||
|
||||
def next_page(self) -> list | None:
|
||||
"""
|
||||
Returns the next page of the paginator
|
||||
|
||||
Returns
|
||||
----------
|
||||
(list): The next page of the paginator
|
||||
"""
|
||||
self.current_page += 1
|
||||
return self.get_page(self.current_page)
|
||||
|
||||
def previous_page(self) -> list | None:
|
||||
"""
|
||||
Returns the previous page of the paginator
|
||||
|
||||
Returns
|
||||
----------
|
||||
(list): The previous page of the paginator
|
||||
"""
|
||||
self.current_page -= 1
|
||||
return self.get_page(self.current_page)
|
||||
|
||||
def first_page(self) -> list | None:
|
||||
"""
|
||||
Returns the first page of the paginator
|
||||
|
||||
Returns
|
||||
----------
|
||||
(list): The first page of the paginator
|
||||
"""
|
||||
self.current_page = 1
|
||||
return self.get_page(self.current_page)
|
||||
|
||||
def last_page(self) -> list | None:
|
||||
"""
|
||||
Returns the last page of the paginator
|
||||
|
||||
Returns
|
||||
----------
|
||||
(list): The last page of the paginator
|
||||
"""
|
||||
self.current_page = self.total_page_count
|
||||
return self.get_page(self.current_page)
|
||||
@@ -1,3 +1,5 @@
|
||||
config_mode: dev
|
||||
|
||||
# Bot settings
|
||||
bot:
|
||||
token:
|
||||
@@ -7,6 +9,17 @@ bot:
|
||||
activity: listening
|
||||
type: dnd
|
||||
|
||||
# Database
|
||||
database:
|
||||
host:
|
||||
dbname:
|
||||
username:
|
||||
password:
|
||||
|
||||
# Minecraft server
|
||||
minecraft:
|
||||
rcon_password:
|
||||
|
||||
# Api keys
|
||||
api:
|
||||
clarifai:
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import logging
|
||||
import logging.handlers
|
||||
|
||||
|
||||
class BotLogger:
|
||||
"""Logging config for the bot"""
|
||||
|
||||
def __init__(self):
|
||||
logger = logging.getLogger('discord')
|
||||
logger.setLevel(logging.INFO)
|
||||
handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w')
|
||||
formatter = logging.Formatter('[{asctime}] [{levelname:<8}] {name}: {message}', '%Y-%m-%d %H:%M:%S', style='{')
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
self.logger = logger
|
||||
+66
-53
@@ -1,84 +1,97 @@
|
||||
from discord.ext import commands
|
||||
import discord
|
||||
import codecs
|
||||
from os import listdir
|
||||
from time import time
|
||||
|
||||
from codecs import open
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
import psycopg2
|
||||
import yaml
|
||||
|
||||
from os import listdir
|
||||
import locale
|
||||
from time import time
|
||||
import psycopg2
|
||||
from logger import BotLogger
|
||||
|
||||
|
||||
locale.setlocale(locale.LC_ALL, "")
|
||||
|
||||
with open("./src/config/config.yaml", "r", encoding="utf8") as f:
|
||||
# Load config file
|
||||
with codecs.open('./src/config/config.yaml', 'r', encoding='utf8') as f:
|
||||
config = yaml.load(f, Loader=yaml.SafeLoader)
|
||||
|
||||
intents = discord.Intents.all()
|
||||
|
||||
|
||||
class Bot(commands.Bot):
|
||||
"""UiO Gaming Bot"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
command_prefix=commands.when_mentioned_or(config["bot"]["prefix"]), case_insensitive=True, intents=intents
|
||||
command_prefix=commands.when_mentioned_or(config['bot']['prefix']),
|
||||
case_insensitive=True,
|
||||
intents=discord.Intents.all()
|
||||
)
|
||||
|
||||
self.prefix = config["bot"]["prefix"]
|
||||
self.presence = config["bot"].get("presence", {})
|
||||
self.logger = BotLogger().logger # Initialize logger
|
||||
|
||||
self.api_keys = config.get("api", {})
|
||||
|
||||
db = config.get("database", {})
|
||||
# Connect to 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'],
|
||||
)
|
||||
|
||||
self.emoji = config.get("emoji", {})
|
||||
self.misc = config.get("misc", {})
|
||||
# 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')
|
||||
|
||||
async def setup_hook(self):
|
||||
# Load cogs
|
||||
for file in listdir('./src/cogs'):
|
||||
if file.endswith('.py'):
|
||||
name = file[:-3]
|
||||
await bot.load_extension(f'cogs.{name}')
|
||||
|
||||
# Sync slash commands to Discord
|
||||
if self.config_mode == 'prod':
|
||||
await self.tree.sync()
|
||||
else:
|
||||
self.tree.copy_global_to(guild=discord.Object(id=412646636771344395))
|
||||
await self.tree.sync(guild=discord.Object(id=412646636771344395))
|
||||
|
||||
|
||||
# Create bot instance
|
||||
bot = Bot()
|
||||
|
||||
|
||||
activities = {"playing": 0, "listening": 2, "watching": 3}
|
||||
if bot.presence["activity"].lower() in activities:
|
||||
activity_type = activities[bot.presence["activity"].lower()]
|
||||
else:
|
||||
activity_type = 0
|
||||
|
||||
status_types = {
|
||||
"online": discord.Status.online,
|
||||
"dnd": discord.Status.dnd,
|
||||
"idle": discord.Status.idle,
|
||||
"offline": discord.Status.offline,
|
||||
}
|
||||
if bot.presence["type"].lower() in status_types:
|
||||
status_type = status_types[bot.presence["type"].lower()]
|
||||
else:
|
||||
status_type = discord.Status.online
|
||||
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
if not hasattr(bot, "uptime"):
|
||||
if not hasattr(bot, 'uptime'):
|
||||
bot.uptime = time()
|
||||
|
||||
for file in listdir("./src/cogs"):
|
||||
if file.endswith(".py"):
|
||||
name = file[:-3]
|
||||
bot.load_extension(f"cogs.{name}")
|
||||
# Print bot info
|
||||
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,
|
||||
}
|
||||
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)
|
||||
|
||||
print(f"Username: {bot.user.name}")
|
||||
print(f"ID: {bot.user.id}")
|
||||
print(f"Version: {discord.__version__}")
|
||||
print("." * 50 + "\n")
|
||||
await bot.change_presence(
|
||||
activity=discord.Activity(type=activity_type, name=bot.presence["message"]), status=status_type
|
||||
activity=discord.Activity(type=activity_type, name=bot.presence['message']),
|
||||
status=status_type
|
||||
)
|
||||
|
||||
|
||||
bot.run(config["bot"]["token"], bot=True, reconnect=True)
|
||||
bot.run(config['bot']['token'], reconnect=True, log_handler=None)
|
||||
Reference in new issue
Block a user