diff --git a/.github/workflows/PythonLint.yml b/.github/workflows/PythonLint.yml deleted file mode 100644 index 0f49332..0000000 --- a/.github/workflows/PythonLint.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Python Linting - -on: - push: - paths: - - "src/**" - -jobs: - tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: 3.8 - - name: Install dependencies - run: | - python -m pip install -U pip - pip install -r requirements.txt - - name: Flake8 Lint - run: | - pip install flake8 - flake8 --max-line-length=120 --show-source diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 0000000..5cf7ce5 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,14 @@ +name: pre-commit + +on: + pull_request: + push: + branches: [ "*" ] + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - uses: pre-commit/action@v3.0.0 diff --git a/.gitignore b/.gitignore index cfe343b..b668ef6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -*.yaml *.pyc *.log __pycache__/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..d7557af --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,26 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace + - id: requirements-txt-fixer + - id: end-of-file-fixer + + - repo: https://github.com/psf/black + rev: 23.3.0 + hooks: + - id: black + exclude: .*/deprecated/.* + + - repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + name: isort (python) + + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: 'v0.0.245' + hooks: + - id: ruff + exclude: .*/deprecated/.* diff --git a/LICENSE b/LICENSE index 2a15844..27d8355 100644 --- a/LICENSE +++ b/LICENSE @@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. \ No newline at end of file +. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..478dd59 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,12 @@ +[tool.black] +line-length = 120 + +[tool.isort] +atomic = true +profile = "black" +line_length = 120 +force_single_line = true +known_first_party = ["black"] + +[tool.ruff] +line-length = 120 diff --git a/src/cogs/anime.py b/src/cogs/anime.py index 3269fa1..d0c0417 100644 --- a/src/cogs/anime.py +++ b/src/cogs/anime.py @@ -1,10 +1,10 @@ -from datetime import datetime import re +from datetime import datetime import discord +import requests from discord import app_commands from discord.ext import commands -import requests from cogs.utils import embed_templates @@ -12,8 +12,10 @@ from cogs.utils import embed_templates class Anime(commands.Cog): """View information about different media on Anilist""" - anilist = app_commands.Group(name='anilist', description='Hent informasjon fra Anilist') - anilist_profile = app_commands.Group(parent=anilist, name='profil', description='Hent informasjon om en bruker på Anilist') + anilist = app_commands.Group(name="anilist", description="Hent informasjon fra Anilist") + anilist_profile = app_commands.Group( + parent=anilist, name="profil", description="Hent informasjon om en bruker på Anilist" + ) def __convert_color(self, color: str) -> int: """ @@ -29,13 +31,13 @@ class Anime(commands.Cog): """ colors = { - 'blue': 0x3db4f2, - 'purple': 0xc063ff, - 'pink': 0xFC9DD6, - 'orange': 0xEF881A, - 'red': 0xE13333, - 'green': 0x4CCA51, - 'gray': 0x677B94 + "blue": 0x3DB4F2, + "purple": 0xC063FF, + "pink": 0xFC9DD6, + "orange": 0xEF881A, + "red": 0xE13333, + "green": 0x4CCA51, + "gray": 0x677B94, } return colors.get(color, 0x677B94) @@ -54,14 +56,14 @@ class Anime(commands.Cog): """ media_formats = { - 'TV': 'TV-Serie', - 'TV_SHORT': 'Kort TV-Serie', - 'MOVIE': 'Film', - 'SPECIAL': 'Ekstramateriale', - 'MUSIC': 'Musikk', - 'MANGA': 'Manga', - 'NOVEL': 'Novelle', - 'ONE_SHOT': 'Kort Manga' + "TV": "TV-Serie", + "TV_SHORT": "Kort TV-Serie", + "MOVIE": "Film", + "SPECIAL": "Ekstramateriale", + "MUSIC": "Musikk", + "MANGA": "Manga", + "NOVEL": "Novelle", + "ONE_SHOT": "Kort Manga", } return media_formats.get(media_format, media_format) @@ -79,16 +81,16 @@ class Anime(commands.Cog): """ languages = { - 'JAPANESE': 'Japansk', - 'ENGLISH': 'Engelsk', - 'KOREAN': 'Koreansk', - 'ITALIAN': 'Italiensk', - 'SPANISH': 'Spansk', - 'PORTUGUESE': 'Portugisisk', - 'FRENCH': 'Fransk', - 'GERMAN': 'Tysk', - 'HEBREW': 'Hebraisk', - 'HUNGARIAN': 'Ungarsk' + "JAPANESE": "Japansk", + "ENGLISH": "Engelsk", + "KOREAN": "Koreansk", + "ITALIAN": "Italiensk", + "SPANISH": "Spansk", + "PORTUGUESE": "Portugisisk", + "FRENCH": "Fransk", + "GERMAN": "Tysk", + "HEBREW": "Hebraisk", + "HUNGARIAN": "Ungarsk", } return languages.get(language_name, language_name) @@ -106,11 +108,7 @@ class Anime(commands.Cog): (str): The role name in norwegian. If a translation doesn't exist it returns the english name """ - roles = { - 'MAIN': 'Hovedkarakter', - 'SUPPORTING': 'Bikarakter/Biperson', - 'BACKGROUND': 'Statist' - } + roles = {"MAIN": "Hovedkarakter", "SUPPORTING": "Bikarakter/Biperson", "BACKGROUND": "Statist"} try: return roles[role_name] except KeyError: @@ -130,10 +128,10 @@ class Anime(commands.Cog): """ statuses = { - 'FINISHED': 'Fullt utgitt', - 'RELEASING': 'Pågående', - 'NOT_YET_RELEASED': 'Ikke utgitt enda', - 'CANCELLED': 'Kansellert' + "FINISHED": "Fullt utgitt", + "RELEASING": "Pågående", + "NOT_YET_RELEASED": "Ikke utgitt enda", + "CANCELLED": "Kansellert", } return statuses.get(status, status) @@ -151,12 +149,14 @@ class Anime(commands.Cog): (str): The input string without HTML tags """ - compiled = re.compile(r'<.*?>') - clean_text = re.sub(compiled, '', text) + compiled = re.compile(r"<.*?>") + clean_text = re.sub(compiled, "", text) return clean_text - async def __request_anilist(self, interaction: discord.Interaction, query: str, variables: dict, key: str) -> tuple[dict, str] | tuple[None, None]: + async def __request_anilist( + self, interaction: discord.Interaction, query: str, variables: dict, key: str + ) -> tuple[dict, str] | tuple[None, None]: """ Makes a request to the Anilist API @@ -173,13 +173,13 @@ class Anime(commands.Cog): """ try: - url = 'https://graphql.anilist.co' - response = requests.post(url, json={'query': query, 'variables': variables}, timeout=10) + url = "https://graphql.anilist.co" + response = requests.post(url, json={"query": query, "variables": variables}, timeout=10) response = response.json() - data = response['data'][key] - url = data['siteUrl'] + data = response["data"][key] + url = data["siteUrl"] except TypeError: - embed = embed_templates.error_fatal(interaction, text='Kunne ikke finne det du søkte etter!') + embed = embed_templates.error_fatal(interaction, text="Kunne ikke finne det du søkte etter!") await interaction.response.send_message(embed=embed) return None, None @@ -201,14 +201,14 @@ class Anime(commands.Cog): favorite_media = [] for node in media: try: - nsfwtag = '🔞' if node['isAdult'] else '' - anime_name = node['title']['romaji'] - anime_url = node['siteUrl'] - favorite_media.append(f'[{anime_name}]({anime_url}){nsfwtag}') + nsfwtag = "🔞" if node["isAdult"] else "" + anime_name = node["title"]["romaji"] + anime_url = node["siteUrl"] + favorite_media.append(f"[{anime_name}]({anime_url}){nsfwtag}") except KeyError: pass - return ' | '.join(favorite_media) + return " | ".join(favorite_media) def __construct_favorite_entity_string(self, entities: list, studio: bool = False) -> str: """ @@ -228,15 +228,15 @@ class Anime(commands.Cog): for entity in entities: try: if studio: - entity_name = entity['name'] + entity_name = entity["name"] else: - entity_name = entity['name']['full'] - entity_url = entity['siteUrl'] - favortie_entities.append(f'[{entity_name}]({entity_url})') + entity_name = entity["name"]["full"] + entity_url = entity["siteUrl"] + favortie_entities.append(f"[{entity_name}]({entity_url})") except KeyError: pass - return ' | '.join(favortie_entities) + return " | ".join(favortie_entities) def __construct_release_schedule_string(self, numbers: dict) -> str: """ @@ -252,28 +252,28 @@ class Anime(commands.Cog): """ # Release and end date formatting - if numbers['start_day'] != '?' and numbers['start_month'] != '?' and numbers['start_year'] != '?': - release_date = datetime(numbers['start_year'], numbers['start_month'], numbers['start_day']) - release_date = discord.utils.format_dt(release_date, style='d') + if numbers["start_day"] != "?" and numbers["start_month"] != "?" and numbers["start_year"] != "?": + release_date = datetime(numbers["start_year"], numbers["start_month"], numbers["start_day"]) + release_date = discord.utils.format_dt(release_date, style="d") else: release_date = f'{numbers["start_day"]}.{numbers["start_month"]}.{numbers["start_year"]}' - if numbers["end_day"] != '?' and numbers["end_month"] != '?' and numbers["end_year"] != '?': + if numbers["end_day"] != "?" and numbers["end_month"] != "?" and numbers["end_year"] != "?": end_date = datetime(numbers["end_year"], numbers["end_month"], numbers["end_day"]) - end_date = discord.utils.format_dt(end_date, style='d') + end_date = discord.utils.format_dt(end_date, style="d") else: end_date = f'{numbers["end_day"]}.{numbers["end_month"]}.{numbers["end_year"]}' if release_date == end_date: date = release_date else: - date = f'{release_date} - {end_date}' + date = f"{release_date} - {end_date}" return date @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @anilist_profile.command(name='generelt', description='Viser informasjon om en Anilistprofil') + @anilist_profile.command(name="generelt", description="Viser informasjon om en Anilistprofil") async def anilist_profile_general(self, interaction: discord.Interaction, bruker: str): """ Shows general information about a user's Anilist profile @@ -357,61 +357,63 @@ class Anime(commands.Cog): } } """ - variables = { - 'name': bruker - } - data, url = await self.__request_anilist(interaction, query, variables, 'User') + variables = {"name": bruker} + data, url = await self.__request_anilist(interaction, query, variables, "User") if not data: return - user_name = data['name'] - profile_pic = data['avatar']['large'] - days_watched = round(data['statistics']['anime']['minutesWatched'] / 1440, 1) - chapters_read = data['statistics']['manga']['chaptersRead'] - color = self.__convert_color(data['options']['profileColor']) + user_name = data["name"] + profile_pic = data["avatar"]["large"] + days_watched = round(data["statistics"]["anime"]["minutesWatched"] / 1440, 1) + chapters_read = data["statistics"]["manga"]["chaptersRead"] + color = self.__convert_color(data["options"]["profileColor"]) - anime_statuses = {status['status']: {'count': status['count']} for status in data['statistics']['anime']['statuses']} - manga_statuses = {status['status']: {'count': status['count']} for status in data['statistics']['manga']['statuses']} + anime_statuses = { + status["status"]: {"count": status["count"]} for status in data["statistics"]["anime"]["statuses"] + } + manga_statuses = { + status["status"]: {"count": status["count"]} for status in data["statistics"]["manga"]["statuses"] + } try: - anime_completed = anime_statuses['COMPLETED']['count'] + anime_completed = anime_statuses["COMPLETED"]["count"] except KeyError: anime_completed = 0 try: - manga_completed = manga_statuses['COMPLETED']['count'] + manga_completed = manga_statuses["COMPLETED"]["count"] except KeyError: manga_completed = 0 - favourite_anime = self.__construct_favorite_media_string(data['favourites']['anime']['nodes']) - favourite_manga = self.__construct_favorite_media_string(data['favourites']['manga']['nodes']) - favourite_character = self.__construct_favorite_entity_string(data['favourites']['characters']['nodes']) - favourite_staff = self.__construct_favorite_entity_string(data['favourites']['staff']['nodes']) - favourite_studio = self.__construct_favorite_entity_string(data['favourites']['studios']['nodes'], studio=True) + favourite_anime = self.__construct_favorite_media_string(data["favourites"]["anime"]["nodes"]) + favourite_manga = self.__construct_favorite_media_string(data["favourites"]["manga"]["nodes"]) + favourite_character = self.__construct_favorite_entity_string(data["favourites"]["characters"]["nodes"]) + favourite_staff = self.__construct_favorite_entity_string(data["favourites"]["staff"]["nodes"]) + favourite_studio = self.__construct_favorite_entity_string(data["favourites"]["studios"]["nodes"], studio=True) embed = discord.Embed(title=user_name, color=color, url=url) - embed.set_author(name='Anilist', icon_url='https://anilist.co/img/logo_al.png') + embed.set_author(name="Anilist", icon_url="https://anilist.co/img/logo_al.png") embed.set_thumbnail(url=profile_pic) - embed.add_field(name='Antall dager sett', value=days_watched) - embed.add_field(name='Antall anime sett', value=anime_completed) - embed.add_field(name='Antall kapitler lest', value=chapters_read) - embed.add_field(name='Antall manga lest', value=manga_completed) + embed.add_field(name="Antall dager sett", value=days_watched) + embed.add_field(name="Antall anime sett", value=anime_completed) + embed.add_field(name="Antall kapitler lest", value=chapters_read) + embed.add_field(name="Antall manga lest", value=manga_completed) if favourite_anime: - embed.add_field(name='Noen favorittanime', value=favourite_anime, inline=False) + embed.add_field(name="Noen favorittanime", value=favourite_anime, inline=False) if favourite_manga: - embed.add_field(name='Noen favorittmanga', value=favourite_manga, inline=False) + embed.add_field(name="Noen favorittmanga", value=favourite_manga, inline=False) if favourite_character: - embed.add_field(name='Noen favorittkarakterer', value=favourite_character, inline=False) + embed.add_field(name="Noen favorittkarakterer", value=favourite_character, inline=False) if favourite_studio: - embed.add_field(name='Noen favorittstudioer', value=favourite_studio, inline=False) + embed.add_field(name="Noen favorittstudioer", value=favourite_studio, inline=False) if favourite_studio: - embed.add_field(name='Noen favorittskapere', value=favourite_staff, inline=False) + embed.add_field(name="Noen favorittskapere", value=favourite_staff, inline=False) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @anilist_profile.command(name='anime', description='Se statistikk om animetittingen til en bruker') + @anilist_profile.command(name="anime", description="Se statistikk om animetittingen til en bruker") async def anilist_profile_anime_stats(self, interaction: discord.Interaction, bruker: str): """ Shows anime viewing statistics from a user's Anilist profile @@ -458,68 +460,69 @@ class Anime(commands.Cog): } } """ - variables = { - 'name': bruker - } - data, url = await self.__request_anilist(interaction, query, variables, 'User') + variables = {"name": bruker} + data, url = await self.__request_anilist(interaction, query, variables, "User") if not data: return - user_name = data['name'] - profile_pic = data['avatar']['large'] - days_watched = round(data['statistics']['anime']['minutesWatched'] / 1440, 1) - episodes_watched = data['statistics']['anime']['episodesWatched'] - color = self.__convert_color(data['options']['profileColor']) + user_name = data["name"] + profile_pic = data["avatar"]["large"] + days_watched = round(data["statistics"]["anime"]["minutesWatched"] / 1440, 1) + episodes_watched = data["statistics"]["anime"]["episodesWatched"] + color = self.__convert_color(data["options"]["profileColor"]) - statuses = {status['status']: {'count': status['count'], 'minutes': status['minutesWatched']} for status in data['statistics']['anime']['statuses']} + statuses = { + status["status"]: {"count": status["count"], "minutes": status["minutesWatched"]} + for status in data["statistics"]["anime"]["statuses"] + } try: - completed = statuses['COMPLETED']['count'] + completed = statuses["COMPLETED"]["count"] except KeyError: completed = 0 try: - watching = statuses['CURRENT']['count'] + watching = statuses["CURRENT"]["count"] except KeyError: watching = 0 try: - planning = statuses['PLANNING']['count'] - planning_days = round(statuses['PLANNING']['minutes'] / 1440, 1) + planning = statuses["PLANNING"]["count"] + planning_days = round(statuses["PLANNING"]["minutes"] / 1440, 1) except KeyError: planning = 0 planning_days = 0 try: - dropped = statuses['DROPPED']['count'] + dropped = statuses["DROPPED"]["count"] except KeyError: dropped = 0 - anime_mean_score = data['statistics']['anime']['meanScore'] + anime_mean_score = data["statistics"]["anime"]["meanScore"] if not anime_mean_score: - anime_mean_score = '**Ingen**' + anime_mean_score = "**Ingen**" - most_watched_genres = ', '.join([genre['genre'] for genre in data['statistics']['anime']['genres']]) - most_watched_studios = self.__construct_favorite_entity_string(data['statistics']['anime']['studios']) + most_watched_genres = ", ".join([genre["genre"] for genre in data["statistics"]["anime"]["genres"]]) + most_watched_studios = self.__construct_favorite_entity_string(data["statistics"]["anime"]["studios"]) embed = discord.Embed(title=user_name, color=color, url=url) - embed.set_author(name='Anilist', icon_url='https://anilist.co/img/logo_al.png') + embed.set_author(name="Anilist", icon_url="https://anilist.co/img/logo_al.png") embed.set_thumbnail(url=profile_pic) - embed.add_field(name='Gj.snittsvurdering gitt', value=anime_mean_score) - embed.add_field(name='Antall dager sett', value=days_watched) - embed.add_field(name='Antall episoder sett', value=episodes_watched) - embed.add_field(name='Antall anime sett', value=completed) - embed.add_field(name='Ser på nå', value=watching) - embed.add_field(name='Planlegger å se', value=f'{planning}\n({planning_days} dager)') - embed.add_field(name='Droppet', value=dropped) + embed.add_field(name="Gj.snittsvurdering gitt", value=anime_mean_score) + embed.add_field(name="Antall dager sett", value=days_watched) + embed.add_field(name="Antall episoder sett", value=episodes_watched) + embed.add_field(name="Antall anime sett", value=completed) + embed.add_field(name="Ser på nå", value=watching) + embed.add_field(name="Planlegger å se", value=f"{planning}\n({planning_days} dager)") + embed.add_field(name="Droppet", value=dropped) if most_watched_genres: - embed.add_field(name='Mest sette sjangere', value=most_watched_genres, inline=False) + embed.add_field(name="Mest sette sjangere", value=most_watched_genres, inline=False) if most_watched_studios: - embed.add_field(name='Mest sette studioer', value=most_watched_studios, inline=False) + embed.add_field(name="Mest sette studioer", value=most_watched_studios, inline=False) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @anilist_profile.command(name='manga', description='Se statistikk om mangalesingen til en bruker') + @anilist_profile.command(name="manga", description="Se statistikk om mangalesingen til en bruker") async def anilist_profile_manga_stats(self, interaction: discord.Interaction, bruker: str): """ Shows manga reading statistics from a user's Anilist profile @@ -568,68 +571,69 @@ class Anime(commands.Cog): } } """ - variables = { - 'name': bruker - } - data, url = await self.__request_anilist(interaction, query, variables, 'User') + variables = {"name": bruker} + data, url = await self.__request_anilist(interaction, query, variables, "User") if not data: return - user_name = data['name'] - profile_pic = data['avatar']['large'] - chapters_read = round(data['statistics']['manga']['chaptersRead'] / 1440, 1) - volumes_read = data['statistics']['manga']['volumesRead'] - color = self.__convert_color(data['options']['profileColor']) + user_name = data["name"] + profile_pic = data["avatar"]["large"] + chapters_read = round(data["statistics"]["manga"]["chaptersRead"] / 1440, 1) + volumes_read = data["statistics"]["manga"]["volumesRead"] + color = self.__convert_color(data["options"]["profileColor"]) - statuses = {status['status']: {'count': status['count'], 'minutes': status['chaptersRead']} for status in data['statistics']['manga']['statuses']} + statuses = { + status["status"]: {"count": status["count"], "minutes": status["chaptersRead"]} + for status in data["statistics"]["manga"]["statuses"] + } try: - completed = statuses['COMPLETED']['count'] + completed = statuses["COMPLETED"]["count"] except KeyError: completed = 0 try: - reading = statuses['CURRENT']['count'] + reading = statuses["CURRENT"]["count"] except KeyError: reading = 0 try: - planning = statuses['PLANNING']['count'] - planning_days = statuses['PLANNING']['chaptersRead'] + planning = statuses["PLANNING"]["count"] + planning_days = statuses["PLANNING"]["chaptersRead"] except KeyError: planning = 0 planning_days = 0 try: - dropped = statuses['DROPPED']['count'] + dropped = statuses["DROPPED"]["count"] except KeyError: dropped = 0 - manga_mean_score = data['statistics']['manga']['meanScore'] + manga_mean_score = data["statistics"]["manga"]["meanScore"] if manga_mean_score == 0: - manga_mean_score = '**Ingen**' + manga_mean_score = "**Ingen**" - most_read_genres = ', '.join([genre['genre'] for genre in data['statistics']['manga']['genres']]) - most_read_staff = self.__construct_favorite_entity_string(data['statistics']['manga']['staff']) + most_read_genres = ", ".join([genre["genre"] for genre in data["statistics"]["manga"]["genres"]]) + most_read_staff = self.__construct_favorite_entity_string(data["statistics"]["manga"]["staff"]) embed = discord.Embed(title=user_name, color=color, url=url) - embed.set_author(name='Anilist', icon_url='https://anilist.co/img/logo_al.png') + embed.set_author(name="Anilist", icon_url="https://anilist.co/img/logo_al.png") embed.set_thumbnail(url=profile_pic) - embed.add_field(name='Gj.snittsvurdering gitt', value=manga_mean_score) - embed.add_field(name='Antall kapitler lest', value=chapters_read) - embed.add_field(name='Antall volum lest', value=volumes_read) - embed.add_field(name='Antall manga lest', value=completed) - embed.add_field(name='Leser nå', value=reading) - embed.add_field(name='Planlegger å lese', value=f'{planning}\n({planning_days} kapitler)') - embed.add_field(name='Droppet', value=dropped) + embed.add_field(name="Gj.snittsvurdering gitt", value=manga_mean_score) + embed.add_field(name="Antall kapitler lest", value=chapters_read) + embed.add_field(name="Antall volum lest", value=volumes_read) + embed.add_field(name="Antall manga lest", value=completed) + embed.add_field(name="Leser nå", value=reading) + embed.add_field(name="Planlegger å lese", value=f"{planning}\n({planning_days} kapitler)") + embed.add_field(name="Droppet", value=dropped) if most_read_genres: - embed.add_field(name='Mest leste sjangere', value=most_read_genres, inline=False) + embed.add_field(name="Mest leste sjangere", value=most_read_genres, inline=False) if most_read_staff: - embed.add_field(name='Mest leste skapere', value=most_read_staff, inline=False) + embed.add_field(name="Mest leste skapere", value=most_read_staff, inline=False) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @anilist.command(name='anime', description='Hent informasjon om en anime') + @anilist.command(name="anime", description="Hent informasjon om en anime") async def anilist_anime(self, interaction: discord.Interaction, navn: str): """ Shows information about an anime @@ -695,101 +699,99 @@ class Anime(commands.Cog): } } """ - variables = { - 'search': navn, - 'isMain': True - } - data, url = await self.__request_anilist(interaction, query, variables, 'Media') + variables = {"search": navn, "isMain": True} + data, url = await self.__request_anilist(interaction, query, variables, "Media") if not data: return - nsfw = data['isAdult'] + nsfw = data["isAdult"] if nsfw: - embed = embed_templates.error_fatal(interaction, text='Animen du søkte på er NSFW. ' + - 'Gjør kommandoen i en NSFW-kanal i stedet') + embed = embed_templates.error_fatal( + interaction, text="Animen du søkte på er NSFW. " + "Gjør kommandoen i en NSFW-kanal i stedet" + ) return await interaction.response.send_message(embed=embed) - cover_image = data['coverImage']['large'] - banner_image = data['bannerImage'] - mean_score = data['meanScore'] + cover_image = data["coverImage"]["large"] + banner_image = data["bannerImage"] + mean_score = data["meanScore"] - color = self.__convert_color(data['coverImage']['color']) + color = self.__convert_color(data["coverImage"]["color"]) - title_romaji = data['title']['romaji'] - title_native = data['title']['native'] - title_english = data['title']['english'] + title_romaji = data["title"]["romaji"] + title_native = data["title"]["native"] + title_english = data["title"]["english"] titles = [title_romaji, title_native, title_english] - title_romaji, title_native, title_english = [title if title else '' for title in titles] + title_romaji, title_native, title_english = [title if title else "" for title in titles] - description = self.__remove_html(data['description']) if data['description'] else '' - genres = ', '.join(data['genres']) - studios_string = self.__construct_favorite_entity_string(data['studios']['nodes'], studio=True) + description = self.__remove_html(data["description"]) if data["description"] else "" + genres = ", ".join(data["genres"]) + studios_string = self.__construct_favorite_entity_string(data["studios"]["nodes"], studio=True) - staff = data['staff']['edges'] - director_string = '' + staff = data["staff"]["edges"] + director_string = "" for staff_member in staff: - if staff_member['role'] == 'Director': - director_first_name = staff_member['node']['name']['first'] - director_last_name = staff_member['node']['name']['last'] - director_native_name = staff_member['node']['name']['native'] - director_url = staff_member['node']['siteUrl'] - director_string += f'[{director_first_name} {director_last_name} ' +\ - f'({director_native_name})]({director_url})' + if staff_member["role"] == "Director": + director_first_name = staff_member["node"]["name"]["first"] + director_last_name = staff_member["node"]["name"]["last"] + director_native_name = staff_member["node"]["name"]["native"] + director_url = staff_member["node"]["siteUrl"] + director_string += ( + f"[{director_first_name} {director_last_name} " + f"({director_native_name})]({director_url})" + ) - episodes = data['episodes'] - duration = data['duration'] + episodes = data["episodes"] + duration = data["duration"] numbers = { - 'episodes': episodes, - 'duration': duration, - 'start_day': data['startDate'].get('day') if data['startDate'].get('day') else '?', - 'start_month': data['startDate'].get('month') if data['startDate'].get('month') else '?', - 'start_year': data['startDate'].get('year') if data['startDate'].get('year') else '?', - 'end_day': data['endDate'].get('day') if data['endDate'].get('day') else '?', - 'end_month': data['endDate'].get('month') if data['endDate'].get('month') else '?', - 'end_year': data['endDate'].get('year') if data['endDate'].get('year') else '?' + "episodes": episodes, + "duration": duration, + "start_day": data["startDate"].get("day") if data["startDate"].get("day") else "?", + "start_month": data["startDate"].get("month") if data["startDate"].get("month") else "?", + "start_year": data["startDate"].get("year") if data["startDate"].get("year") else "?", + "end_day": data["endDate"].get("day") if data["endDate"].get("day") else "?", + "end_month": data["endDate"].get("month") if data["endDate"].get("month") else "?", + "end_year": data["endDate"].get("year") if data["endDate"].get("year") else "?", } date = self.__construct_release_schedule_string(numbers) - length_string = '' - if numbers['duration'] == 1: - length_string += 'minutt ' + length_string = "" + if numbers["duration"] == 1: + length_string += "minutt " else: - length_string += 'minutter ' - if numbers['episodes'] == 1: - length_string += 'lang' + length_string += "minutter " + if numbers["episodes"] == 1: + length_string += "lang" else: - length_string += 'lange' + length_string += "lange" # Status - status = data['status'] + status = data["status"] status = self.__convert_status(status) # Format - media_format = data['format'] + media_format = data["format"] media_format = self.__convert_media_format(media_format) - embed = discord.Embed(color=color, title=title_romaji, url=url, - description=f'{title_native}\n{title_english}') + embed = discord.Embed(color=color, title=title_romaji, url=url, description=f"{title_native}\n{title_english}") embed.set_thumbnail(url=cover_image) - embed.add_field(name='Format', value=media_format) - embed.add_field(name='Status', value=status) + embed.add_field(name="Format", value=media_format) + embed.add_field(name="Status", value=status) if studios_string: - embed.add_field(name='Studio', value=studios_string) + embed.add_field(name="Studio", value=studios_string) if director_string: - embed.add_field(name='Regissør', value=director_string) - embed.add_field(name='Utgivelsesdato', value=date) - if media_format == 'Film': - embed.add_field(name='Lengde', value=f'{duration} minutter') + embed.add_field(name="Regissør", value=director_string) + embed.add_field(name="Utgivelsesdato", value=date) + if media_format == "Film": + embed.add_field(name="Lengde", value=f"{duration} minutter") else: - embed.add_field(name='Episoder', value=f'{episodes} ({duration} {length_string})') + embed.add_field(name="Episoder", value=f"{episodes} ({duration} {length_string})") if mean_score: - embed.add_field(name='Gj.snittsvurdering', value=f'{mean_score}/100') - embed.add_field(name='Sjangere', value=genres) + embed.add_field(name="Gj.snittsvurdering", value=f"{mean_score}/100") + embed.add_field(name="Sjangere", value=genres) if len(description) < 1024 and description: - embed.add_field(name='Sammendrag', value=description, inline=False) + embed.add_field(name="Sammendrag", value=description, inline=False) if banner_image: embed.set_image(url=banner_image) embed_templates.default_footer(interaction, embed) @@ -797,7 +799,7 @@ class Anime(commands.Cog): @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @anilist.command(name='manga', description='Hent informasjon om en manga') + @anilist.command(name="manga", description="Hent informasjon om en manga") async def anilist_manga(self, interaction: discord.Interaction, navn: str): """ Shows information about a manga @@ -856,82 +858,80 @@ class Anime(commands.Cog): } } """ - variables = { - 'search': navn - } - data, url = await self.__request_anilist(interaction, query, variables, 'Media') + variables = {"search": navn} + data, url = await self.__request_anilist(interaction, query, variables, "Media") if not data: return - nsfw = data['isAdult'] + nsfw = data["isAdult"] if nsfw: - embed = embed_templates.error_fatal(interaction, text='Mangaen du søkte på er NSFW. ' + - 'Gjør kommandoen i en NSFW-kanal i stedet') + embed = embed_templates.error_fatal( + interaction, text="Mangaen du søkte på er NSFW. " + "Gjør kommandoen i en NSFW-kanal i stedet" + ) return await interaction.response.send_message(embed=embed) - cover_image = data['coverImage']['large'] - banner_image = data['bannerImage'] - mean_score = data['meanScore'] + cover_image = data["coverImage"]["large"] + banner_image = data["bannerImage"] + mean_score = data["meanScore"] - color = self.__convert_color(data['coverImage']['color']) + color = self.__convert_color(data["coverImage"]["color"]) - title_romaji = data['title']['romaji'] - title_native = data['title']['native'] - title_english = data['title']['english'] + title_romaji = data["title"]["romaji"] + title_native = data["title"]["native"] + title_english = data["title"]["english"] titles = [title_romaji, title_native, title_english] - title_romaji, title_native, title_english = [title if title else '' for title in titles] + title_romaji, title_native, title_english = [title if title else "" for title in titles] - description = self.__remove_html(data['description']) if data.get('description') else '' - genres = ', '.join(data['genres']) + description = self.__remove_html(data["description"]) if data.get("description") else "" + genres = ", ".join(data["genres"]) - staff = data['staff']['edges'] - staff_string = '' + staff = data["staff"]["edges"] + staff_string = "" for staff_member in staff: - staff_first_name = staff_member['node']['name']['first'] - staff_last_name = staff_member['node']['name']['last'] - staff_native_name = staff_member['node']['name']['native'] - staff_url = staff_member['node']['siteUrl'] - staff_string += f'[{staff_first_name} {staff_last_name} ({staff_native_name})]({staff_url})\n' + staff_first_name = staff_member["node"]["name"]["first"] + staff_last_name = staff_member["node"]["name"]["last"] + staff_native_name = staff_member["node"]["name"]["native"] + staff_url = staff_member["node"]["siteUrl"] + staff_string += f"[{staff_first_name} {staff_last_name} ({staff_native_name})]({staff_url})\n" numbers = { - 'chapters': data['chapters'], - 'volumes': data['volumes'], - 'start_day': data['startDate'].get('day') if data['startDate'].get('day') else '?', - 'start_month': data['startDate'].get('month') if data['startDate'].get('month') else '?', - 'start_year': data['startDate'].get('year') if data['startDate'].get('year') else '?', - 'end_day': data['endDate'].get('day') if data['endDate'].get('day') else '?', - 'end_month': data['endDate'].get('month') if data['endDate'].get('month') else '?', - 'end_year': data['endDate'].get('year') if data['endDate'].get('year') else '?' + "chapters": data["chapters"], + "volumes": data["volumes"], + "start_day": data["startDate"].get("day") if data["startDate"].get("day") else "?", + "start_month": data["startDate"].get("month") if data["startDate"].get("month") else "?", + "start_year": data["startDate"].get("year") if data["startDate"].get("year") else "?", + "end_day": data["endDate"].get("day") if data["endDate"].get("day") else "?", + "end_month": data["endDate"].get("month") if data["endDate"].get("month") else "?", + "end_year": data["endDate"].get("year") if data["endDate"].get("year") else "?", } date = self.__construct_release_schedule_string(numbers) - chapters_string = '' - if numbers['chapters'] == 1: - chapters_string += 'kapittel' + chapters_string = "" + if numbers["chapters"] == 1: + chapters_string += "kapittel" else: - chapters_string += 'kapitler' + chapters_string += "kapitler" - status = data['status'] + status = data["status"] status = self.__convert_status(status) - media_format = data['format'] + media_format = data["format"] media_format = self.__convert_media_format(media_format) - embed = discord.Embed(color=color, title=title_romaji, url=url, - description=f'{title_native}\n{title_english}') + embed = discord.Embed(color=color, title=title_romaji, url=url, description=f"{title_native}\n{title_english}") embed.set_thumbnail(url=cover_image) - embed.add_field(name='Format', value=media_format) - embed.add_field(name='Status', value=status) + embed.add_field(name="Format", value=media_format) + embed.add_field(name="Status", value=status) if staff_string: - embed.add_field(name='Laget av', value=staff_string) - embed.add_field(name='Utgivelsesdato', value=date) - embed.add_field(name='Lengde', value=f'{numbers["chapters"]} {chapters_string}\n{numbers["volumes"]} volum') + embed.add_field(name="Laget av", value=staff_string) + embed.add_field(name="Utgivelsesdato", value=date) + embed.add_field(name="Lengde", value=f'{numbers["chapters"]} {chapters_string}\n{numbers["volumes"]} volum') if mean_score: - embed.add_field(name='Gj.snittsvurdering', value=f'{mean_score}/100') - embed.add_field(name='Sjangere', value=genres) + embed.add_field(name="Gj.snittsvurdering", value=f"{mean_score}/100") + embed.add_field(name="Sjangere", value=genres) if len(description) < 1024 and description: - embed.add_field(name='Sammendrag', value=description, inline=False) + embed.add_field(name="Sammendrag", value=description, inline=False) if banner_image: embed.set_image(url=banner_image) embed_templates.default_footer(interaction, embed) @@ -939,7 +939,7 @@ class Anime(commands.Cog): @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @anilist.command(name='karakter', description='Hent informasjon om en karakter') + @anilist.command(name="karakter", description="Hent informasjon om en karakter") async def anilist_character(self, interaction: discord.Interaction, navn: str): """ Shows information about a character @@ -986,57 +986,55 @@ class Anime(commands.Cog): } } """ - variables = { - 'search': navn - } - data, url = await self.__request_anilist(interaction, query, variables, 'Character') + variables = {"search": navn} + data, url = await self.__request_anilist(interaction, query, variables, "Character") if not data: return - name_romaji = data['name']['full'] - name_native = data['name']['native'] - image = data['image']['large'] - favourites = data['favourites'] + name_romaji = data["name"]["full"] + name_native = data["name"]["native"] + image = data["image"]["large"] + favourites = data["favourites"] - if data['description']: - description = self.__remove_html(data['description']) + if data["description"]: + description = self.__remove_html(data["description"]) if len(description) > 1024: - description = description[0:1020] + '...' + description = description[0:1020] + "..." else: - description = '*Ingen biografi funnet* 😔' + description = "*Ingen biografi funnet* 😔" featured_in = [] voice_actors = [] - for media in data['media']['edges']: - nsfwtag = '🔞' if media['node']['isAdult'] else '' - media_name = media['node']['title']['romaji'] - media_url = media['node']['siteUrl'] - media_role = self.__convert_role_names(media['characterRole']) - for voice_actor in media['voiceActors']: - voice_actor_url = voice_actor['siteUrl'] - voice_actor_language = self.__convert_language_names(voice_actor['language']) - voice_actor_name = voice_actor['name']['full'] - if voice_actor['name']['native'] != ' ' and voice_actor['name']['native'] is not None: + for media in data["media"]["edges"]: + nsfwtag = "🔞" if media["node"]["isAdult"] else "" + media_name = media["node"]["title"]["romaji"] + media_url = media["node"]["siteUrl"] + media_role = self.__convert_role_names(media["characterRole"]) + for voice_actor in media["voiceActors"]: + voice_actor_url = voice_actor["siteUrl"] + voice_actor_language = self.__convert_language_names(voice_actor["language"]) + voice_actor_name = voice_actor["name"]["full"] + if voice_actor["name"]["native"] != " " and voice_actor["name"]["native"] is not None: voice_actor_name += f' ({voice_actor["name"]["native"]}' - voice_actors.append(f'{voice_actor_language} stemme: [{voice_actor_name}]({voice_actor_url})') + voice_actors.append(f"{voice_actor_language} stemme: [{voice_actor_name}]({voice_actor_url})") - voice_actors_string = '\n'.join(voice_actors) - featured_in.append(f'[{media_name}]({media_url}){nsfwtag} som {media_role}\n{voice_actors_string}') + voice_actors_string = "\n".join(voice_actors) + featured_in.append(f"[{media_name}]({media_url}){nsfwtag} som {media_role}\n{voice_actors_string}") - featured_in = '\n\n'.join(featured_in) + featured_in = "\n\n".join(featured_in) embed = discord.Embed(color=0x02A9FF, title=name_romaji, url=url, description=name_native) embed.set_thumbnail(url=image) - embed.add_field(name='Antall favoritter på Anilist', value=favourites, inline=False) - embed.add_field(name='Biografi', value=description, inline=False) - embed.add_field(name='Er med i bl.a.', value=featured_in, inline=False) + embed.add_field(name="Antall favoritter på Anilist", value=favourites, inline=False) + embed.add_field(name="Biografi", value=description, inline=False) + embed.add_field(name="Er med i bl.a.", value=featured_in, inline=False) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @anilist.command(name='skaper', description='Hent informasjon om en skaper') + @anilist.command(name="skaper", description="Hent informasjon om en skaper") async def anilist_creator(self, interaction: discord.Interaction, navn: str): """ Shows information about a creator @@ -1087,58 +1085,56 @@ class Anime(commands.Cog): } } """ - variables = { - 'search': navn - } - data, url = await self.__request_anilist(interaction, query, variables, 'Staff') + variables = {"search": navn} + data, url = await self.__request_anilist(interaction, query, variables, "Staff") if not data: return - name_romaji = data['name']['full'] - name_native = data['name']['native'] - image = data['image']['large'] - favourites = data['favourites'] + name_romaji = data["name"]["full"] + name_native = data["name"]["native"] + image = data["image"]["large"] + favourites = data["favourites"] - if data['description']: - description = self.__remove_html(data['description']) + if data["description"]: + description = self.__remove_html(data["description"]) if len(description) > 1024: - description = description[0:1020] + '...' + description = description[0:1020] + "..." else: - description = '*Ingen biografi funnet* 😔' + description = "*Ingen biografi funnet* 😔" featured_in = [] - for media in data['staffMedia']['edges']: - nsfwtag = '🔞' if media['node']['isAdult'] else '' - media_name = media['node']['title']['romaji'] - media_url = media['node']['siteUrl'] - media_role = media['staffRole'] - featured_in.append(f'[{media_name}]({media_url}){nsfwtag}\n{media_role}') - featured_in = '\n\n'.join(featured_in) + for media in data["staffMedia"]["edges"]: + nsfwtag = "🔞" if media["node"]["isAdult"] else "" + media_name = media["node"]["title"]["romaji"] + media_url = media["node"]["siteUrl"] + media_role = media["staffRole"] + featured_in.append(f"[{media_name}]({media_url}){nsfwtag}\n{media_role}") + featured_in = "\n\n".join(featured_in) characters = [] - for character in data['characters']['edges']: - character_url = character['node']['siteUrl'] - character_name = character['node']['name']['full'] - if character['node']['name']['native'] != ' ' and character['node']['name']['native'] is not None: + for character in data["characters"]["edges"]: + character_url = character["node"]["siteUrl"] + character_name = character["node"]["name"]["full"] + if character["node"]["name"]["native"] != " " and character["node"]["name"]["native"] is not None: character_name += f' ({character["node"]["name"]["native"]}' - characters.append(f'[{character_name}]({character_url})') - characters = '\n\n'.join(characters) + characters.append(f"[{character_name}]({character_url})") + characters = "\n\n".join(characters) embed = discord.Embed(color=0x02A9FF, title=name_romaji, url=url, description=name_native) embed.set_thumbnail(url=image) - embed.add_field(name='Antall favoritter på Anilist', value=favourites, inline=False) - embed.add_field(name='Biografi', value=description, inline=False) + embed.add_field(name="Antall favoritter på Anilist", value=favourites, inline=False) + embed.add_field(name="Biografi", value=description, inline=False) if characters: - embed.add_field(name='Har vært stemmen til bl.a.', value=characters, inline=False) + embed.add_field(name="Har vært stemmen til bl.a.", value=characters, inline=False) if featured_in: - embed.add_field(name='Har deltatt i produksjonen av bl.a.', value=featured_in, inline=False) + embed.add_field(name="Har deltatt i produksjonen av bl.a.", value=featured_in, inline=False) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @anilist.command(name='studio', description='Hent informasjon om et studio') + @anilist.command(name="studio", description="Hent informasjon om et studio") async def anilist_studio(self, interaction: discord.Interaction, navn: str): """ Shows information about a studio @@ -1170,24 +1166,22 @@ class Anime(commands.Cog): } } """ - variables = { - 'search': navn - } - data, url = await self.__request_anilist(interaction, query, variables, 'Studio') + variables = {"search": navn} + data, url = await self.__request_anilist(interaction, query, variables, "Studio") if not data: return - name = data['name'] - favourites = data['favourites'] + name = data["name"] + favourites = data["favourites"] popular_media = [] - for media in data['media']['nodes']: - nsfwtag = '🔞' if media['isAdult'] else '' - media_name = media['title']['romaji'] - media_url = media['siteUrl'] - popular_media.append(f'- [{media_name}]({media_url}){nsfwtag}') - popular_media = '\n'.join(popular_media) + for media in data["media"]["nodes"]: + nsfwtag = "🔞" if media["isAdult"] else "" + media_name = media["title"]["romaji"] + media_url = media["siteUrl"] + popular_media.append(f"- [{media_name}]({media_url}){nsfwtag}") + popular_media = "\n".join(popular_media) query2 = """ query ($search: String) { @@ -1205,30 +1199,32 @@ class Anime(commands.Cog): } } """ - data = requests.post('https://graphql.anilist.co', json={'query': query2, 'variables': variables}, timeout=10).json() - data = data['data']['Studio'] + data = requests.post( + "https://graphql.anilist.co", json={"query": query2, "variables": variables}, timeout=10 + ).json() + data = data["data"]["Studio"] recent_media = [] upcoming_media = [] - for media in data['media']['nodes']: - nsfwtag = '🔞' if media['isAdult'] else '' - media_name = media['title']['romaji'] - media_url = media['siteUrl'] - if media['status'] == 'NOT_YET_RELEASED': - upcoming_media.append(f'- [{media_name}]({media_url}){nsfwtag}') + for media in data["media"]["nodes"]: + nsfwtag = "🔞" if media["isAdult"] else "" + media_name = media["title"]["romaji"] + media_url = media["siteUrl"] + if media["status"] == "NOT_YET_RELEASED": + upcoming_media.append(f"- [{media_name}]({media_url}){nsfwtag}") else: - recent_media.append(f'- [{media_name}]({media_url}){nsfwtag}') - recent_media = '\n'.join(recent_media[0:3]) - upcoming_media = '\n'.join(upcoming_media[0:3]) + recent_media.append(f"- [{media_name}]({media_url}){nsfwtag}") + recent_media = "\n".join(recent_media[0:3]) + upcoming_media = "\n".join(upcoming_media[0:3]) embed = discord.Embed(color=0x02A9FF, title=name, url=url) - embed.add_field(name='Antall favoritter på Anilist', value=favourites, inline=False) + embed.add_field(name="Antall favoritter på Anilist", value=favourites, inline=False) if popular_media: - embed.add_field(name='Mest Populære Anime', value=popular_media, inline=False) + embed.add_field(name="Mest Populære Anime", value=popular_media, inline=False) if recent_media: - embed.add_field(name='Nyeste Utgitte Anime', value=recent_media, inline=False) + embed.add_field(name="Nyeste Utgitte Anime", value=recent_media, inline=False) if upcoming_media: - embed.add_field(name='Kommende Anime', value=upcoming_media, inline=False) + embed.add_field(name="Kommende Anime", value=upcoming_media, inline=False) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) diff --git a/src/cogs/birthday.py b/src/cogs/birthday.py index 25f9d29..f56ac12 100644 --- a/src/cogs/birthday.py +++ b/src/cogs/birthday.py @@ -1,13 +1,15 @@ import asyncio from datetime import datetime -from dateutil.relativedelta import relativedelta import discord -from discord import app_commands -from discord.ext import commands, tasks import psycopg2 +from dateutil.relativedelta import relativedelta +from discord import app_commands +from discord.ext import commands +from discord.ext import tasks -from cogs.utils import discord_utils, embed_templates +from cogs.utils import discord_utils +from cogs.utils import embed_templates class Birthday(commands.Cog): @@ -59,7 +61,7 @@ class Birthday(commands.Cog): for birthday in birthdays: user = self.bot.get_user(birthday[0]) if user: - await channel.send(f'Gratulrer med dagen {user.mention}!') + await channel.send(f"Gratulrer med dagen {user.mention}!") @birthday_check.before_loop async def before_birthday_check(self): @@ -92,7 +94,7 @@ class Birthday(commands.Cog): (datetime | None): The birthday of the user """ - self.cursor.execute('SELECT birthday FROM birthdays WHERE discord_id = (%s)', (user_id,)) + self.cursor.execute("SELECT birthday FROM birthdays WHERE discord_id = (%s)", (user_id,)) result = self.cursor.fetchone() if result: birthday = result[0] @@ -113,17 +115,19 @@ class Birthday(commands.Cog): 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,) + SELECT *, CAST(birthday + ((EXTRACT(YEAR FROM AGE(birthday)) + 1) * interval '1' YEAR) AS DATE) AS next_fbirthday + FROM birthdays + WHERE discord_id = %s + """, + (user_id,), ) 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 + # This will never happen unless a database error occurs. Keeping the type checker happy + return datetime.now() def __fetch_next_birthdays(self) -> list[tuple[int, datetime, datetime]]: """ @@ -169,14 +173,16 @@ class Birthday(commands.Cog): """ INSERT INTO birthdays (discord_id, birthday) VALUES (%s, %s) - """, (user_id, birthday)) + """, + (user_id, birthday), + ) 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)) @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') + @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. @@ -193,30 +199,33 @@ class Birthday(commands.Cog): date = datetime(år, måned, dag) except ValueError: return await interaction.response.send_message( - embed=embed_templates.error_fatal(interaction, text='ikke en gyldig dato, gjøk!'), - ephemeral=True + embed=embed_templates.error_fatal(interaction, text="ikke en gyldig dato, gjøk!"), ephemeral=True ) if date.year < 1970: return await interaction.response.send_message( - embed=embed_templates.error_fatal(interaction, text='Ok boomer, men nei. Hvorfor? Unix timestamps. Google it'), - ephemeral=True + embed=embed_templates.error_fatal( + interaction, text="Ok boomer, men nei. Hvorfor? Unix timestamps. Google it" + ), + ephemeral=True, ) if date > datetime.now(): return await interaction.response.send_message( - embed=embed_templates.error_fatal(interaction, text='Du kan ikke sette en fremtidig dato!'), - ephemeral=True + embed=embed_templates.error_fatal(interaction, text="Du kan ikke sette en fremtidig dato!"), + ephemeral=True, ) self.__set_user_birthday(interaction.user.id, date) - embed = embed_templates.success(interaction, text=f'Bursdag satt til {discord.utils.format_dt(date, style="D")}') + embed = embed_templates.success( + interaction, text=f'Bursdag satt til {discord.utils.format_dt(date, style="D")}' + ) await interaction.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @app_commands.command(name='fjernbursdag', description='Fjerner bursdagen din fra databasen') + @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 @@ -226,15 +235,17 @@ class Birthday(commands.Cog): interaction (discord.Interaction): Slash command context object """ - self.cursor.execute('DELETE FROM birthdays WHERE discord_id = (%s)', (interaction.user.id,)) + self.cursor.execute("DELETE FROM birthdays WHERE discord_id = (%s)", (interaction.user.id,)) - embed = embed_templates.success(interaction, text='Bursdag fjernet') + embed = embed_templates.success(interaction, text="Bursdag fjernet") await interaction.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @app_commands.command(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): + @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. @@ -251,7 +262,7 @@ class Birthday(commands.Cog): if not user: return await interaction.response.send_message( - embed=embed_templates.error_fatal(interaction, text='Brukeren har ikke registrert bursdagen sin') + embed=embed_templates.error_fatal(interaction, text="Brukeren har ikke registrert bursdagen sin") ) # Current age information @@ -266,16 +277,22 @@ class Birthday(commands.Cog): embed = discord.Embed(description=bruker.mention, color=discord_utils.get_color(bruker)) embed.set_thumbnail(url=bruker.display_avatar) embed.set_author(name=bruker.name, icon_url=bruker.display_avatar) - embed.add_field(name='Bursdag', value=discord.utils.format_dt(birthday, style='D')) - embed.add_field(name='Hvor gammel?', value=f'{years_old} år\n({days_old} dager)', inline=False) - embed.add_field(name='Neste bursdag om', value=f'{next_birthday_days} {"dager" if next_birthday_days != 1 else "dag"}', inline=False) + embed.add_field(name="Bursdag", value=discord.utils.format_dt(birthday, style="D")) + embed.add_field(name="Hvor gammel?", value=f"{years_old} år\n({days_old} dager)", inline=False) + embed.add_field( + name="Neste bursdag om", + value=f'{next_birthday_days} {"dager" if next_birthday_days != 1 else "dag"}', + inline=False, + ) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @app_commands.command(name='kommendebursdager', description='Viser en liste over de opptil 5 kommende bursdager i serveren') + @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. @@ -288,24 +305,32 @@ class Birthday(commands.Cog): next_birthdays = self.__fetch_next_birthdays() if not next_birthdays: - return await interaction.response.send_message(embed=embed_templates.error_fatal(interaction, text='Ingen bursdager')) + return await interaction.response.send_message( + embed=embed_templates.error_fatal(interaction, text="Ingen bursdager") + ) - birthday_string = '' + birthday_string = "" for user in next_birthdays: user_id, _, next_birthday = user try: - discord_user = await interaction.guild.fetch_member(user_id) # Guild should always be available because of guild_only + discord_user = await interaction.guild.fetch_member( + user_id + ) # Guild should always be available because of guild_only except (discord.NotFound, discord.HTTPException): continue - timestamp = discord.utils.format_dt(next_birthday, style='D') - relative_timestamp = discord.utils.format_dt(next_birthday, style='R') - birthday_string += f'{discord_user.name}#{discord_user.discriminator} - {timestamp} ({relative_timestamp})\n' + timestamp = discord.utils.format_dt(next_birthday, style="D") + relative_timestamp = discord.utils.format_dt(next_birthday, style="R") + birthday_string += ( + f"{discord_user.name}#{discord_user.discriminator} - {timestamp} ({relative_timestamp})\n" + ) if not birthday_string: - return await interaction.response.send_message(embed=embed_templates.error_fatal(interaction, text='Ingen bursdager')) + return await interaction.response.send_message( + embed=embed_templates.error_fatal(interaction, text="Ingen bursdager") + ) - embed = discord.Embed(title='Kommende bursdager', description=birthday_string) + embed = discord.Embed(title="Kommende bursdager", description=birthday_string) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) diff --git a/src/cogs/botinfo.py b/src/cogs/botinfo.py index 5e940b5..1c4f8e7 100644 --- a/src/cogs/botinfo.py +++ b/src/cogs/botinfo.py @@ -1,5 +1,6 @@ -from os import environ, getpid import platform +from os import environ +from os import getpid from time import time import discord @@ -24,7 +25,7 @@ class BotInfo(commands.Cog): @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') + @app_commands.command(name="botinfo", description="Se informajson om botten") async def botinfo(self, interaction: discord.Interaction): """ View information about the bot @@ -58,42 +59,46 @@ class BotInfo(commands.Cog): for guild in self.bot.guilds: for member in guild.members: total_members.add(member.id) - if str(member.status) == 'online': + if str(member.status) == "online": online_members.add(member.id) - elif str(member.status) == 'idle': + elif str(member.status) == "idle": idle_members.add(member.id) - elif str(member.status) == 'dnd': + elif str(member.status) == "dnd": dnd_members.add(member.id) - elif str(member.status) == 'offline': + elif str(member.status) == "offline": offline_members.add(member.id) # Build embed - embed = discord.Embed(color=interaction.client.user.color, url=self.bot.misc['website']) + 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'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()) - embed.add_field(name='Ressursbruk', value=f'RAM: {memory_usage} MB') - embed.add_field(name='Kernel', value=f'{platform.system()} {platform.release()}') - if 'docker' in environ: - embed.add_field(name='Docker', value='U+FE0F') - embed.add_field(name=f'Brukere ({len(total_members)})', - value=f'{self.bot.emoji["online"]}{len(online_members)} ' + - f'{self.bot.emoji["idle"]}{len(idle_members)} ' + - f'{self.bot.emoji["dnd"]}{len(dnd_members)} ' + - 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.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"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()) + embed.add_field(name="Ressursbruk", value=f"RAM: {memory_usage} MB") + embed.add_field(name="Kernel", value=f"{platform.system()} {platform.release()}") + if "docker" in environ: + embed.add_field(name="Docker", value="U+FE0F") + embed.add_field( + name=f"Brukere ({len(total_members)})", + value=f'{self.bot.emoji["online"]}{len(online_members)} ' + + f'{self.bot.emoji["idle"]}{len(idle_members)} ' + + f'{self.bot.emoji["dnd"]}{len(dnd_members)} ' + + 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(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='oppetid', description='Se hvor lenge botten har kjørt') + @app_commands.command(name="oppetid", description="Se hvor lenge botten har kjørt") async def uptime(self, interaction: discord.Interaction): """ View the bot's uptime @@ -104,13 +109,13 @@ class BotInfo(commands.Cog): """ embed = discord.Embed(color=interaction.client.user.color) - embed.add_field(name='🔌 Oppetid', value=self.__get_uptime()) + 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') + @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 @@ -121,10 +126,7 @@ class BotInfo(commands.Cog): """ embed = discord.Embed(color=interaction.client.user.color) - embed.add_field( - name='📶 Ping', - value=f'**Websocket ping:** {self.__get_ping()} ms' - ) + 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) @@ -154,7 +156,7 @@ class BotInfo(commands.Cog): hours, remainder = divmod(remainder, 60 * 60) minutes, seconds = divmod(remainder, 60) - return f'{days}d, {hours}t, {minutes}m, {seconds}s' + return f"{days}d, {hours}t, {minutes}m, {seconds}s" async def setup(bot: commands.Bot): diff --git a/src/cogs/deprecated/camera_channel.py b/src/cogs/deprecated/camera_channel.py index 11e9889..ecd3d7c 100644 --- a/src/cogs/deprecated/camera_channel.py +++ b/src/cogs/deprecated/camera_channel.py @@ -1,7 +1,7 @@ -from discord.ext import commands - import asyncio +from discord.ext import commands + class CameraChannel(commands.Cog): def __init__(self, bot: commands.Bot): @@ -21,6 +21,6 @@ class CameraChannel(commands.Cog): async def setup(bot: commands.Bot): - #bot.add_listener(CameraChannel(bot).on_voice_state_update, 'on_voice_state_update') - #await bot.add_cog(CameraChannel(bot)) + # bot.add_listener(CameraChannel(bot).on_voice_state_update, 'on_voice_state_update') + # await bot.add_cog(CameraChannel(bot)) pass diff --git a/src/cogs/deprecated/vær.py b/src/cogs/deprecated/vær.py index b21499a..a9bcc98 100644 --- a/src/cogs/deprecated/vær.py +++ b/src/cogs/deprecated/vær.py @@ -1,26 +1,25 @@ -from discord.ext import commands -import discord - -from yr.libyr import Yr -import aiocron import json +import aiocron +import discord +from discord.ext import commands +from yr.libyr import Yr + class Vær(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot - @aiocron.crontab('0 6 * * *') + @aiocron.crontab("0 6 * * *") async def forecast(): - dev = await self.bot.fetch_user(162337748781367296) guild = self.bot.get_guild(747542543750660178) channel = guild.get_channel(750052141346979850) - weather = Yr(location_name='Norway/Oslo/Oslo/Oslo', forecast_link='forecast_hour_by_hour') + weather = Yr(location_name="Norway/Oslo/Oslo/Oslo", forecast_link="forecast_hour_by_hour") - embed = discord.Embed(title=':white_sun_small_cloud: Værmelding for Oslo :white_sun_small_cloud:') - embed.description = '*Værmeldingen levert til deg av Petter*' + embed = discord.Embed(title=":white_sun_small_cloud: Værmelding for Oslo :white_sun_small_cloud:") + embed.description = "*Værmeldingen levert til deg av Petter*" embed.set_author(name=dev.name, icon_url=dev.display_avatar) half_hour = False @@ -31,15 +30,15 @@ class Vær(commands.Cog): continue data = json.loads(forecast) - temp = data['temperature'] - rain = data['precipitation'] - regn = rain['@value'] - temperatur = temp['@value'] - embed.add_field(name=f'kl {klokkeslett}', value=f'{temperatur}°C - {regn}mm') + temp = data["temperature"] + rain = data["precipitation"] + regn = rain["@value"] + temperatur = temp["@value"] + embed.add_field(name=f"kl {klokkeslett}", value=f"{temperatur}°C - {regn}mm") klokkeslett += 1 half_hour = True - await channel.send('RISE AND SHINE GAMERS!', embed=embed) + await channel.send("RISE AND SHINE GAMERS!", embed=embed) async def setup(bot: commands.Bot): diff --git a/src/cogs/deprecated/wiki_search.py b/src/cogs/deprecated/wiki_search.py index d594782..815a807 100644 --- a/src/cogs/deprecated/wiki_search.py +++ b/src/cogs/deprecated/wiki_search.py @@ -1,12 +1,14 @@ +import discord +import wikipedia from discord.ext import commands -import discord, wikipedia + from cogs.utils import embed_templates + 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 +17,12 @@ 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) + embed_templates.default_footer(ctx, embed) await ctx.send(embed=embed) + async def setup(bot: commands.Bot): - await bot.add_cog(Wiki(bot)) \ No newline at end of file + await bot.add_cog(Wiki(bot)) diff --git a/src/cogs/dev_tools.py b/src/cogs/dev_tools.py index 8e35dd4..3fcddea 100644 --- a/src/cogs/dev_tools.py +++ b/src/cogs/dev_tools.py @@ -1,8 +1,8 @@ import asyncio from os import listdir -import requests import discord +import requests from discord.ext import commands from cogs.utils import embed_templates @@ -22,7 +22,10 @@ class DevTools(commands.Cog): @commands.is_owner() @commands.bot_has_permissions(embed_links=True) - @commands.command(name='custommsg', description='Send en melding til hvilken som helst kanal på hvilken som helst server botten er i') + @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 any channel on any server the bot is in @@ -36,18 +39,18 @@ class DevTools(commands.Cog): # Send message to the requested channel channel = self.bot.get_channel(channel) - custommessage = ' '.join(text) + 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) + embed.add_field(name="Sent", value=custommessage) await ctx.reply(embed=embed) @commands.is_owner() @commands.bot_has_permissions(embed_links=True) @commands.cooldown(1, 10, commands.BucketType.guild) - @commands.command(name='changepresence', description='Endre botten sin nåværende status') + @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): """ Change the bot's presence status @@ -60,32 +63,25 @@ class DevTools(commands.Cog): status_type (str): The type of status to set the bot's status to """ - activities = { - 'playing': 0, - 'listening': 2, - 'watching': 3 - } + activities = {"playing": 0, "listening": 2, "watching": 3} activity_type = activities.get(activity_type, 0) status_types = { - 'online': discord.Status.online, - 'dnd': discord.Status.dnd, - 'idle': discord.Status.idle, - 'offline': discord.Status.offline + "online": discord.Status.online, + "dnd": discord.Status.dnd, + "idle": discord.Status.idle, + "offline": discord.Status.offline, } status_type = status_types.get(status_type, discord.Status.online) - await self.bot.change_presence( - status=status_type, - activity=discord.Activity(type=activity_type, name=message) - ) + 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!') + embed = discord.Embed(color=ctx.me.color, description="Endret Presence!") await ctx.reply(embed=embed) @commands.is_owner() @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') + @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): """ Make bot leave a specified guild. If no guild is specified, leave the guild the command was sent from @@ -103,33 +99,33 @@ class DevTools(commands.Cog): 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') + embed = embed_templates.error_fatal(ctx, text="Bot is not a member of this guild") return await ctx.reply(embed=embed) # Send confirmation message for leaving - confirmation_msg = await ctx.reply(f'Do you want to leave {guild.name} (`{guild.id}`)?') - await confirmation_msg.add_reaction('✅') + confirmation_msg = await ctx.reply(f"Do you want to leave {guild.name} (`{guild.id}`)?") + await confirmation_msg.add_reaction("✅") # Check confirmation def comfirm(reaction: discord.Reaction, user: discord.Member): - return user == ctx.author and str(reaction.emoji) == '✅' + return user == ctx.author and str(reaction.emoji) == "✅" try: - 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() else: await guild.leave() try: - embed = discord.Embed(color=ctx.me.color, description='Guild left!') + embed = discord.Embed(color=ctx.me.color, description="Guild left!") await ctx.reply(embed=embed) except discord.errors.Forbidden: pass @commands.is_owner() @commands.bot_has_permissions(embed_links=True) - @commands.command(name='publicip', description='Hent den offentlige IP-adressen til serveren botten kjører på') + @commands.command(name="publicip", description="Hent den offentlige IP-adressen til serveren botten kjører på") async def publicip(self, ctx: commands.Context): """ Sends WAN IP-address. Inb4 I leak my IP-address @@ -139,18 +135,18 @@ class DevTools(commands.Cog): ctx (commands.Context): Context object """ - data = requests.get('https://wtfismyip.com/json', timeout=10).json() - ip = data['YourFuckingIPAddress'] - location = data['YourFuckingLocation'] - isp = data['YourFuckingISP'] + 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) - embed.add_field(name='WAN IP-address', value=f'{ip}\n{location}\n{isp}') + embed.add_field(name="WAN IP-address", value=f"{ip}\n{location}\n{isp}") await ctx.reply(embed=embed) @commands.is_owner() @commands.bot_has_permissions(embed_links=True) - @commands.group(name='cogs', description='Administrer cogs') + @commands.group(name="cogs", description="Administrer cogs") async def cogs(self, ctx: commands.Context): """ Cog management commands @@ -163,7 +159,7 @@ class DevTools(commands.Cog): if not ctx.invoked_subcommand: await ctx.reply_help(ctx.command) - @cogs.command(name='unload', description='Avslutt en cog') + @cogs.command(name="unload", description="Avslutt en cog") async def cogs_unload(self, ctx: commands.Context, cog: str): """ Disables a specified cog @@ -174,18 +170,18 @@ class DevTools(commands.Cog): cog (str): The name of the cog to disable """ - for file in listdir('./src/cogs'): - if file.endswith('.py'): + 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') + await self.bot.unload_extension(f"cogs.{name}") + embed = discord.Embed(color=ctx.me.color, description=f"{cog} has been disabled") return await ctx.reply(embed=embed) - embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist') + embed = embed_templates.error_fatal(ctx, text=f"{cog} does not exist") await ctx.reply(embed=embed) - @cogs.command(name='load', description='Aktiver en cog') + @cogs.command(name="load", description="Aktiver en cog") async def cogs_load(self, ctx: commands.Context, cog: str): """ Enables a speicifed cog @@ -196,18 +192,18 @@ class DevTools(commands.Cog): cog (str): The name of the cog to enable """ - for file in listdir('./src/cogs'): - if file.endswith('.py'): + 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') + await self.bot.load_extension(f"cogs.{name}") + embed = discord.Embed(color=ctx.me.color, description=f"{cog} loaded") return await ctx.reply(embed=embed) - embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist') + embed = embed_templates.error_fatal(ctx, text=f"{cog} does not exist") await ctx.reply(embed=embed) - @cogs.command(name='reload', description='Last inn en cog på nytt') + @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 @@ -217,18 +213,18 @@ class DevTools(commands.Cog): ctx (commands.Context): Context object cog (str): The name of the cog to reload """ - for file in listdir('./src/cogs'): - if file.endswith('.py'): + 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') + await self.bot.reload_extension(f"cogs.{name}") + embed = discord.Embed(color=ctx.me.color, description=f"{cog} has been reloaded") return await ctx.reply(embed=embed) - embed = embed_templates.error_fatal(ctx, text=f'{cog} does not exist') + embed = embed_templates.error_fatal(ctx, text=f"{cog} does not exist") await ctx.reply(embed=embed) - @cogs.command(name='reloadunloaded', description='Last inn alle cogs på nytt, selv de som ikke er lastet inn') + @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 @@ -239,21 +235,21 @@ class DevTools(commands.Cog): """ # Unload all cogs - for file in listdir('./src/cogs'): - if file.endswith('.py'): + for file in listdir("./src/cogs"): + if file.endswith(".py"): name = file[:-3] - await self.bot.unload_extension(f'cogs.{name}') + await self.bot.unload_extension(f"cogs.{name}") # Load all cogs - for file in listdir('./src/cogs'): - if file.endswith('.py'): + for file in listdir("./src/cogs"): + if file.endswith(".py"): name = file[:-3] - await self.bot.load_extension(f'cogs.{name}') + await self.bot.load_extension(f"cogs.{name}") - embed = discord.Embed(color=ctx.me.color, description='Reloaded all cogs') + embed = discord.Embed(color=ctx.me.color, description="Reloaded all cogs") await ctx.reply(embed=embed) - @cogs.command(name='reloadall', description='Last inn alle cogs på nytt') + @cogs.command(name="reloadall", description="Last inn alle cogs på nytt") async def cogs_reloadall(self, ctx: commands.Context): """ Reloads all previously enabled cogs @@ -263,12 +259,12 @@ class DevTools(commands.Cog): ctx (commands.Context): Context object """ - for file in listdir('./src/cogs'): - if file.endswith('.py'): + for file in listdir("./src/cogs"): + if file.endswith(".py"): name = file[:-3] - await self.bot.reload_extension(f'cogs.{name}') + await self.bot.reload_extension(f"cogs.{name}") - embed = discord.Embed(color=ctx.me.color, description='Reloaded all previously enabled cogs') + embed = discord.Embed(color=ctx.me.color, description="Reloaded all previously enabled cogs") await ctx.reply(embed=embed) diff --git a/src/cogs/errors.py b/src/cogs/errors.py index 08eefc6..2fd430c 100644 --- a/src/cogs/errors.py +++ b/src/cogs/errors.py @@ -32,13 +32,15 @@ class Errors(commands.Cog): """ 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}' + 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_app_command_completion(self, interaction: discord.Interaction, command: app_commands.Command | app_commands.ContextMenu): + async def on_app_command_completion( + self, interaction: discord.Interaction, command: app_commands.Command | app_commands.ContextMenu + ): """ Logs slash command execution metadata @@ -49,9 +51,9 @@ class Errors(commands.Cog): """ 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}' + 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() @@ -67,54 +69,47 @@ class Errors(commands.Cog): # Reset cooldown if command throws AttributeError with ignore_exception(AttributeError): - self.bot.get_command(f'{ctx.command}').reset_cooldown(ctx) + self.bot.get_command(f"{ctx.command}").reset_cooldown(ctx) # Ignore command's own error handling - if hasattr(ctx.command, 'on_error'): + if hasattr(ctx.command, "on_error"): return # Ignored errors ignored = commands.CommandNotFound - error = getattr(error, 'original', error) + error = getattr(error, "original", error) if isinstance(error, ignored): return - send_help = ( - commands.MissingRequiredArgument, - commands.TooManyArguments, - commands.BadArgument - ) + send_help = (commands.MissingRequiredArgument, commands.TooManyArguments, commands.BadArgument) if isinstance(error, send_help): - self.bot.get_command(f'{ctx.command}').reset_cooldown(ctx) + self.bot.get_command(f"{ctx.command}").reset_cooldown(ctx) return await ctx.send_help(ctx.command) elif isinstance(error, commands.BotMissingPermissions): - permissions = ', '.join(error.missing_perms) - text = 'Jeg mangler følgende tillatelser:\n\n' + \ - f'```\n{permissions}\n```' + permissions = ", ".join(error.missing_perms) + text = "Jeg mangler følgende tillatelser:\n\n" + f"```\n{permissions}\n```" return await ctx.reply(text) elif isinstance(error, commands.MissingPermissions): - permissions = ', '.join(error.missing_perms) - text = 'Du mangler følgende tillatelser\n\n' + \ - f'```\n{permissions}\n```' + permissions = ", ".join(error.missing_perms) + text = "Du mangler følgende tillatelser\n\n" + f"```\n{permissions}\n```" return await ctx.reply(text) elif isinstance(error, commands.NotOwner): - text = 'Bare boteieren kan gjøre dette' + text = "Bare boteieren kan gjøre dette" return await ctx.reply(text) elif isinstance(error, commands.CommandOnCooldown): - text = 'Kommandoen har nettopp blitt brukt\n' + \ - f'Prøv igjen om `{error.retry_after:.1f}` sekunder.' + text = "Kommandoen har nettopp blitt brukt\n" + f"Prøv igjen om `{error.retry_after:.1f}` sekunder." return await ctx.reply(text) elif isinstance(error, commands.NoPrivateMessage): try: - text = 'Denne kommandoen kan bare utføres i servere' + text = "Denne kommandoen kan bare utføres i servere" return await ctx.reply(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 @@ -122,11 +117,11 @@ class Errors(commands.Cog): elif isinstance(error, commands.CheckFailure): return - embed = embed_templates.error_fatal(ctx, text='En ukjent feil oppstod!') + embed = embed_templates.error_fatal(ctx, text="En ukjent feil oppstod!") await ctx.reply(embed=embed) # Log full exception to file - self.bot.logger.error(''.join(traceback.format_exception(type(error), error, error.__traceback__))) + 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): """ @@ -144,15 +139,17 @@ class Errors(commands.Cog): await self.on_app_command_completion(interaction, interaction.command) if isinstance(error, app_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```') + 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, app_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```') + 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) # TODO: figure this shit out. app_commands does not support this check @@ -161,15 +158,17 @@ class Errors(commands.Cog): # return await interaction.response.send_message(embed=embed) elif isinstance(error, app_commands.CommandOnCooldown): - embed = embed_templates.error_warning(interaction, text='Kommandoen har nettopp blitt brukt\n' + - f'Prøv igjen om `{error.retry_after:.1f}` sekunder.') + embed = embed_templates.error_warning( + interaction, + text="Kommandoen har nettopp blitt brukt\n" + 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!') + 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__))) + self.bot.logger.error("".join(traceback.format_exception(type(error), error, error.__traceback__))) async def setup(bot: commands.Bot): diff --git a/src/cogs/fun.py b/src/cogs/fun.py index 0370840..6472526 100644 --- a/src/cogs/fun.py +++ b/src/cogs/fun.py @@ -5,7 +5,7 @@ class Fun(commands.Cog): """Simple commands that return short strings for the memes""" @commands.cooldown(1, 2, commands.BucketType.guild) - @commands.command(name='norskeuniversiteter') + @commands.command(name="norskeuniversiteter") async def norskeuniversiteter(self, ctx: commands.Context): """ Sends a link to university meme image album @@ -15,10 +15,10 @@ class Fun(commands.Cog): ctx (commands.Context): Context object """ - await ctx.reply('') + await ctx.reply("") @commands.cooldown(1, 2, commands.BucketType.guild) - @commands.command(name='ifi') + @commands.command(name="ifi") async def ifi(self, ctx: commands.Context): """ ifi meme 1 @@ -28,10 +28,10 @@ class Fun(commands.Cog): ctx (commands.Context): Context object """ - await ctx.reply('https://i.imgur.com/ypyK1mi.jpg') + await ctx.reply("https://i.imgur.com/ypyK1mi.jpg") @commands.cooldown(1, 2, commands.BucketType.guild) - @commands.command(name='ifi2') + @commands.command(name="ifi2") async def ifi2(self, ctx: commands.Context): """ ifi meme 2 @@ -41,7 +41,7 @@ class Fun(commands.Cog): ctx (commands.Context): Context object """ - await ctx.reply('https://i.imgur.com/ZqgZEEA.jpg') + await ctx.reply("https://i.imgur.com/ZqgZEEA.jpg") @commands.cooldown(1, 2, commands.BucketType.guild) @commands.command() @@ -54,7 +54,7 @@ class Fun(commands.Cog): ctx (commands.Context): Context object """ - await ctx.reply('https://i.imgur.com/Gx9DQE5.jpg') + await ctx.reply("https://i.imgur.com/Gx9DQE5.jpg") @commands.cooldown(1, 2, commands.BucketType.guild) @commands.command() @@ -67,7 +67,7 @@ class Fun(commands.Cog): ctx (commands.Context): Context object """ - await ctx.reply('https://i.imgur.com/188MoIV.jpg') + await ctx.reply("https://i.imgur.com/188MoIV.jpg") @commands.cooldown(1, 2, commands.BucketType.guild) @commands.command() @@ -80,7 +80,7 @@ class Fun(commands.Cog): ctx (commands.Context): Context object """ - await ctx.reply('https://twitter.com/NTNU/status/970667413564993536') + await ctx.reply("https://twitter.com/NTNU/status/970667413564993536") @commands.cooldown(1, 2, commands.BucketType.guild) @commands.command() @@ -93,7 +93,7 @@ class Fun(commands.Cog): ctx (commands.Context): Context object """ - await ctx.reply('https://i.imgur.com/h84fknj.jpg') + await ctx.reply("https://i.imgur.com/h84fknj.jpg") @commands.cooldown(1, 2, commands.BucketType.guild) @commands.command() @@ -106,7 +106,7 @@ class Fun(commands.Cog): ctx (commands.Context): Context object """ - await ctx.reply('https://twitter.com/erna_solberg/status/1075333228779765760') + await ctx.reply("https://twitter.com/erna_solberg/status/1075333228779765760") async def setup(bot: commands.Bot): diff --git a/src/cogs/funreplies.py b/src/cogs/funreplies.py index e78d3e2..8392fdc 100644 --- a/src/cogs/funreplies.py +++ b/src/cogs/funreplies.py @@ -22,13 +22,15 @@ class FunReplies(commands.Cog): # # 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 + 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 + "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): @@ -45,38 +47,47 @@ class FunReplies(commands.Cog): message_content = message.content.lower() - 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.reply('<@267415183931080715> DE SNAKKER OM BORGERLØNN') - self.previous_invokations['borgerlønn'] = datetime.now() + 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.reply("<@267415183931080715> DE SNAKKER OM BORGERLØNN") + self.previous_invokations["borgerlønn"] = datetime.now() - 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.reply('Jeg vet hvem som drepte Olof Palme 👀') - self.previous_invokations['olof palme'] = datetime.now() + 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.reply("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.reply('https://cdn.discordapp.com/attachments/750052141346979850/' + - '824764933513281596/3xhpwbakz2361.png') - self.previous_invokations['lesgo'] = 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.reply( + "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: + 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.reply(f'Ja, {to_be_pinged} bor der') + await message.reply(f"Ja, {to_be_pinged} bor der") - self.previous_invokations['neuf'] = datetime.now() + 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.reply('<:Nei:826593267642662912>') - self.previous_invokations['yeet'] = 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.reply("<:Nei:826593267642662912>") + self.previous_invokations["yeet"] = datetime.now() - elif re.search(r'https?://(www\.)?instagram\.com/reel/.*', message_content, flags=re.IGNORECASE) and message.author.id == 205741213050077185: - await message.reply('||Bruk yt-dlp REEEE||\nhttps://media.tenor.com/Fm0bJgHucO8AAAAd/epic-embed-fail.gif') + elif ( + re.search(r"https?://(www\.)?instagram\.com/reel/.*", message_content, flags=re.IGNORECASE) + and message.author.id == 205741213050077185 + ): + await message.reply("||Bruk yt-dlp REEEE||\nhttps://media.tenor.com/Fm0bJgHucO8AAAAd/epic-embed-fail.gif") async def setup(bot: commands.Bot): @@ -88,5 +99,5 @@ async def setup(bot: commands.Bot): bot (commands.Bot): Bot instance """ - bot.add_listener(FunReplies(bot).reply_to_triggers, 'on_message') + bot.add_listener(FunReplies(bot).reply_to_triggers, "on_message") await bot.add_cog(FunReplies(bot)) diff --git a/src/cogs/gullkorn.py b/src/cogs/gullkorn.py index 96abb8b..ec59e48 100644 --- a/src/cogs/gullkorn.py +++ b/src/cogs/gullkorn.py @@ -2,7 +2,8 @@ import discord from discord import app_commands from discord.ext import commands -from cogs.utils import discord_utils, embed_templates +from cogs.utils import discord_utils +from cogs.utils import embed_templates class Gullkorn(commands.Cog): @@ -61,10 +62,10 @@ class Gullkorn(commands.Cog): str: The input data formatted into a prettified string """ - formatted_string = '' + formatted_string = "" for i, row in enumerate(data): user = self.bot.get_user(row[0]) - formatted_string += f'**#{i+1}** {user.name}#{user.discriminator} - *{row[1]}*\n' + formatted_string += f"**#{i+1}** {user.name}#{user.discriminator} - *{row[1]}*\n" return formatted_string @@ -87,7 +88,8 @@ class Gullkorn(commands.Cog): VALUES (%s, 1, 0) ON CONFLICT (discord_id) DO UPDATE SET times_cited = gullkorn.times_cited + 1; - """, (user.id,) + """, + (user.id,), ) self.cursor.execute( @@ -96,14 +98,17 @@ class Gullkorn(commands.Cog): VALUES (%s, 0, 1) ON CONFLICT (discord_id) DO UPDATE SET citations_posted = gullkorn.citations_posted + 1; - """, (message.author.id,) + """, + (message.author.id,), ) - gullkorn_group = app_commands.Group(name='gullkorn', description='Se statistikk for gullkorn') + gullkorn_group = app_commands.Group(name="gullkorn", description="Se statistikk for gullkorn") @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @gullkorn_group.command(name='statistikk', description='Se informasjon om gullkorn for en bruker eller hele serveren') + @gullkorn_group.command( + name="statistikk", description="Se informasjon om gullkorn for en bruker eller hele serveren" + ) async def gullkorn_stats(self, interaction: discord.Interaction, bruker: discord.Member | None = None): """ Fetches gullkorn stats for a user or the whole server @@ -118,26 +123,27 @@ class Gullkorn(commands.Cog): result = self.cursor.execute( """ SELECT * - FROM gullkorn + FROM gullkorn WHERE discord_id = %s; - """, (bruker.id,) + """, + (bruker.id,), ) result = self.cursor.fetchone() if not result: return await interaction.response.send_message( - embed=embed_templates.error_fatal(interaction, text='Ingen data om denne brukeren funnet'), - ephemeral=False + embed=embed_templates.error_fatal(interaction, text="Ingen data om denne brukeren funnet"), + ephemeral=False, ) embed = discord.Embed( - title=f'Gullkornstatistikk for {bruker.name}#{bruker.discriminator}', - color=discord_utils.get_color(bruker) + title=f"Gullkornstatistikk for {bruker.name}#{bruker.discriminator}", + color=discord_utils.get_color(bruker), ) embed.set_thumbnail(url=bruker.avatar) - embed.add_field(name='Antall gullkorn', value=result[1]) - embed.add_field(name='Antall gullkorn postet', value=result[2]) + embed.add_field(name="Antall gullkorn", value=result[1]) + embed.add_field(name="Antall gullkorn postet", value=result[2]) return await interaction.response.send_message(embed=embed, ephemeral=False) summary = self.cursor.execute( @@ -168,12 +174,12 @@ class Gullkorn(commands.Cog): most_cited_string = self.__construct_data_string(most_cited) citations_posted_string = self.__construct_data_string(citations_posted) - - embed = discord.Embed(title='Gullkornstatistikk for serveren') - embed.description = f'Antall gullkorn siden [denne meldingen](https://canary.discord.com/channels/747542543750660178/865970753748074576/1034587913285025912): *{summary[0]}*' - embed.add_field(name='Mest sitert', value=most_cited_string, inline=False) - embed.add_field(name='Postet mest', value=citations_posted_string, inline=False) - await interaction.response.send_message(embed=embed, ephemeral=False) + + embed = discord.Embed(title="Gullkornstatistikk for serveren") + embed.description = f"Antall gullkorn siden [denne meldingen](https://canary.discord.com/channels/747542543750660178/865970753748074576/1034587913285025912): *{summary[0]}*" + embed.add_field(name="Mest sitert", value=most_cited_string, inline=False) + embed.add_field(name="Postet mest", value=citations_posted_string, inline=False) + await interaction.response.send_message(embed=embed, ephemeral=False) async def setup(bot: commands.Bot): @@ -185,5 +191,5 @@ async def setup(bot: commands.Bot): bot (commands.Bot): Bot instance """ - bot.add_listener(Gullkorn(bot).gullkorn_listener, 'on_message') + bot.add_listener(Gullkorn(bot).gullkorn_listener, "on_message") await bot.add_cog(Gullkorn(bot)) diff --git a/src/cogs/info.py b/src/cogs/info.py index d83c460..a367205 100644 --- a/src/cogs/info.py +++ b/src/cogs/info.py @@ -4,7 +4,9 @@ import discord from discord import app_commands from discord.ext import commands -from cogs.utils import discord_utils, embed_templates, misc_utils +from cogs.utils import discord_utils +from cogs.utils import embed_templates +from cogs.utils import misc_utils class Info(commands.Cog): @@ -19,8 +21,8 @@ class Info(commands.Cog): self.bot = bot - guild_group = app_commands.Group(name='guild', description='Se ting om serveren') - user_group = app_commands.Group(name='bruker', description='Se ting om brukeren') + guild_group = app_commands.Group(name="guild", description="Se ting om serveren") + user_group = app_commands.Group(name="bruker", description="Se ting om brukeren") def __construct_role_string(self, roles: list[discord.Role]) -> str: """ @@ -36,14 +38,14 @@ class Info(commands.Cog): """ if not roles: - return '**Ingen roller**' + return "**Ingen roller**" - roles = [role.name for role in roles if role.name != '@everyone'] + roles = [role.name for role in roles if role.name != "@everyone"] roles.reverse() - return ', '.join(roles) + return ", ".join(roles) - def __construct_booster_string(self, interaction: discord.Interaction, join_method: callable = ', '.join) -> str: + def __construct_booster_string(self, interaction: discord.Interaction, join_method: callable = ", ".join) -> str: """ Joins all boosters into a string @@ -58,12 +60,16 @@ class Info(commands.Cog): """ if not interaction.guild.premium_subscribers: - return '**Ingen boostere**' + return "**Ingen boostere**" # Sort boosters by boost date and put name#discrim as well as date of boost into a list of stirngs # Use map instead of list comprehension because I can divide the code into 2 lines - boosters = list(map(lambda booster: f'{booster.name}#{booster.discriminator} - {discord.utils.format_dt(booster.premium_since)}', - sorted(interaction.guild.premium_subscribers, key=lambda m: m.premium_since))) + boosters = list( + map( + lambda booster: f"{booster.name}#{booster.discriminator} - {discord.utils.format_dt(booster.premium_since)}", + sorted(interaction.guild.premium_subscribers, key=lambda m: m.premium_since), + ) + ) return join_method(boosters) @@ -81,11 +87,11 @@ class Info(commands.Cog): """ if not members: - return '**Ingen**' + return "**Ingen**" - members = [f'{member.name}#{member.discriminator}' for member in members] + members = [f"{member.name}#{member.discriminator}" for member in members] - return ', '.join(members) + return ", ".join(members) async def __send_as_txt_file(self, interaction: discord.Interaction, content: str, file_path: str): """ @@ -99,7 +105,7 @@ class Info(commands.Cog): """ # Create file - with open(file_path, 'w', encoding='utf-8') as file: + with open(file_path, "w", encoding="utf-8") as file: file.write(content) # Send file @@ -113,7 +119,7 @@ class Info(commands.Cog): @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True, external_emojis=True) @app_commands.checks.cooldown(1, 2) - @guild_group.command(name='info', description='Hent informasjon om en server') + @guild_group.command(name="info", description="Hent informasjon om en server") async def guild_info(self, interaction: discord.Interaction): """ Sends general information about the guild @@ -124,9 +130,9 @@ class Info(commands.Cog): """ # Days since guild was created - creation_date_timestamp = discord.utils.format_dt(interaction.guild.created_at, style='F') + creation_date_timestamp = discord.utils.format_dt(interaction.guild.created_at, style="F") since_created_days = (interaction.created_at - interaction.guild.created_at).days - days_ago = f'{since_created_days} dager' if since_created_days != 1 else f'{since_created_days} dag' + days_ago = f"{since_created_days} dager" if since_created_days != 1 else f"{since_created_days} dag" # Member count and status counts total_members = interaction.guild.member_count @@ -138,22 +144,30 @@ class Info(commands.Cog): for member in interaction.guild.members: if member.bot: bot_members += 1 - if str(member.status) == 'online': + if str(member.status) == "online": online_members += 1 - elif str(member.status) == 'idle': + elif str(member.status) == "idle": idle_members += 1 - elif str(member.status) == 'dnd': + elif str(member.status) == "dnd": dnd_members += 1 - elif str(member.status) == 'offline': + elif str(member.status) == "offline": offline_members += 1 # Roles roles = self.__construct_role_string(interaction.guild.roles) - roles = roles if len(roles) < 1024 else f'Bruk `/{self.bot.tree.get_command("guild").get_command("roller").qualified_name}` for å se rollene' + roles = ( + roles + if len(roles) < 1024 + else f'Bruk `/{self.bot.tree.get_command("guild").get_command("roller").qualified_name}` for å se rollene' + ) # Boosts - boosters = self.__construct_booster_string(interaction, join_method='\n'.join) - boosters = boosters if len(boosters) < 1024 else f'Bruk `/{self.bot.tree.get_command("guild").get_command("boosters").qualified_name}` for å se boostere' + boosters = self.__construct_booster_string(interaction, join_method="\n".join) + boosters = ( + boosters + if len(boosters) < 1024 + else f'Bruk `/{self.bot.tree.get_command("guild").get_command("boosters").qualified_name}` for å se boostere' + ) # Channels counts text_channels = len(interaction.guild.text_channels) @@ -162,96 +176,102 @@ class Info(commands.Cog): total_channels = text_channels + voice_channels # Features - features_string = '' + features_string = "" if interaction.guild.features is not []: features = { - 'ANIMATED_BANNER': 'Animer serverbanner', - 'ANIMATED_ICON': 'Animert serverikon', - 'BANNER': 'Serverbanner', - 'COMMERCE': 'E-handel', - 'COMMUNITY': 'Samfunnsserver', - 'DISCOVERABLE': 'På utforsksiden', - 'FEATURABLE': '', - 'INVITE_SPLASH': 'Invitasjonsbilde', - 'MEMBER_VERIFICATION_GATE_ENABLED': 'Medlemsverifisering', - 'MONETIZATION_ENABLED': 'Betalingskanal', - 'MORE_EMOJI': 'Flere emoji', - 'MORE_STICKERS': 'Flere stickers', - 'NEWS': 'Nyhetskanaler', - 'PARTNERED': 'Partner', - 'PREVIEW_ENABLED': 'Forhåndsvisning', - 'PRIVATE_THREADS': 'Private tråder', - 'ROLE_ICONS': 'Rolleikon', - 'TICKETED_EVENTS_ENABLED': 'Arrangmenter med billettsalg', - 'VANITY_URL': 'Egendefinert URL', - 'VERIFIED': 'Verifisert', - 'VIP_REGIONS': 'Høyere bitrate i stemmekanaler', - 'WELCOME_SCREEN_ENABLED': 'Velkomstskjerm', - 'INVITES_DISABLED': 'Invitasjoner deaktivert' + "ANIMATED_BANNER": "Animer serverbanner", + "ANIMATED_ICON": "Animert serverikon", + "BANNER": "Serverbanner", + "COMMERCE": "E-handel", + "COMMUNITY": "Samfunnsserver", + "DISCOVERABLE": "På utforsksiden", + "FEATURABLE": "", + "INVITE_SPLASH": "Invitasjonsbilde", + "MEMBER_VERIFICATION_GATE_ENABLED": "Medlemsverifisering", + "MONETIZATION_ENABLED": "Betalingskanal", + "MORE_EMOJI": "Flere emoji", + "MORE_STICKERS": "Flere stickers", + "NEWS": "Nyhetskanaler", + "PARTNERED": "Partner", + "PREVIEW_ENABLED": "Forhåndsvisning", + "PRIVATE_THREADS": "Private tråder", + "ROLE_ICONS": "Rolleikon", + "TICKETED_EVENTS_ENABLED": "Arrangmenter med billettsalg", + "VANITY_URL": "Egendefinert URL", + "VERIFIED": "Verifisert", + "VIP_REGIONS": "Høyere bitrate i stemmekanaler", + "WELCOME_SCREEN_ENABLED": "Velkomstskjerm", + "INVITES_DISABLED": "Invitasjoner deaktivert", } for feature in interaction.guild.features: if translation := features.get(feature): - features_string += f'{translation}\n' + features_string += f"{translation}\n" photos = {} if interaction.guild.splash: - photos['Invitasjonsbilde'] = interaction.guild.splash + photos["Invitasjonsbilde"] = interaction.guild.splash if interaction.guild.banner: - photos['Banner'] = interaction.guild.banner + photos["Banner"] = interaction.guild.banner verification_level = { - 'none': 'ingen', - 'low': 'e-post', - 'medium': 'e-post, registrert i 5 min', - 'high': 'e-post, registrert i 5 min, medlem i 10 min', - 'extreme': 'telefon' + "none": "ingen", + "low": "e-post", + "medium": "e-post, registrert i 5 min", + "high": "e-post, registrert i 5 min, medlem i 10 min", + "extreme": "telefon", } verification = verification_level[str(interaction.guild.verification_level)] - content_filter = { - 'disabled': 'nei', - 'no_role': 'for alle uten rolle', - 'all_members': 'ja' - } + content_filter = {"disabled": "nei", "no_role": "for alle uten rolle", "all_members": "ja"} content = content_filter[str(interaction.guild.explicit_content_filter)] - embed = discord.Embed(color=interaction.guild.me.color, description=f'**Verifiseringskrav:** {verification}\n' + - f'**Innholdsfilter:** {content}\n' + - f'**Boost Tier:** {interaction.guild.premium_tier}\n' + - f'**Emoji:** {len(interaction.guild.emojis)}') + embed = discord.Embed( + color=interaction.guild.me.color, + description=f"**Verifiseringskrav:** {verification}\n" + + f"**Innholdsfilter:** {content}\n" + + f"**Boost Tier:** {interaction.guild.premium_tier}\n" + + f"**Emoji:** {len(interaction.guild.emojis)}", + ) embed.set_author(name=interaction.guild.name, icon_url=interaction.guild.icon) embed.set_thumbnail(url=interaction.guild.icon) - embed.add_field(name='ID', value=interaction.guild.id) - embed.add_field(name='Eier', value=interaction.guild.owner.mention) - embed.add_field(name='Opprettet', value=f'{creation_date_timestamp}\n{days_ago} siden') - embed.add_field(name=f'Kanaler ({total_channels})', value=f'💬 Tekst: **{text_channels}**\n' + - f'🔊 Tale: **{voice_channels}**\n' + - f'🗃️ Kategorier: **{categories}**') - embed.add_field(name=f'Medlemmer ({total_members})', - value=f'👤 Mennesker: **{int(total_members) - int(bot_members)}**\n' + - f'🤖 Båtter: **{bot_members}**\n' + - f'{self.bot.emoji["online"]}{online_members} ' + - f'{self.bot.emoji["idle"]}{idle_members} ' + - f'{self.bot.emoji["dnd"]}{dnd_members} ' + - f'{self.bot.emoji["offline"]}{offline_members}') - embed.add_field(name=f'Roller ({len(interaction.guild.roles) - 1})', value=roles, inline=False) + embed.add_field(name="ID", value=interaction.guild.id) + embed.add_field(name="Eier", value=interaction.guild.owner.mention) + embed.add_field(name="Opprettet", value=f"{creation_date_timestamp}\n{days_ago} siden") + embed.add_field( + name=f"Kanaler ({total_channels})", + value=f"💬 Tekst: **{text_channels}**\n" + + f"🔊 Tale: **{voice_channels}**\n" + + f"🗃️ Kategorier: **{categories}**", + ) + embed.add_field( + name=f"Medlemmer ({total_members})", + value=f"👤 Mennesker: **{int(total_members) - int(bot_members)}**\n" + + f"🤖 Båtter: **{bot_members}**\n" + + f'{self.bot.emoji["online"]}{online_members} ' + + f'{self.bot.emoji["idle"]}{idle_members} ' + + f'{self.bot.emoji["dnd"]}{dnd_members} ' + + f'{self.bot.emoji["offline"]}{offline_members}', + ) + embed.add_field(name=f"Roller ({len(interaction.guild.roles) - 1})", value=roles, inline=False) if interaction.guild.premium_tier != 0: - embed.add_field(name=f'Boosts ({interaction.guild.premium_subscription_count})', value=boosters, inline=False) + embed.add_field( + name=f"Boosts ({interaction.guild.premium_subscription_count})", value=boosters, inline=False + ) if features_string: - embed.add_field(name='Tillegsfunksjoner', value=features_string) + embed.add_field(name="Tillegsfunksjoner", value=features_string) if photos: - photos_string = '' + photos_string = "" for key, value in photos.items(): - photos_string += f'[{key}]({value})\n' - embed.add_field(name='Bilder', value=photos_string) + photos_string += f"[{key}]({value})\n" + embed.add_field(name="Bilder", value=photos_string) await interaction.response.send_message(embed=embed) @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @guild_group.command(name='roller', description='Se rollene på serveren') + @guild_group.command(name="roller", description="Se rollene på serveren") async def guild_roles(self, interaction: discord.Interaction): """ List all roles in the guild @@ -265,17 +285,17 @@ class Info(commands.Cog): # IF roles list is longer than 2048, create text file and send it if len(roles) > 2048: - self.__send_as_txt_file(interaction, f'./assets/temp/{interaction.guild.id}_roles.txt', roles) + self.__send_as_txt_file(interaction, f"./assets/temp/{interaction.guild.id}_roles.txt", roles) else: embed = discord.Embed(color=interaction.guild.me.color, description=roles) - embed.set_author(name=f'Roller ({len(interaction.guild.roles)})', icon_url=interaction.guild.icon) + embed.set_author(name=f"Roller ({len(interaction.guild.roles)})", icon_url=interaction.guild.icon) embed.set_footer(text=interaction.guild.name, icon_url=interaction.guild.icon) await interaction.response.send_message(embed=embed) @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @guild_group.command(name='boosters', description='Se boostere på serveren') + @guild_group.command(name="boosters", description="Se boostere på serveren") async def guild_boosters(self, interaction: discord.Interaction): """ List all boosters in the guild @@ -286,20 +306,22 @@ class Info(commands.Cog): """ if len(interaction.guild.premium_subscribers) == 0: - embed = embed_templates.error_warning(interaction, text='Serveren har ikke noen boosts :(') + embed = embed_templates.error_warning(interaction, text="Serveren har ikke noen boosts :(") return await interaction.response.send_message(embed=embed) - boosters = self.__construct_booster_string(interaction, '\n'.join) + boosters = self.__construct_booster_string(interaction, "\n".join) embed = discord.Embed(color=interaction.guild.me.color, description=boosters) - embed.set_author(name=f'Boosts ({interaction.guild.premium_subscription_count})', icon_url=interaction.guild.icon) + embed.set_author( + name=f"Boosts ({interaction.guild.premium_subscription_count})", icon_url=interaction.guild.icon + ) embed.set_footer(text=interaction.guild.name, icon_url=interaction.guild.icon) await interaction.response.send_message(embed=embed) @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @guild_group.command(name='ikon', description='Hent serverens ikon') + @guild_group.command(name="ikon", description="Hent serverens ikon") async def guild_icon(self, interaction: discord.Interaction): """ Get the guild icon @@ -309,7 +331,7 @@ class Info(commands.Cog): interaction (discord.Interaction): Slash command context object """ - embed = discord.Embed(color=interaction.guild.me.color, description=f'[Lenke]({interaction.guild.icon})') + embed = discord.Embed(color=interaction.guild.me.color, description=f"[Lenke]({interaction.guild.icon})") embed.set_author(name=interaction.guild.name, icon_url=interaction.guild.icon) embed.set_image(url=interaction.guild.icon) embed_templates.default_footer(interaction, embed) @@ -318,7 +340,7 @@ class Info(commands.Cog): @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @guild_group.command(name='splash', description='Hent serverens splash (bakgrunnsbilde på invitasjonsside)') + @guild_group.command(name="splash", description="Hent serverens splash (bakgrunnsbilde på invitasjonsside)") async def guild_splash(self, interaction: discord.Interaction): """ Get the guild splash @@ -329,10 +351,10 @@ class Info(commands.Cog): """ if not interaction.guild.splash: - embed = embed_templates.error_warning(interaction, text='Serveren har ikke en splash') + embed = embed_templates.error_warning(interaction, text="Serveren har ikke en splash") return await interaction.response.send_message(embed=embed) - embed = discord.Embed(color=interaction.guild.me.color, description=f'[Lenke]({interaction.guild.splash})') + embed = discord.Embed(color=interaction.guild.me.color, description=f"[Lenke]({interaction.guild.splash})") embed.set_author(name=interaction.guild.name, icon_url=interaction.guild.icon) embed.set_image(url=interaction.guild.splash) embed_templates.default_footer(interaction, embed) @@ -341,7 +363,7 @@ class Info(commands.Cog): @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @guild_group.command(name='banner', description='Hen serverens banner') + @guild_group.command(name="banner", description="Hen serverens banner") async def guild_banner(self, interaction: discord.Interaction): """ Get the guild banner @@ -352,10 +374,10 @@ class Info(commands.Cog): """ if not interaction.guild.banner: - embed = embed_templates.error_warning(interaction, text='Serveren har ikke et banner :(') + embed = embed_templates.error_warning(interaction, text="Serveren har ikke et banner :(") return await interaction.response.send_message(embed=embed) - embed = discord.Embed(color=interaction.guild.me.color, description=f'[Lenke]({interaction.guild.banner})') + embed = discord.Embed(color=interaction.guild.me.color, description=f"[Lenke]({interaction.guild.banner})") embed.set_author(name=interaction.guild.name, icon_url=interaction.guild.icon) embed.set_image(url=interaction.guild.banner) embed_templates.default_footer(interaction, embed) @@ -364,7 +386,7 @@ class Info(commands.Cog): @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @guild_group.command(name='rolle', description='Hent informasjon om en rolle på serveren') + @guild_group.command(name="rolle", description="Hent informasjon om en rolle på serveren") async def guild_role(self, interaction: discord.Interaction, rolle: discord.Role): """ Get information about a role @@ -375,39 +397,44 @@ class Info(commands.Cog): rolle (discord.Role): Role to fetch information about """ - if rolle.name == '@everyone': - embed = embed_templates.error_fatal(interaction, text='Skriv inn en annen rolle enn @everyone') + if rolle.name == "@everyone": + embed = embed_templates.error_fatal(interaction, text="Skriv inn en annen rolle enn @everyone") return await interaction.response.send_message(embed=embed) # Timestamp and days since creation - created_at_timestamp = discord.utils.format_dt(rolle.created_at, style='F') + created_at_timestamp = discord.utils.format_dt(rolle.created_at, style="F") since_created_days = (interaction.created_at - rolle.created_at).days # List of members with the role members = self.__construct_member_string(rolle.members) - members = members if len(members) < 1024 else 'For mange medlemmer for å vise her' + members = members if len(members) < 1024 else "For mange medlemmer for å vise her" # List of permissions - permissions = ', '.join([permission for permission, value in iter(rolle.permissions) if value is True]) + permissions = ", ".join([permission for permission, value in iter(rolle.permissions) if value is True]) - embed = discord.Embed(title=rolle.name, description=f'{rolle.mention}\n**ID:** {rolle.id}', color=discord_utils.get_color(rolle)) + embed = discord.Embed( + title=rolle.name, description=f"{rolle.mention}\n**ID:** {rolle.id}", color=discord_utils.get_color(rolle) + ) embed.set_author(name=rolle.guild.name, icon_url=rolle.guild.icon) - embed.add_field(name='Fargekode', value=str(rolle.color)) - embed.add_field(name='Opprettet', value=f'{created_at_timestamp}\n{since_created_days} ' + - f'{"dager" if since_created_days > 1 else "dag"} siden') - embed.add_field(name='Posisjon', value=rolle.position) - embed.add_field(name='Nevnbar', value='Ja' if rolle.mentionable else 'Nei') - embed.add_field(name='Vises separat i medlemsliste', value='Ja' if rolle.hoist else 'Nei') + embed.add_field(name="Fargekode", value=str(rolle.color)) + embed.add_field( + name="Opprettet", + value=f"{created_at_timestamp}\n{since_created_days} " + + f'{"dager" if since_created_days > 1 else "dag"} siden', + ) + embed.add_field(name="Posisjon", value=rolle.position) + embed.add_field(name="Nevnbar", value="Ja" if rolle.mentionable else "Nei") + embed.add_field(name="Vises separat i medlemsliste", value="Ja" if rolle.hoist else "Nei") if permissions: - embed.add_field(name='Tillatelser', value=permissions, inline=False) - embed.add_field(name=f'Brukere med rollen ({len(rolle.members)})', value=members, inline=False) + embed.add_field(name="Tillatelser", value=permissions, inline=False) + embed.add_field(name=f"Brukere med rollen ({len(rolle.members)})", value=members, inline=False) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @guild_group.command(name='tekstkanal', description='Hent informasjon om en tekstkanal') + @guild_group.command(name="tekstkanal", description="Hent informasjon om en tekstkanal") async def guild_text_channel(self, interaction: discord.Interaction, kanal: discord.TextChannel): """ Get information about a text channel @@ -420,24 +447,28 @@ class Info(commands.Cog): members = self.__construct_member_string(kanal.members) if len(members) > 1024: - members = 'For mange for å vise her' + members = "For mange for å vise her" - embed = discord.Embed(color=interaction.guild.me.color, title=kanal.name, description=f'{kanal.mention}\nID: {kanal.id}') + embed = discord.Embed( + color=interaction.guild.me.color, title=kanal.name, description=f"{kanal.mention}\nID: {kanal.id}" + ) embed.set_author(name=kanal.guild.name, icon_url=kanal.guild.icon) - embed.add_field(name='Beskrivelse', value=kanal.topic if kanal.topic else '**Ingen**', inline=False) - embed.add_field(name='Opprettet', value=discord.utils.format_dt(kanal.created_at, style='F')) - embed.add_field(name='NSFW', value='Ja' if kanal.is_nsfw() else 'Nei') - embed.add_field(name='Saktemodus', value=f'Ja ({kanal.slowmode_delay} sekunder)' if kanal.slowmode_delay else 'Nei') + embed.add_field(name="Beskrivelse", value=kanal.topic if kanal.topic else "**Ingen**", inline=False) + embed.add_field(name="Opprettet", value=discord.utils.format_dt(kanal.created_at, style="F")) + embed.add_field(name="NSFW", value="Ja" if kanal.is_nsfw() else "Nei") + embed.add_field( + name="Saktemodus", value=f"Ja ({kanal.slowmode_delay} sekunder)" if kanal.slowmode_delay else "Nei" + ) if kanal.category: - embed.add_field(name='Kategori', value=kanal.category.name) - embed.add_field(name=f'Antall med tilgang ({len(kanal.members)})', value=members) + embed.add_field(name="Kategori", value=kanal.category.name) + embed.add_field(name=f"Antall med tilgang ({len(kanal.members)})", value=members) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @guild_group.command(name='talekanal', description='Hent informasjon om en talekanal') + @guild_group.command(name="talekanal", description="Hent informasjon om en talekanal") async def guild_voice_channel(self, interaction: discord.Interaction, kanal: discord.VoiceChannel): """ Get information about a voice channel @@ -448,14 +479,16 @@ class Info(commands.Cog): kanal (discord.VoiceChannel): Voice channel to fetch information about """ - embed = discord.Embed(color=interaction.guild.me.color, title=kanal.name, description=f'ID: {kanal.id}') + embed = discord.Embed(color=interaction.guild.me.color, title=kanal.name, description=f"ID: {kanal.id}") embed.set_author(name=kanal.guild.name, icon_url=kanal.guild.icon) - embed.add_field(name='Opprettet', value=discord.utils.format_dt(kanal.created_at, style='F')) - embed.add_field(name='Bitrate', value=f'{int(kanal.bitrate / 1000)}kbps') - embed.add_field(name='Maksgrense', value=f'{kanal.user_limit} personer' if kanal.user_limit != 0 else '∞ personer') + embed.add_field(name="Opprettet", value=discord.utils.format_dt(kanal.created_at, style="F")) + embed.add_field(name="Bitrate", value=f"{int(kanal.bitrate / 1000)}kbps") + embed.add_field( + name="Maksgrense", value=f"{kanal.user_limit} personer" if kanal.user_limit != 0 else "∞ personer" + ) if kanal.category: - embed.add_field(name='Kategori', value=kanal.category.name) - embed.add_field(name='Antall koblet til', value=len(kanal.members)) + embed.add_field(name="Kategori", value=kanal.category.name) + embed.add_field(name="Antall koblet til", value=len(kanal.members)) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) @@ -465,7 +498,7 @@ class Info(commands.Cog): @commands.guild_only() @commands.bot_has_permissions(embed_links=True) @commands.cooldown(1, 2) - @commands.command(name='emoji', description='Hent informasjon om en emoji i serveren') + @commands.command(name="emoji", description="Hent informasjon om en emoji i serveren") async def emoji(self, ctx: commands.Context, emoji: discord.Emoji): """ Get information about an emoji in the server @@ -478,21 +511,25 @@ class Info(commands.Cog): emoji = await emoji.guild.fetch_emoji(emoji.id) try: - emoji_creator = f'{emoji.user.mention}\n{emoji.user.name}#{emoji.user.discriminator}' + emoji_creator = f"{emoji.user.mention}\n{emoji.user.name}#{emoji.user.discriminator}" except AttributeError: - emoji_creator = 'Jeg trenger `manage_emojis`-tillatelsen på serveren den er fra for å hente dette' + emoji_creator = "Jeg trenger `manage_emojis`-tillatelsen på serveren den er fra for å hente dette" - embed = discord.Embed(color=ctx.me.color, title=emoji.name, description=f'ID: {emoji.id}') + embed = discord.Embed(color=ctx.me.color, title=emoji.name, description=f"ID: {emoji.id}") embed.set_author(name=emoji.guild.name, icon_url=emoji.guild.icon) - embed.add_field(name='Opprettet', value=discord.utils.format_dt(emoji.created_at, style='F')) - embed.add_field(name='Animert', value='Ja' if emoji.animated else 'Nei') - embed.add_field(name='Lagt til av', value=emoji_creator) + embed.add_field(name="Opprettet", value=discord.utils.format_dt(emoji.created_at, style="F")) + embed.add_field(name="Animert", value="Ja" if emoji.animated else "Nei") + embed.add_field(name="Lagt til av", value=emoji_creator) embed.set_image(url=emoji.url) await ctx.reply(embed=embed) - guild_oldest_group = app_commands.Group(name='eldst', description='Viser de eldste medlemmene på serveren', parent=guild_group) + guild_oldest_group = app_commands.Group( + name="eldst", description="Viser de eldste medlemmene på serveren", parent=guild_group + ) - def __construct_oldest_embed(self, paginator: misc_utils.Paginator, page: list, embed: discord.Embed) -> discord.Embed: + def __construct_oldest_embed( + self, paginator: misc_utils.Paginator, page: list, embed: discord.Embed + ) -> discord.Embed: """ Constructs the embed for the oldest commands @@ -502,14 +539,16 @@ class Info(commands.Cog): page (list): List of members to display embed (discord.Embed): Embed to add fields to """ - embed.description = '\n'.join(page) - embed.set_footer(text=f'Side {paginator.current_page}/{paginator.total_page_count}') + embed.description = "\n".join(page) + embed.set_footer(text=f"Side {paginator.current_page}/{paginator.total_page_count}") return embed @commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @guild_oldest_group.command(name='lagd', description='Liste over de eldste brukerene på serveren basert på når de ble lagd') + @guild_oldest_group.command( + name="lagd", description="Liste over de eldste brukerene på serveren basert på når de ble lagd" + ) async def guild_user_created_oldest(self, interaction: discord.Interaction): """ List the oldest users on the server based on when they were created @@ -523,23 +562,29 @@ class Info(commands.Cog): members = sorted(interaction.guild.members, key=lambda m: m.created_at) # Create list of members with index, name#discriminator and creation date - members_formatted = list(map( - lambda m: f'**#{(m[0] + 1)}** {m[1].name}#{m[1].discriminator} - {discord.utils.format_dt(m[1].created_at, style="F")}', - enumerate(members) - )) + members_formatted = list( + map( + lambda m: f'**#{(m[0] + 1)}** {m[1].name}#{m[1].discriminator} - {discord.utils.format_dt(m[1].created_at, style="F")}', + enumerate(members), + ) + ) paginator = misc_utils.Paginator(members_formatted) view = discord_utils.Scroller(paginator, self.__construct_oldest_embed) # Send first page - embed = discord.Embed(color=interaction.guild.me.color, title='Eldste brukere på serveren basert på når de ble lagd') + embed = discord.Embed( + color=interaction.guild.me.color, title="Eldste brukere på serveren basert på når de ble lagd" + ) embed = self.__construct_oldest_embed(paginator, paginator.get_current_page(), embed) await interaction.response.send_message(embed=embed, view=view) @commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @guild_oldest_group.command(name='joined', description='Liste over de eldste brukerene på serveren basert på når de ble med') + @guild_oldest_group.command( + name="joined", description="Liste over de eldste brukerene på serveren basert på når de ble med" + ) async def guild_user_joined_oldest(self, interaction: discord.Interaction): """ List the oldest users on the server based on when they joined @@ -553,23 +598,27 @@ class Info(commands.Cog): members = sorted(interaction.guild.members, key=lambda m: m.joined_at) # Create list of members with index, name#discriminator and creation date - members_formatted = list(map( - lambda m: f'**#{(m[0] + 1)}** {m[1].name}#{m[1].discriminator} - {discord.utils.format_dt(m[1].joined_at, style="F")}', - enumerate(members) - )) + members_formatted = list( + map( + lambda m: f'**#{(m[0] + 1)}** {m[1].name}#{m[1].discriminator} - {discord.utils.format_dt(m[1].joined_at, style="F")}', + enumerate(members), + ) + ) paginator = misc_utils.Paginator(members_formatted) view = discord_utils.Scroller(paginator, self.__construct_oldest_embed) # Send first page - embed = discord.Embed(color=interaction.guild.me.color, title='Eldste brukere på serveren basert på når de ble med') + embed = discord.Embed( + color=interaction.guild.me.color, title="Eldste brukere på serveren basert på når de ble med" + ) embed = self.__construct_oldest_embed(paginator, paginator.get_current_page(), embed) await interaction.response.send_message(embed=embed, view=view) @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True, external_emojis=True) @app_commands.checks.cooldown(1, 2) - @user_group.command(name='info', description='Hent informasjon om en bruker') + @user_group.command(name="info", description="Hent informasjon om en bruker") async def user_info(self, interaction: discord.Interaction, *, bruker: discord.Member | None = None): """ Get information about a user @@ -584,76 +633,93 @@ class Info(commands.Cog): bruker = interaction.user # Get device(s) that is currently used by the user - app = '' - if str(bruker.mobile_status) != 'offline': - app += '📱 ' - if str(bruker.web_status) != 'offline': - app += '🌐 ' - if str(bruker.desktop_status) != 'offline': - app += '💻' + app = "" + if str(bruker.mobile_status) != "offline": + app += "📱 " + if str(bruker.web_status) != "offline": + app += "🌐 " + if str(bruker.desktop_status) != "offline": + app += "💻" # Get index of join, creation and/or boost date in comparison to other users in the guild join_index = sorted(interaction.guild.members, key=lambda m: m.joined_at).index(bruker) + 1 creation_index = sorted(interaction.guild.members, key=lambda m: m.created_at).index(bruker) + 1 if bruker.premium_since: - premium_index = sorted(interaction.guild.premium_subscribers, key=lambda m: m.premium_since).index(bruker) + 1 + premium_index = ( + sorted(interaction.guild.premium_subscribers, key=lambda m: m.premium_since).index(bruker) + 1 + ) # Creation/join date & days ago - created_timestamp = discord.utils.format_dt(bruker.created_at, style='F') - joined_timestamp = discord.utils.format_dt(bruker.joined_at, style='F') + created_timestamp = discord.utils.format_dt(bruker.created_at, style="F") + joined_timestamp = discord.utils.format_dt(bruker.joined_at, style="F") joined_days = (interaction.created_at - bruker.joined_at).days created_days = (interaction.created_at - bruker.created_at).days # Boost date & days ago if bruker.premium_since: - premium_since = discord.utils.format_dt(bruker.premium_since, style='F') + premium_since = discord.utils.format_dt(bruker.premium_since, style="F") premium_since_days = (interaction.created_at - bruker.premium_since).days # Get user roles roles = self.__construct_role_string(bruker.roles) - roles = roles if len(roles) < 1024 else f'Bruk `/{self.bot.tree.get_command("bruker").get_command("roller").qualified_name}` for å se rollene' + roles = ( + roles + if len(roles) < 1024 + else f'Bruk `/{self.bot.tree.get_command("bruker").get_command("roller").qualified_name}` for å se rollene' + ) statuses = { - 'online': f'{self.bot.emoji["online"]} Pålogget', - 'idle': f'{self.bot.emoji["idle"]} Inaktiv', - 'dnd': f'{self.bot.emoji["dnd"]} Ikke forstyrr', - 'offline': f'{self.bot.emoji["offline"]} Frakoblet' + "online": f'{self.bot.emoji["online"]} Pålogget', + "idle": f'{self.bot.emoji["idle"]} Inaktiv', + "dnd": f'{self.bot.emoji["dnd"]} Ikke forstyrr', + "offline": f'{self.bot.emoji["offline"]} Frakoblet', } status = statuses[str(bruker.status)] - embed = discord.Embed(color=discord_utils.get_color(bruker), description=f'{bruker.mention}\nID: {bruker.id}\n{status}\n{app}') + embed = discord.Embed( + color=discord_utils.get_color(bruker), description=f"{bruker.mention}\nID: {bruker.id}\n{status}\n{app}" + ) if bruker.display_name == bruker.name: - embed.set_author(name=f'{bruker.name}#{bruker.discriminator}', icon_url=bruker.display_avatar) + embed.set_author(name=f"{bruker.name}#{bruker.discriminator}", icon_url=bruker.display_avatar) else: - embed.set_author(name=f'{bruker.name}#{bruker.discriminator} | {bruker.display_name}', - icon_url=bruker.display_avatar) + embed.set_author( + name=f"{bruker.name}#{bruker.discriminator} | {bruker.display_name}", icon_url=bruker.display_avatar + ) embed.set_thumbnail(url=bruker.display_avatar) - embed.add_field(name='Opprettet', value=f'{created_timestamp}\n{created_days} ' + - f'{"dag" if created_days == 1 else "dager"} siden') - embed.add_field(name='Ble med i serveren', value=f'{joined_timestamp}\n{joined_days} ' + - f'{"dag" if joined_days == 1 else "dager"} siden') + embed.add_field( + name="Opprettet", + value=f"{created_timestamp}\n{created_days} " + f'{"dag" if created_days == 1 else "dager"} siden', + ) + embed.add_field( + name="Ble med i serveren", + value=f"{joined_timestamp}\n{joined_days} " + f'{"dag" if joined_days == 1 else "dager"} siden', + ) if bruker.premium_since: - embed.add_field(name='Boost', value=f'{premium_since}\n{premium_since_days} ' + - f'{"dag" if premium_since_days == 1 else "dager"} siden\n' + - f'Booster #{premium_index} av serveren', inline=False) - embed.add_field(name=f'Roller ({len(bruker.roles)})', value=roles, inline=False) - embed.set_footer(text=f'#{join_index} Medlem av serveren | #{creation_index} Eldste brukeren på serveren') + embed.add_field( + name="Boost", + value=f"{premium_since}\n{premium_since_days} " + + f'{"dag" if premium_since_days == 1 else "dager"} siden\n' + + f"Booster #{premium_index} av serveren", + inline=False, + ) + embed.add_field(name=f"Roller ({len(bruker.roles)})", value=roles, inline=False) + embed.set_footer(text=f"#{join_index} Medlem av serveren | #{creation_index} Eldste brukeren på serveren") # Playing activity if bruker.activities: - games = '' + games = "" for activity in bruker.activities: - games += f'{activity.name}\n' + games += f"{activity.name}\n" if games: - embed.add_field(name='Spiller', value=games, inline=False) + embed.add_field(name="Spiller", value=games, inline=False) await interaction.response.send_message(embed=embed) @app_commands.guild_only() @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @user_group.command(name='roller', description='Hent roller til en bruker') + @user_group.command(name="roller", description="Hent roller til en bruker") async def user_roles(self, interaction: discord.Interaction, bruker: discord.Member | None = None): """ Get roles of a user @@ -671,16 +737,18 @@ class Info(commands.Cog): # If the list of roles is too long, send it as a file if len(roles) > 2048: - self.__send_as_txt_file(interaction, f'./assets/temp/{interaction.guild.id}_{interaction.user.id}_roles.txt', roles) + self.__send_as_txt_file( + interaction, f"./assets/temp/{interaction.guild.id}_{interaction.user.id}_roles.txt", roles + ) else: embed = discord.Embed(color=discord_utils.get_color(bruker), description=roles) - embed.set_author(name=f'Roller ({len(bruker.roles)})', icon_url=bruker.display_avatar) - embed.set_footer(text=f'{bruker.name}#{bruker.discriminator}', icon_url=bruker.display_avatar) + embed.set_author(name=f"Roller ({len(bruker.roles)})", icon_url=bruker.display_avatar) + embed.set_footer(text=f"{bruker.name}#{bruker.discriminator}", icon_url=bruker.display_avatar) await interaction.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @user_group.command(name='avatar', description='Hent avatar til en bruker') + @user_group.command(name="avatar", description="Hent avatar til en bruker") async def user_avatar(self, interaction: discord.Interaction, bruker: discord.User | discord.Member | None = None): """ Get avatar of a user @@ -694,8 +762,8 @@ class Info(commands.Cog): if not bruker: bruker = interaction.user - embed = discord.Embed(color=discord_utils.get_color(bruker), description=f'[Lenke]({bruker.display_avatar})') - embed.set_author(name=f'{bruker.name}#{bruker.discriminator}', icon_url=bruker.display_avatar) + embed = discord.Embed(color=discord_utils.get_color(bruker), description=f"[Lenke]({bruker.display_avatar})") + embed.set_author(name=f"{bruker.name}#{bruker.discriminator}", icon_url=bruker.display_avatar) embed.set_image(url=bruker.display_avatar) embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) diff --git a/src/cogs/mc_whitelist.py b/src/cogs/mc_whitelist.py index 5d099db..180fdc1 100644 --- a/src/cogs/mc_whitelist.py +++ b/src/cogs/mc_whitelist.py @@ -1,8 +1,8 @@ import discord +import requests from discord import app_commands from discord.ext import commands from mcrcon import MCRcon -import requests from cogs.utils import embed_templates @@ -35,7 +35,7 @@ class MCWhitelist(commands.Cog): @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') + @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 @@ -47,11 +47,13 @@ class MCWhitelist(commands.Cog): """ # Fetch minecraft uuid from api - data = requests.get(f'https://api.mojang.com/users/profiles/minecraft/{minecraftbrukernavn}', timeout=10) + data = requests.get(f"https://api.mojang.com/users/profiles/minecraft/{minecraftbrukernavn}", timeout=10) if data.status_code != 200: return await interaction.response.send_message( - embed=embed_templates.error_fatal(interaction, text=f'Brukeren `{minecraftbrukernavn}` finnes ikke på minecraft'), - ephemeral=True + embed=embed_templates.error_fatal( + interaction, text=f"Brukeren `{minecraftbrukernavn}` finnes ikke på minecraft" + ), + ephemeral=True, ) data = data.json() @@ -62,21 +64,21 @@ class MCWhitelist(commands.Cog): SELECT * FROM mc_whitelist WHERE minecraft_id = %s OR discord_id = %s - """, (data['id'], interaction.user.id) + """, + (data["id"], interaction.user.id), ) if self.cursor.fetchone(): return await interaction.response.send_message( embed=embed_templates.error_fatal( - interaction, - text='Du har allerede whitelisted en bruker eller så er brukeren du oppga whitelisted' + interaction, text="Du har allerede whitelisted en bruker eller så er brukeren du oppga whitelisted" ) ) # Whitelist user on minecraft server # Unfortunately, this requires an active connection to the server, with correct credentials - with MCRcon(host='127.0.0.1', password=self.bot.mc_rcon_password, port=25575) as mcr: + 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') + mcr.command("whitelist reload") # Add user to db self.cursor.execute( @@ -84,7 +86,7 @@ class MCWhitelist(commands.Cog): INSERT INTO mc_whitelist (discord_id, minecraft_id) VALUES (%s, %s) """, - (interaction.user.id, data['id']), + (interaction.user.id, data["id"]), ) await interaction.response.send_message( diff --git a/src/cogs/misc.py b/src/cogs/misc.py index 23f09bc..3ceb617 100644 --- a/src/cogs/misc.py +++ b/src/cogs/misc.py @@ -1,13 +1,15 @@ -from datetime import datetime import re -from os import remove import urllib +from datetime import datetime +from os import remove import discord +import requests from discord import app_commands from discord.ext import commands -from PIL import Image, ImageDraw, ImageFont -import requests +from PIL import Image +from PIL import ImageDraw +from PIL import ImageFont from cogs.utils import embed_templates from cogs.utils.misc_utils import ignore_exception @@ -27,7 +29,7 @@ class Misc(commands.Cog): @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @app_commands.command(name='weeb', description='Kjeft på weebs') + @app_commands.command(name="weeb", description="Kjeft på weebs") async def weeb(self, interaction: discord.Interaction): """ Call out weebs @@ -37,11 +39,11 @@ class Misc(commands.Cog): interaction (discord.Interaction): Slash command context object """ - await interaction.response.send_message('<:sven:762725919604473866> Weebs 👉 <#803596668129509417>') + await interaction.response.send_message("<:sven:762725919604473866> Weebs 👉 <#803596668129509417>") @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @app_commands.command(name='owo', description='Oversetter teksten din til owo (we_eb)') + @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) @@ -52,13 +54,13 @@ class Misc(commands.Cog): tekst (str): Text to translate """ - owo_rules = {'r': 'w', 'l': 'w', 'R': 'W', 'L': 'W', 'n': 'ny', 'N': 'Ny', 'ove': 'uv'} + owo_rules = {"r": "w", "l": "w", "R": "W", "L": "W", "n": "ny", "N": "Ny", "ove": "uv"} for key, value in owo_rules.items(): tekst = re.sub(key, value, tekst) # https://kaomoji.moe/ if len(tekst) >= 1000: - embed = embed_templates.error_warning(interaction, text='Teksten er for lang') + embed = embed_templates.error_warning(interaction, text="Teksten er for lang") return await interaction.response.send_message(embed=embed) embed = discord.Embed(color=interaction.client.user.color, description=tekst) @@ -66,7 +68,7 @@ class Misc(commands.Cog): await interaction.response.send_message(embed=embed) @app_commands.checks.cooldown(1, 5) - @app_commands.command(name='emne', description='For NTNU\'ere som ikke kan emnekoder på UiO') + @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 @@ -77,15 +79,17 @@ class Misc(commands.Cog): emnekode (str): UiO course code """ - data = requests.get(f'https://data.uio.no/studies/v1/course/{emnekode}', timeout=10) + data = requests.get(f"https://data.uio.no/studies/v1/course/{emnekode}", timeout=10) if data.status_code != 200: - return await interaction.response.send_message(embed=embed_templates.error_fatal(interaction, text='Fant ikke emnekode')) + return await interaction.response.send_message( + embed=embed_templates.error_fatal(interaction, text="Fant ikke emnekode") + ) - await interaction.response.send_message(data.json()['info']['name']) + await interaction.response.send_message(data.json()["info"]["name"]) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 2) - @app_commands.command(name='klappifiser', description='Klappifiser tekst') + @app_commands.command(name="klappifiser", description="Klappifiser tekst") async def clapify(self, interation: discord.Interaction, tekst: str): """ Add clap emoji between every word of a string @@ -97,18 +101,18 @@ class Misc(commands.Cog): """ if len(tekst) >= 1000: - embed = embed_templates.error_warning(interation, text='Teksten er for lang') + embed = embed_templates.error_warning(interation, text="Teksten er for lang") return await interation.response.send_message(embed=embed) - tekst = re.sub(' ', '👏', tekst) + tekst = re.sub(" ", "👏", tekst) - embed = discord.Embed(color=interation.client.user.color, description=f'**{tekst.upper()}**') + embed = discord.Embed(color=interation.client.user.color, description=f"**{tekst.upper()}**") embed_templates.default_footer(interation, embed) await interation.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @app_commands.command(name='imdb', description='Søk etter filmer på IMDB') + @app_commands.command(name="imdb", description="Søk etter filmer på IMDB") async def imdb(self, interaction: discord.Interaction, tittel: str): """ Search for movies on IMDB and displays information about the first result @@ -120,20 +124,22 @@ class Misc(commands.Cog): """ # Search for movie/show - url = 'http://www.omdbapi.com/?' + urllib.parse.urlencode({'s': tittel, 'apikey': self.bot.api_keys['omdb']}) + url = "http://www.omdbapi.com/?" + urllib.parse.urlencode({"s": tittel, "apikey": self.bot.api_keys["omdb"]}) search = requests.get(url, timeout=10).json() try: - best_result_id = search['Search'][0]['imdbID'] + best_result_id = search["Search"][0]["imdbID"] except KeyError: - embed = embed_templates.error_fatal(interaction, text='Fant ikke filmen!') + embed = embed_templates.error_fatal(interaction, text="Fant ikke filmen!") return await interaction.response.send_message(embed=embed) # Get movie/show info - data = requests.get(f'http://www.omdbapi.com/?i={best_result_id}&apikey={self.bot.api_keys["omdb"]}', timeout=10).json() - acceptable_media_types = ['movie', 'series', 'episode'] - if data['Type'] not in acceptable_media_types: - embed = embed_templates.error_fatal(interaction, text='Fant ikke filmen!') + 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( @@ -142,27 +148,27 @@ class Misc(commands.Cog): url=f'https://www.imdb.com/title/{data["imdbID"]}/', ) embed.set_author(name=interaction.user.name, icon_url=interaction.user.display_avatar) - embed.add_field(name='Type', value=data['Type'].title()) - embed.add_field(name='Sjanger', value=data['Genre']) - embed.add_field(name='Spilletid', value=data['Runtime']) - embed.add_field(name='Vurdering på IMDb', value=f'{data["imdbRating"]}/10') - release_date = datetime.strptime(data['Released'], '%d %b %Y') - embed.add_field(name='Utgitt', value=discord.utils.format_dt(release_date, style='D')) + embed.add_field(name="Type", value=data["Type"].title()) + embed.add_field(name="Sjanger", value=data["Genre"]) + embed.add_field(name="Spilletid", value=data["Runtime"]) + embed.add_field(name="Vurdering på IMDb", value=f'{data["imdbRating"]}/10') + release_date = datetime.strptime(data["Released"], "%d %b %Y") + embed.add_field(name="Utgitt", value=discord.utils.format_dt(release_date, style="D")) embed_templates.default_footer(interaction, embed) - if data['Poster'] != 'N/A': - embed.set_thumbnail(url=data['Poster']) - if data['Director'] != 'N/A': - embed.description = data['Director'] - if data['Plot'] != 'N/A' and len(data['Plot']) < 1024: - embed.add_field(name='Sammendrag', value=data['Plot'], inline=False) + if data["Poster"] != "N/A": + embed.set_thumbnail(url=data["Poster"]) + if data["Director"] != "N/A": + embed.description = data["Director"] + if data["Plot"] != "N/A" and len(data["Plot"]) < 1024: + embed.add_field(name="Sammendrag", value=data["Plot"], inline=False) await interaction.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @app_commands.command(name='helligdager', description='Se helligdager i et land for et år') - async def holidays(self, interaction: discord.Interaction, *, land: str = 'NO', år: int = None): + @app_commands.command(name="helligdager", description="Se helligdager i et land for et år") + async def holidays(self, interaction: discord.Interaction, *, land: str = "NO", år: int = None): """ Get holidays for a country for a given year @@ -176,31 +182,33 @@ class Misc(commands.Cog): land = land.upper() aar = datetime.now().year if not år else int(år) - data = requests.get(f'https://date.nager.at/api/v2/publicholidays/{aar}/{land}', timeout=10) + data = requests.get(f"https://date.nager.at/api/v2/publicholidays/{aar}/{land}", timeout=10) if data.status_code != 200: embed = embed_templates.error_fatal( - interaction, text='Ugyldig land\nHusk å bruke landskoder\n' + 'For eksempel: `NO`' + interaction, text="Ugyldig land\nHusk å bruke landskoder\n" + "For eksempel: `NO`" ) return await interaction.response.send_message(embed=embed) data = data.json() - country = data[0]['countryCode'].lower() + country = data[0]["countryCode"].lower() # Construct output - holiday_str = '' + holiday_str = "" for day in data: - date = discord.utils.format_dt(datetime.strptime(day['date'], '%Y-%m-%d'), style='D') + date = discord.utils.format_dt(datetime.strptime(day["date"], "%Y-%m-%d"), style="D") holiday_str += f'**{date}**: {day["localName"]}\n' - embed = discord.Embed(color=interaction.client.user.color, title=f':flag_{country}: Helligdager {aar} :flag_{country}:') + embed = discord.Embed( + color=interaction.client.user.color, title=f":flag_{country}: Helligdager {aar} :flag_{country}:" + ) embed.description = holiday_str embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True) @app_commands.checks.cooldown(1, 5) - @app_commands.command(name='match', description='Se hvor mye du matcher med en annen') + @app_commands.command(name="match", description="Se hvor mye du matcher med en annen") async def match(self, interaction: discord.Interaction, bruker: discord.Member): """ Get dating compatibility with another user @@ -213,7 +221,7 @@ class Misc(commands.Cog): if bruker == interaction.user: embed = embed_templates.error_warning( - interaction, text='Jeg vet du er ensom, men du kan ' 'ikke matche med deg selv' + interaction, text="Jeg vet du er ensom, men du kan " "ikke matche med deg selv" ) return await interaction.response.send_message(embed=embed) @@ -225,38 +233,38 @@ class Misc(commands.Cog): if bruker.id == self.bot.user.id: match_percent = 100 - await interaction.user.display_avatar.save(fp=f'./src/assets/temp/{interaction.user.id}_raw.png') - await bruker.display_avatar.save(fp=f'./src/assets/temp/{bruker.id}_raw.png') + await interaction.user.display_avatar.save(fp=f"./src/assets/temp/{interaction.user.id}_raw.png") + await bruker.display_avatar.save(fp=f"./src/assets/temp/{bruker.id}_raw.png") - invoker = Image.open(f'./src/assets/temp/{interaction.user.id}_raw.png').convert('RGBA') + invoker = Image.open(f"./src/assets/temp/{interaction.user.id}_raw.png").convert("RGBA") invoker = invoker.resize((389, 389), Image.ANTIALIAS) - user = Image.open(f'./src/assets/temp/{bruker.id}_raw.png').convert('RGBA') + user = Image.open(f"./src/assets/temp/{bruker.id}_raw.png").convert("RGBA") user = user.resize((389, 389), Image.ANTIALIAS) - heart = Image.open('./src/assets/misc/heart.png') - mask = Image.open('./src/assets/misc/heart.png', 'r') + heart = Image.open("./src/assets/misc/heart.png") + mask = Image.open("./src/assets/misc/heart.png", "r") - image = Image.new('RGBA', (1024, 576)) + image = Image.new("RGBA", (1024, 576)) image.paste(invoker, (0, 94)) image.paste(user, (635, 94)) image.paste(heart, (311, 94), mask=mask) draw = ImageDraw.Draw(image) - font = ImageFont.truetype('./src/assets/fonts/RobotoMono-Medium.ttf', 86) - font_size = font.getsize(f'{match_percent}%') + font = ImageFont.truetype("./src/assets/fonts/RobotoMono-Medium.ttf", 86) + font_size = font.getsize(f"{match_percent}%") font_size = ((image.size[0] - font_size[0]) / 2, (image.size[1] - font_size[1]) / 2) - draw.text(font_size, f'{match_percent}%', font=font, fill=(255, 255, 255, 255)) + draw.text(font_size, f"{match_percent}%", font=font, fill=(255, 255, 255, 255)) - image.save(f'./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png') + image.save(f"./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png") - f = discord.File(f'./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png') + f = discord.File(f"./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png") embed = discord.Embed() - embed.set_image(url=f'attachment://{interaction.user.id}_{bruker.id}_edit.png') + embed.set_image(url=f"attachment://{interaction.user.id}_{bruker.id}_edit.png") embed_templates.default_footer(interaction, embed) await interaction.response.send_message(embed=embed, file=f) with ignore_exception(OSError): - remove(f'./src/assets/temp/{bruker.id}_raw.png') - remove(f'./src/assets/temp/{interaction.user.id}_raw.png') - remove(f'./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png') + remove(f"./src/assets/temp/{bruker.id}_raw.png") + remove(f"./src/assets/temp/{interaction.user.id}_raw.png") + remove(f"./src/assets/temp/{interaction.user.id}_{bruker.id}_edit.png") async def setup(bot: commands.Bot): diff --git a/src/cogs/repeated_messages.py b/src/cogs/repeated_messages.py index f39cdbc..29d341f 100644 --- a/src/cogs/repeated_messages.py +++ b/src/cogs/repeated_messages.py @@ -21,7 +21,7 @@ class RepeatedMessages(commands.Cog): # await asyncio.sleep(1) # await channel.send(stickers=[sticker]) - @aiocron.crontab('0 0 * * 5') + @aiocron.crontab("0 0 * * 5") async def fredag(): """Sends a message on Friday at 00:00""" @@ -29,42 +29,39 @@ class RepeatedMessages(commands.Cog): channel = guild.get_channel(747542544291987597) videos = [ - 'https://cdn.discordapp.com/attachments/750052141346979850/851216786259181578/video0.mp4', - 'https://cdn.discordapp.com/attachments/878368386671849582/1043133798512070666/durk_durk_fredag.mp4', - 'https://cdn.discordapp.com/attachments/878368386671849582/1043133820079177808/finfredag.png', - 'https://cdn.discordapp.com/attachments/878368386671849582/1043133832360120340/fredag_1.mp4', - 'https://cdn.discordapp.com/attachments/878368386671849582/1043133914316816424/shutup_friday.mp4', - 'https://cdn.discordapp.com/attachments/878368386671849582/1043133934915031040/uboot_fredag.mp4', - 'https://cdn.discordapp.com/attachments/747542544291987597/1037864063901909043/fredag_whole_store4.mp4', - 'https://cdn.discordapp.com/attachments/747542544291987597/1037864293154168863/fredag_wholesome.mp4', - 'https://cdn.discordapp.com/attachments/747542544291987597/1055835511366877244/received_914083109578582.gif', - 'https://cdn.discordapp.com/attachments/747542544291987597/1037866542328713256/fredag_i_norge.mp4' + "https://cdn.discordapp.com/attachments/750052141346979850/851216786259181578/video0.mp4", + "https://cdn.discordapp.com/attachments/878368386671849582/1043133798512070666/durk_durk_fredag.mp4", + "https://cdn.discordapp.com/attachments/878368386671849582/1043133820079177808/finfredag.png", + "https://cdn.discordapp.com/attachments/878368386671849582/1043133832360120340/fredag_1.mp4", + "https://cdn.discordapp.com/attachments/878368386671849582/1043133914316816424/shutup_friday.mp4", + "https://cdn.discordapp.com/attachments/878368386671849582/1043133934915031040/uboot_fredag.mp4", + "https://cdn.discordapp.com/attachments/747542544291987597/1037864063901909043/fredag_whole_store4.mp4", + "https://cdn.discordapp.com/attachments/747542544291987597/1037864293154168863/fredag_wholesome.mp4", + "https://cdn.discordapp.com/attachments/747542544291987597/1055835511366877244/received_914083109578582.gif", + "https://cdn.discordapp.com/attachments/747542544291987597/1037866542328713256/fredag_i_norge.mp4", ] - await channel.send( - 'NU ÄR DET FREDAG!\n' + - random.choice(videos) - ) + await channel.send("NU ÄR DET FREDAG!\n" + random.choice(videos)) - @aiocron.crontab('0 0 * * 1') + @aiocron.crontab("0 0 * * 1") async def mandag(): """Sends a message on Monday at 00:00""" guild = self.bot.get_guild(747542543750660178) channel = guild.get_channel(747542544291987597) await channel.send( - 'ENDELIG MANDAG!\n\n' + - 'https://cdn.discordapp.com/attachments/678396498089738250/862853827278929940/hvorfor_de_rike_br_spises.mp4' + "ENDELIG MANDAG!\n\n" + + "https://cdn.discordapp.com/attachments/678396498089738250/862853827278929940/hvorfor_de_rike_br_spises.mp4" ) - @aiocron.crontab('0 0 1 1 *') + @aiocron.crontab("0 0 1 1 *") async def new_year(): """Sends a message on New Year's Day at 00:00""" guild = self.bot.get_guild(747542543750660178) channel = guild.get_channel(747542544291987597) await channel.send( - 'GODT NYTTÅR!\n\nNå, meld dere inn i UiO Gaming igjen <:ThisIsAThreat:874998234072903710>' + "GODT NYTTÅR!\n\nNå, meld dere inn i UiO Gaming igjen <:ThisIsAThreat:874998234072903710>" ) diff --git a/src/cogs/thousandth_member.py b/src/cogs/thousandth_member.py index 7257f5b..e9b73e4 100644 --- a/src/cogs/thousandth_member.py +++ b/src/cogs/thousandth_member.py @@ -29,6 +29,7 @@ class ThousanthMember(commands.Cog): channel = member.guild.get_channel(747542544291987597) await channel.send("Vi er nå 1000 brukere på serveren! <:LETSFUCKINGGOOOOOO:814477215868649492>") + async def setup(bot: commands.Bot): """ Add the cog to the bot on extension load @@ -38,6 +39,5 @@ async def setup(bot: commands.Bot): bot (commands.Bot): Bot instance """ - bot.add_listener(ThousanthMember(bot).on_member_join, 'on_member_join') + bot.add_listener(ThousanthMember(bot).on_member_join, "on_member_join") await bot.add_cog(ThousanthMember(bot)) - diff --git a/src/cogs/utils/discord_utils.py b/src/cogs/utils/discord_utils.py index 4d02ebf..595282f 100644 --- a/src/cogs/utils/discord_utils.py +++ b/src/cogs/utils/discord_utils.py @@ -16,7 +16,7 @@ def get_color(discord_object: discord.User | discord.Member | discord.Role) -> d (discord.Color): The user's displayed color """ - if hasattr(discord_object, 'color') and str(discord_object.color) != '#000000': + if hasattr(discord_object, "color") and str(discord_object.color) != "#000000": return discord_object.color return discord.Colour(0x99AAB5) @@ -25,7 +25,14 @@ def get_color(discord_object: discord.User | discord.Member | discord.Role) -> d 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): + def __init__( + self, + paginator: Paginator, + button_action: callable, + content_constructor: callable, + label: str, + disabled: bool = False, + ): """ Parameters ----------- @@ -67,7 +74,39 @@ class Scroller(discord.ui.View): 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)) + 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, + ) + ) diff --git a/src/cogs/utils/embed_templates.py b/src/cogs/utils/embed_templates.py index ce41af3..78cf079 100644 --- a/src/cogs/utils/embed_templates.py +++ b/src/cogs/utils/embed_templates.py @@ -16,8 +16,7 @@ def default_footer(interaction: discord.Interaction, embed: discord.Embed) -> di """ return embed.set_footer( - icon_url=interaction.user.avatar, - text=f'{interaction.user.name}#{interaction.user.discriminator}' + icon_url=interaction.user.avatar, text=f"{interaction.user.name}#{interaction.user.discriminator}" ) @@ -35,7 +34,7 @@ def error_warning(interaction: discord.Interaction, text: str) -> discord.Embed: (discord.Embed): An embed object based on the template with the specified text """ - embed = discord.Embed(color=discord.Color.gold(), description=f'⚠️ {text}') + embed = discord.Embed(color=discord.Color.gold(), description=f"⚠️ {text}") default_footer(interaction, embed) return embed @@ -55,7 +54,7 @@ def error_fatal(interaction: discord.Interaction, text: str) -> discord.Embed: (discord.Embed): An embed object based on the template with the specified text """ - embed = discord.Embed(color=discord.Color.red(), description=f'❌ {text}') + embed = discord.Embed(color=discord.Color.red(), description=f"❌ {text}") default_footer(interaction, embed) return embed @@ -75,7 +74,7 @@ def success(interaction: discord.Interaction, text: str) -> discord.Embed: discord.Embed: An embed object based on the template with the specified text """ - embed = discord.Embed(color=discord.Color.green(), description=f'✅ {text}') + embed = discord.Embed(color=discord.Color.green(), description=f"✅ {text}") default_footer(interaction, embed) return embed diff --git a/src/cogs/word_cloud.py b/src/cogs/word_cloud.py index 4578a7f..84c285f 100644 --- a/src/cogs/word_cloud.py +++ b/src/cogs/word_cloud.py @@ -1,23 +1,26 @@ -import discord -from discord import app_commands -from discord.ext import commands, tasks - -from collections import defaultdict import functools import itertools -from io import BytesIO, StringIO import json +import re +from collections import defaultdict +from io import BytesIO +from io import StringIO + +import discord import nltk -from nltk.corpus import stopwords import numpy as np +from discord import app_commands +from discord.ext import commands +from discord.ext import tasks +from nltk.corpus import stopwords from PIL import Image from psycopg2.extras import execute_batch -import re from wordcloud import WordCloud as WCloud # Avoid naming conflicts with cog class name -# from wordcloud import ImageColorGenerator from cogs.utils import embed_templates +# from wordcloud import ImageColorGenerator + class WordCloud(commands.Cog): """Generate a wordcloud based on the most frequent words posted""" @@ -40,7 +43,7 @@ class WordCloud(commands.Cog): self.consenting_users = [] self.populate_consenting_users() - nltk.download('stopwords') + nltk.download("stopwords") self.batch_update_word_freqs_loop.start() @@ -93,10 +96,12 @@ class WordCloud(commands.Cog): # Flatten the defaultdict into a list of tuples # This is a bit of a hack but it works - word_freqs = list(itertools.chain.from_iterable( - [(user_id, word, freq) for word, freq in user_word_freqs.items()] - for user_id, user_word_freqs in self.word_freq_cache.items() - )) + word_freqs = list( + itertools.chain.from_iterable( + [(user_id, word, freq) for word, freq in user_word_freqs.items()] + for user_id, user_word_freqs in self.word_freq_cache.items() + ) + ) # Insert cache into database try: @@ -107,7 +112,8 @@ class WordCloud(commands.Cog): VALUES (%s, %s, %s) ON CONFLICT (discord_user_id, word) DO UPDATE SET frequency = wordcloud_words.frequency + EXCLUDED.frequency - """, word_freqs + """, + word_freqs, ) except: self.bot.db_connection.rollback() @@ -148,7 +154,7 @@ class WordCloud(commands.Cog): for word in words: # Filter urls # do I really need to comment on this being naive again? - if re.match(r'https?://', word): + if re.match(r"https?://", word): continue # Remove punctuation @@ -156,16 +162,12 @@ class WordCloud(commands.Cog): if not word: continue - # Enter into cache - # This may take a performance hit but who tf cares. We're using python anyway - self.word_freq_cache[message.author.id][word] += 1 + # Enter into cache + # This may take a performance hit but who tf cares. We're using python anyway + self.word_freq_cache[message.author.id][word] += 1 @staticmethod - def generate_wordcloud( - text: str, - max_words: int = 4000, - allow_bigrams: bool = False - ) -> BytesIO: + def generate_wordcloud(text: str, max_words: int = 4000, allow_bigrams: bool = False) -> BytesIO: """ Generates a wordcloud @@ -180,8 +182,8 @@ class WordCloud(commands.Cog): BytesIO: BytesIO object containing the wordcloud image """ - filter_words = set(stopwords.words('norwegian') + stopwords.words('english')) - mask = np.array(Image.open('./src/assets/word_cloud/mask.png')) + filter_words = set(stopwords.words("norwegian") + stopwords.words("english")) + mask = np.array(Image.open("./src/assets/word_cloud/mask.png")) wc = WCloud( max_words=max_words, @@ -189,7 +191,7 @@ class WordCloud(commands.Cog): repeat=False, stopwords=filter_words, min_word_length=3, - collocations=allow_bigrams + collocations=allow_bigrams, ) wc.process_text(text) wc.generate(text) @@ -199,22 +201,19 @@ class WordCloud(commands.Cog): img = wc.to_image() b = BytesIO() - img.save(b, 'png') + img.save(b, "png") b.seek(0) return b wordcloud_group = app_commands.Group( - name='ordsky', - description='Generer en ordsky basert på dine mest frekvente sagte ord' + name="ordsky", description="Generer en ordsky basert på dine mest frekvente sagte ord" ) wordcloud_generate_group = app_commands.Group( - parent=wordcloud_group, - name='generer', - description='Generer en ordsky basert på dine mest frekvente sagte ord' + parent=wordcloud_group, name="generer", description="Generer en ordsky basert på dine mest frekvente sagte ord" ) @app_commands.checks.bot_has_permissions(embed_links=True) - @wordcloud_group.command(name='samtykke', description='Gi samtykke til å samle meldingsdataen din for ordskyer') + @wordcloud_group.command(name="samtykke", description="Gi samtykke til å samle meldingsdataen din for ordskyer") async def consent(self, interaction: discord.Interaction): """ Gi samtykke til å samle meldingsdataen din @@ -226,8 +225,7 @@ class WordCloud(commands.Cog): if interaction.user.id in self.consenting_users: return await interaction.response.send_message( - embed=embed_templates.error_warning(interaction, text='Du har allerede samtykket'), - ephemeral=False + embed=embed_templates.error_warning(interaction, text="Du har allerede samtykket"), ephemeral=False ) try: @@ -235,23 +233,24 @@ class WordCloud(commands.Cog): """ INSERT INTO wordcloud_metadata (discord_user_id, tracked_since_message_channel_id, tracked_since_message_id) VALUES (%s, %s, %s) - """, (interaction.user.id, interaction.channel_id, interaction.id) + """, + (interaction.user.id, interaction.channel_id, interaction.id), ) except: self.bot.db_connection.rollback() self.bot.logger.exception("Failed to insert wordcloud metadata into database") return await interaction.response.send_message( - embed=embed_templates.error_warning(interaction, text='Klarte ikke å skrive til database'), - ephemeral=False + embed=embed_templates.error_warning(interaction, text="Klarte ikke å skrive til database"), + ephemeral=False, ) self.consenting_users.append(interaction.user.id) - embed = embed_templates.success(interaction, 'Samtykke registrert!') + embed = embed_templates.success(interaction, "Samtykke registrert!") await interaction.response.send_message(embed=embed, ephemeral=False) @app_commands.checks.bot_has_permissions(embed_links=True) - @wordcloud_group.command(name='slett', description='Fjern samtykke og slett alle dine ordskydata') + @wordcloud_group.command(name="slett", description="Fjern samtykke og slett alle dine ordskydata") async def consent_remove(self, interaction: discord.Interaction): """ Fjern samtykke og slett meldingsdata @@ -265,33 +264,33 @@ class WordCloud(commands.Cog): self.consenting_users.remove(interaction.user.id) except ValueError: return await interaction.response.send_message( - embed=embed_templates.error_warning(interaction, text='Fant ingen data om deg'), - ephemeral=False + embed=embed_templates.error_warning(interaction, text="Fant ingen data om deg"), ephemeral=False ) - self.word_freq_cache.pop(f'{interaction.user.id}', None) + self.word_freq_cache.pop(f"{interaction.user.id}", None) try: self.cursor.execute( """ DELETE FROM wordcloud_metadata WHERE discord_user_id = %s; DELETE FROM wordcloud_words WHERE discord_user_id = %s; - """, (interaction.user.id, interaction.user.id) + """, + (interaction.user.id, interaction.user.id), ) except: self.bot.db_connection.rollback() self.bot.logger.exception("Failed to delete wordcloud metadata from database") return await interaction.response.send_message( - embed=embed_templates.error_warning(interaction, text='Klarte ikke å slette fra database'), - ephemeral=False + embed=embed_templates.error_warning(interaction, text="Klarte ikke å slette fra database"), + ephemeral=False, ) - embed = embed_templates.success(interaction, 'Meldingsdata er slettet!') + embed = embed_templates.success(interaction, "Meldingsdata er slettet!") await interaction.response.send_message(embed=embed) @app_commands.checks.bot_has_permissions(embed_links=True, attach_files=True) @app_commands.checks.cooldown(1, 10) - @wordcloud_group.command(name='data', description='Få tilsendt dine ordskydata i JSON-format') + @wordcloud_group.command(name="data", description="Få tilsendt dine ordskydata i JSON-format") async def data(self, interaction: discord.Interaction): """ Få tilsendt dine data @@ -307,30 +306,29 @@ class WordCloud(commands.Cog): FROM wordcloud_words WHERE discord_user_id = %s ORDER BY frequency DESC - """, (interaction.user.id,) + """, + (interaction.user.id,), ) result = self.cursor.fetchall() if not result: return await interaction.response.send_message( - embed=embed_templates.error_warning(interaction, text='Fant ingen data om deg'), - ephemeral=False + embed=embed_templates.error_warning(interaction, text="Fant ingen data om deg"), ephemeral=False ) - freq_list = {f'{word}': freq for word, freq in result} + freq_list = {f"{word}": freq for word, freq in result} - embed = discord.Embed(description='Her er dataen jeg har lagret om deg') + embed = discord.Embed(description="Her er dataen jeg har lagret om deg") buffer = StringIO() buffer.write(json.dumps(freq_list, indent=4)) buffer.seek(0) - file = discord.File(buffer, filename=f'uiog_word_freqs_{interaction.user.id}.json') + file = discord.File(buffer, filename=f"uiog_word_freqs_{interaction.user.id}.json") await interaction.response.send_message(embed=embed, file=file, ephemeral=True) @app_commands.checks.bot_has_permissions(embed_links=True, attach_files=True) @app_commands.checks.cooldown(1, 10) @wordcloud_generate_group.command( - name='alle', - description='Generer en ordsky basert på dine mest frekvente sagte ord siden du ga samtykke' + name="alle", description="Generer en ordsky basert på dine mest frekvente sagte ord siden du ga samtykke" ) async def generate_db(self, interaction: discord.Interaction): """ @@ -352,14 +350,14 @@ class WordCloud(commands.Cog): SELECT word, frequency FROM wordcloud_words WHERE discord_user_id = %s - """, (interaction.user.id,) + """, + (interaction.user.id,), ) results = self.cursor.fetchall() if not results: return await interaction.followup.send( - embed=embed_templates.error_warning(interaction, text='Fant ingen data om deg'), - ephemeral=False + embed=embed_templates.error_warning(interaction, text="Fant ingen data om deg"), ephemeral=False ) # Fetch tracking start time metadata @@ -368,13 +366,14 @@ class WordCloud(commands.Cog): SELECT tracked_since_message_channel_id, tracked_since_message_id FROM wordcloud_metadata WHERE discord_user_id = %s - """, (interaction.user.id,) + """, + (interaction.user.id,), ) origin_msg_channel_id, origin_msg_id = self.cursor.fetchone() try: origin_msg_channel = self.bot.get_channel(origin_msg_channel_id) origin_msg = await origin_msg_channel.fetch_message(origin_msg_id) - origin_msg_timestamp = discord.utils.format_dt(origin_msg.created_at, style='f') + origin_msg_timestamp = discord.utils.format_dt(origin_msg.created_at, style="f") except discord.errors.NotFound: origin_found = False else: @@ -389,21 +388,23 @@ class WordCloud(commands.Cog): generation_task = functools.partial(WordCloud.generate_wordcloud, text) word_cloud = await self.bot.loop.run_in_executor(None, generation_task) - word_cloud_file = discord.File(word_cloud, filename=f'wordcloud_{interaction.user.id}.png') - embed = discord.Embed(title='☁️ Her er ordskyen din! ☁️') + word_cloud_file = discord.File(word_cloud, filename=f"wordcloud_{interaction.user.id}.png") + embed = discord.Embed(title="☁️ Her er ordskyen din! ☁️") if origin_found: - embed.description = f'Basert på de 4000 mest frekvente ordene dine siden {origin_msg_timestamp}\n' + \ - f'[Se melding]({origin_msg.jump_url})' + embed.description = ( + f"Basert på de 4000 mest frekvente ordene dine siden {origin_msg_timestamp}\n" + + f"[Se melding]({origin_msg.jump_url})" + ) else: - embed.description = 'Basert på de 4000 mest frekvente ordene dine siden `ukjent dato`' - embed.set_image(url=f'attachment://wordcloud_{interaction.user.id}.png') + embed.description = "Basert på de 4000 mest frekvente ordene dine siden `ukjent dato`" + embed.set_image(url=f"attachment://wordcloud_{interaction.user.id}.png") await interaction.followup.send(embed=embed, file=word_cloud_file) @app_commands.checks.bot_has_permissions(embed_links=True, attach_files=True) @app_commands.checks.cooldown(1, 30) @wordcloud_generate_group.command( - name='siste', - description='Generer en ordsky basert på dine mest frekvente sagte ord fra de siste meldingene dine' + name="siste", + description="Generer en ordsky basert på dine mest frekvente sagte ord fra de siste meldingene dine", ) async def generate_last(self, interaction: discord.Interaction, antall: app_commands.Range[int, 100, 2000] = 1000): """ @@ -420,17 +421,22 @@ class WordCloud(commands.Cog): member_role = interaction.guild.get_role(779849617651138601) # Fetch last 1000 messages - all_messages = '' + all_messages = "" for channel in interaction.guild.text_channels: if not channel.permissions_for(interaction.user).send_messages: continue # Avoid reading secret board member chats - if not channel.permissions_for(member_role).send_messages and not channel.permissions_for(interaction.guild.default_role).send_messages: + if ( + not channel.permissions_for(member_role).send_messages + and not channel.permissions_for(interaction.guild.default_role).send_messages + ): continue try: - async for message in channel.history(limit=int(antall/2)): # Limit search in each channel to half of requested + async for message in channel.history( + limit=int(antall / 2) + ): # Limit search in each channel to half of requested if message.author != interaction.user: continue @@ -440,35 +446,33 @@ class WordCloud(commands.Cog): # Filter URLs filtered_msg = re.sub( - r'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)', # noqa: E501 - '', - message.clean_content + r"https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)", # noqa: E501 + "", + message.clean_content, ) - all_messages += f'{filtered_msg} ' + all_messages += f"{filtered_msg} " except discord.errors.Forbidden: continue if not all_messages: return await interaction.followup.send( - embed=embed_templates.error_warning(interaction, text='Fant ingen data om deg'), - ephemeral=False + embed=embed_templates.error_warning(interaction, text="Fant ingen data om deg"), ephemeral=False ) # Generate word cloud generation_task = functools.partial( - WordCloud.generate_wordcloud, - all_messages, - max_words=1000, - allow_bigrams=True + WordCloud.generate_wordcloud, all_messages, max_words=1000, allow_bigrams=True ) word_cloud = await self.bot.loop.run_in_executor(None, generation_task) - word_cloud_file = discord.File(word_cloud, filename=f'wordcloud_{interaction.user.id}.png') - embed = discord.Embed(title='☁️ Her er ordskyen din! ☁️') - embed.description = f'Basert på de {int(antall/2)} siste meldingene i alle kanaler og ' + \ - f'topp {antall} mest frekvente ord i dine meldinger' - embed.set_image(url=f'attachment://wordcloud_{interaction.user.id}.png') + word_cloud_file = discord.File(word_cloud, filename=f"wordcloud_{interaction.user.id}.png") + embed = discord.Embed(title="☁️ Her er ordskyen din! ☁️") + embed.description = ( + f"Basert på de {int(antall/2)} siste meldingene i alle kanaler og " + + f"topp {antall} mest frekvente ord i dine meldinger" + ) + embed.set_image(url=f"attachment://wordcloud_{interaction.user.id}.png") await interaction.followup.send(embed=embed, file=word_cloud_file) @@ -481,5 +485,5 @@ async def setup(bot: commands.Bot): bot (commands.Bot): Bot instance """ - bot.add_listener(WordCloud(bot).word_freq_listener, 'on_message') + bot.add_listener(WordCloud(bot).word_freq_listener, "on_message") await bot.add_cog(WordCloud(bot)) diff --git a/src/config/config.yaml.example b/src/config/config.yaml.example index d2343c9..efed68d 100644 --- a/src/config/config.yaml.example +++ b/src/config/config.yaml.example @@ -2,9 +2,9 @@ config_mode: dev # Bot settings bot: - token: + token: prefix: 'u!' - presence: + presence: message: Diskusjoner om borgerlønn activity: listening type: dnd @@ -22,7 +22,7 @@ minecraft: # Api keys api: - clarifai: + clarifai: # Emoji emoji: @@ -34,4 +34,4 @@ emoji: # Misc misc: website: https://uiogaming.no - source_code: https://github.com/UiO-Gaming/uiogaming-bot \ No newline at end of file + source_code: https://github.com/UiO-Gaming/uiogaming-bot diff --git a/src/logger.py b/src/logger.py index 0d0d493..c00a009 100644 --- a/src/logger.py +++ b/src/logger.py @@ -6,10 +6,10 @@ class BotLogger: """Logging config for the bot""" def __init__(self): - logger = logging.getLogger('discord') + 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 = 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) diff --git a/src/run.py b/src/run.py index c8e2b0c..0c763d5 100644 --- a/src/run.py +++ b/src/run.py @@ -3,15 +3,14 @@ from os import listdir from time import time import discord -from discord.ext import commands import psycopg2 import yaml +from discord.ext import commands from logger import BotLogger - # Load config file -with codecs.open('./src/config/config.yaml', 'r', encoding='utf8') as f: +with codecs.open("./src/config/config.yaml", "r", encoding="utf8") as f: config = yaml.load(f, Loader=yaml.SafeLoader) @@ -20,40 +19,40 @@ class Bot(commands.Bot): def __init__(self): super().__init__( - command_prefix=commands.when_mentioned_or(config['bot']['prefix']), + command_prefix=commands.when_mentioned_or(config["bot"]["prefix"]), case_insensitive=True, - intents=discord.Intents.all() + intents=discord.Intents.all(), ) self.logger = BotLogger().logger # Initialize logger # Connect to database - db = config.get('database', {}) + db = config.get("database", {}) self.db_connection = psycopg2.connect( - host=db['host'], - dbname=db['dbname'], - user=db['username'], - password=db['password'], + host=db["host"], + dbname=db["dbname"], + user=db["username"], + password=db["password"], ) self.db_connection.autocommit = True # 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('config_mode') + self.mc_rcon_password = config["minecraft"]["rcon_password"] + self.presence = config["bot"].get("presence", {}) + self.api_keys = config.get("api", {}) + self.emoji = config.get("emoji", {}) + self.misc = config.get("misc", {}) + self.config_mode = config.get("config_mode") async def setup_hook(self): # Load cogs - for file in listdir('./src/cogs'): - if file.endswith('.py'): + for file in listdir("./src/cogs"): + if file.endswith(".py"): name = file[:-3] - await bot.load_extension(f'cogs.{name}') + await bot.load_extension(f"cogs.{name}") # Sync slash commands to Discord - if self.config_mode == 'prod': + if self.config_mode == "prod": await self.tree.sync() else: self.tree.copy_global_to(guild=discord.Object(id=412646636771344395)) @@ -66,33 +65,32 @@ bot = Bot() @bot.event async def on_ready(): - if not hasattr(bot, 'uptime'): + if not hasattr(bot, "uptime"): bot.uptime = time() # Print bot info - print(f'Username: {bot.user.name}') - print(f'ID: {bot.user.id}') - print(f'Version: {discord.__version__}') - print('.' * 50 + '\n') + print(f"Username: {bot.user.name}") + print(f"ID: {bot.user.id}") + print(f"Version: {discord.__version__}") + print("." * 50 + "\n") # Set initial presence # Presence status status_types = { - 'online': discord.Status.online, - 'dnd': discord.Status.dnd, - 'idle': discord.Status.idle, - 'offline': discord.Status.offline, + "online": discord.Status.online, + "dnd": discord.Status.dnd, + "idle": discord.Status.idle, + "offline": discord.Status.offline, } - status_type = status_types.get(bot.presence['type'].lower(), discord.Status.online) + status_type = status_types.get(bot.presence["type"].lower(), discord.Status.online) # Presence actitivity - activities = {'playing': 0, 'listening': 2, 'watching': 3} - activity_type = activities.get(bot.presence['activity'].lower(), 0) + activities = {"playing": 0, "listening": 2, "watching": 3} + activity_type = activities.get(bot.presence["activity"].lower(), 0) await bot.change_presence( - activity=discord.Activity(type=activity_type, name=bot.presence['message']), - status=status_type + activity=discord.Activity(type=activity_type, name=bot.presence["message"]), status=status_type ) -bot.run(config['bot']['token'], reconnect=True, log_handler=None) +bot.run(config["bot"]["token"], reconnect=True, log_handler=None)