From 91c1312d35651bc0b879b74f50cf3eb2cbf5a995 Mon Sep 17 00:00:00 2001
From: dnns01 <git@dnns01.de>
Date: Mon, 19 Dec 2022 17:17:20 +0100
Subject: [PATCH] Remove old stuff and update schedule to post a weekly
 calendar

---
 .gitignore             |   1 +
 armin.py               |  35 ---------
 extensions/schedule.py | 165 +++++++++++++++++++++++++++++++++++++++++
 leaderboard.py         |  73 ------------------
 models.py              |  41 ++++++++++
 poll_cog.py            | 118 -----------------------------
 requirements.txt       |  23 +++---
 roll_cog.py            |  19 -----
 schedule.py            |  69 -----------------
 strolly.py             |  42 ++++-------
 utils.py               |  24 ------
 11 files changed, 233 insertions(+), 377 deletions(-)
 delete mode 100644 armin.py
 create mode 100644 extensions/schedule.py
 delete mode 100644 leaderboard.py
 create mode 100644 models.py
 delete mode 100644 poll_cog.py
 delete mode 100644 roll_cog.py
 delete mode 100644 schedule.py
 delete mode 100644 utils.py

diff --git a/.gitignore b/.gitignore
index 8512892..e67bb08 100644
--- a/.gitignore
+++ b/.gitignore
@@ -123,3 +123,4 @@ GitHub.sublime-settings
 /news.json
 /highscores.json
 /schedule.json
+/strolly.db
diff --git a/armin.py b/armin.py
deleted file mode 100644
index 357a087..0000000
--- a/armin.py
+++ /dev/null
@@ -1,35 +0,0 @@
-import random
-from datetime import datetime, timedelta
-
-from discord.ext import commands
-
-
-class Armin(commands.Cog):
-    def __init__(self, bot):
-        self.bot = bot
-        self.a = ["ein", "zwei", "drei", "vier", "fünf", "sechs"]
-        self.b = ["tägige", "wöchige", "monatige", "fache", "malige", "hebige"]
-        self.c = ["harte", "softe", "optionale", "intransparente", "alternativlose", "unumkehrbare"]
-        self.d = ["Wellenbrecher-", "Brücken-", "Treppen-", "Wende-", "Impf-", "Ehren-"]
-        self.e = ["Lockdown", "Stopp", "Maßnahme", "Kampagne", "Sprint", "Matrix"]
-        self.f = ["zum Sommer", "auf Weiteres", "zur Bundestagswahl", "2030", "nach den Abiturprüfungen",
-                  "in die Puppen"]
-        self.g = ["sofortigen", "nachhaltigen", "allmählichen", "unausweichlichen", "wirtschaftsschonenden",
-                  "willkürlichen"]
-        self.h = ["Senkung", "Steigerung", "Beendigung", "Halbierung", "Vernichtung", "Beschönigung"]
-        self.i = ["Infektionszahlen", "privaten Treffen", "Wirtschaftsleistung", "Wahlprognosen", "dritten Welle",
-                  "Bundeskanzlerin"]
-        self.arminsagt_cooldown = datetime.now()
-
-    @commands.command(name="arminsagt")
-    async def cmd_arminsagt(self, ctx):
-        if datetime.now() > self.arminsagt_cooldown:
-            self.arminsagt_cooldown = datetime.now() + timedelta(minutes=1)
-            rNum = random.randint(0, 5)
-            n = "n" if rNum not in [2, 3, 5] else ""
-            await ctx.send(f"Was wir jetzt brauchen, ist eine{n} {random.choice(self.a)}{random.choice(self.b)}{n} "
-                           f"{random.choice(self.c)}{n} {random.choice(self.d)}{self.e[rNum]} "
-                           f"bis {random.choice(self.f)} zur {random.choice(self.g)} {random.choice(self.h)} "
-                           f"der {random.choice(self.i)}.")
-        else:
-            await ctx.send("Sorry, aber Armin denkt noch nach...")
diff --git a/extensions/schedule.py b/extensions/schedule.py
new file mode 100644
index 0000000..d02487f
--- /dev/null
+++ b/extensions/schedule.py
@@ -0,0 +1,165 @@
+import base64
+import json
+import os
+from datetime import datetime, timedelta
+
+import discord
+from discord import app_commands, Interaction
+from discord.ext import commands, tasks
+from twitchio import Client
+
+from models import ScheduleSegment, TwitchChannel, Schedule
+
+
+def get_calendar_week():
+    now = datetime.now()
+    calendar = now.isocalendar()
+
+    if calendar.weekday < 7 or now.hour < 12:
+        start_day = now - timedelta(days=calendar.weekday - 1)
+        return calendar.week, datetime(year=start_day.year, month=start_day.month, day=start_day.day)
+
+    start_day = now + timedelta(days=1)
+    return start_day.isocalendar().week, datetime(year=start_day.year, month=start_day.month, day=start_day.day)
+
+
+def get_weekday(curr_day):
+    weekdays = ["", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]
+    return weekdays[curr_day.isocalendar().weekday]
+
+
+def remove_cancelled_streams(user, segments):
+    segments_dict = {segment.id: segment for segment in segments}
+
+    for schedule_segment in ScheduleSegment.select().where(ScheduleSegment.channel == user.id).where(
+            ScheduleSegment.start_time > datetime.now()):
+        if schedule_segment.id not in segments_dict:
+            schedule_segment.delete_instance()
+
+
+@app_commands.guild_only
+@app_commands.default_permissions(manage_server=True)
+class TwitchSchedule(commands.GroupCog, name="schedule"):
+    def __init__(self, bot):
+        self.bot = bot
+        self.twitch_client = Client.from_client_credentials(client_id=os.getenv("TWITCH_CLIENT_ID"),
+                                                            client_secret=os.getenv("TWITCH_CLIENT_SECRET"))
+        self.update_task.start()
+
+    @app_commands.command(name="add", description="Add Twitch channel to schedule")
+    @app_commands.describe(twitch_channel="Twitch channel to add",
+                           emoji="Emoji to be used for this channels entries in schedule",
+                           update_schedule="Define whether schedule should be updated or not.")
+    async def cmd_add(self, interaction: Interaction, twitch_channel: str, emoji: str, update_schedule: bool = False):
+        await interaction.response.defer(ephemeral=True)
+        user = await self.twitch_client.fetch_users(names=[twitch_channel])
+        if len(user) != 1:
+            await interaction.edit_original_response(
+                content="Twitch Kanal nicht gefunden. Bitte überprüfe, ob du den Kanal richtig geschrieben hast.")
+            return
+
+        if TwitchChannel.get_or_none(TwitchChannel.user_id == user[0].id):
+            await interaction.edit_original_response(
+                content="Der angegebene Kanal ist schon Teil des Kalenders.")
+            return
+
+        TwitchChannel.create(user_id=user[0].id, emoji=emoji, display_name=user[0].display_name)
+        await interaction.edit_original_response(
+            content=f"Twitch Kanal {twitch_channel} erfolgreich hinzugefügt.")
+        if update_schedule:
+            await self.update_schedule()
+
+    @app_commands.command(name="remove", description="Remove Twitch Channel from Schedule")
+    @app_commands.describe(twitch_channel="Twitch Channel to remove",
+                           update_schedule="Define whether Schedule should be updated or not.")
+    async def cmd_remove(self, interaction: Interaction, twitch_channel: str, update_schedule: bool = False):
+        await interaction.response.defer(ephemeral=True)
+        user = await self.twitch_client.fetch_users(names=[twitch_channel])
+        if len(user) != 1:
+            await interaction.edit_original_response(
+                content="Twitch Kanal nicht gefunden. Bitte überprüfe, ob du den Kanal richtig geschrieben hast.")
+            return
+
+        if channel := TwitchChannel.get_or_none(TwitchChannel.user_id == user[0].id):
+            channel.delete_instance(recursive=True)
+            await interaction.edit_original_response(
+                content=f"Twitch Kanal {twitch_channel} erfolgreich entfernt.")
+            if update_schedule:
+                await self.update_schedule()
+            return
+
+        await interaction.edit_original_response(
+            content=f"Twitch Kanal ist kein Teil des Kalenders.")
+
+    @app_commands.command(name="update", description="Force to update the schedule")
+    async def cmd_update(self, interaction: Interaction):
+        await interaction.response.defer(ephemeral=True)
+        await self.update_schedule()
+        await interaction.edit_original_response(content="Update abgeschlossen.")
+
+    @tasks.loop(hours=1)
+    async def update_task(self):
+        await self.update_schedule()
+
+    async def update_schedule(self):
+        await self.update_database()
+        calendar_week, start_day = get_calendar_week()
+        end_day = start_day + timedelta(days=6)
+
+        schedule_channel = await self.bot.fetch_channel(int(os.getenv("SCHEDULE_CHANNEL")))
+
+        week_schedule = Schedule.get_or_none(calendar_week=calendar_week, calendar_year=start_day.year)
+        embed = discord.Embed(title=f"Contentvorhersage für die {calendar_week}. Kalenderwoche",
+                              description=f"Strolchige Streams in der Woche vom {start_day.strftime('%d.%m.%Y')} "
+                                          f"bis {end_day.strftime('%d.%m.%Y')}")
+        embed.set_thumbnail(url="https://strolchibot.dnns01.dev/static/images/logo.png")
+
+        curr_day = start_day
+        while curr_day <= end_day:
+            name = f"{get_weekday(curr_day)} {curr_day.strftime('%d.%m.%Y')}"
+            value = ""
+            for segment in ScheduleSegment.select() \
+                    .where(ScheduleSegment.start_time.between(curr_day, (curr_day + timedelta(days=1)))) \
+                    .order_by(ScheduleSegment.start_time):
+                value += f"{segment.channel.emoji} {segment.timeframe()}\n{segment.title}\n\n"
+
+            if len(value) > 0:
+                embed.add_field(name=name, value=value, inline=False)
+            curr_day += timedelta(days=1)
+
+        if week_schedule.message_id:
+            try:
+                message = await schedule_channel.fetch_message(week_schedule.message_id)
+                await message.edit(embed=embed)
+                return
+            except:
+                pass
+
+        message = await schedule_channel.send("", embed=embed)
+        week_schedule.update(message_id=message.id).where(Schedule.id == week_schedule.id).execute()
+
+    async def update_database(self):
+        twitch_channels = [twitch_channel.user_id for twitch_channel in TwitchChannel.select()]
+        for user in await self.twitch_client.fetch_users(ids=twitch_channels):
+            schedule = await user.fetch_schedule()
+            for segment in schedule.segments:
+                segment_id = json.loads(base64.b64decode(segment.id))
+                calendar_year = segment_id["isoYear"]
+                calendar_week = segment_id["isoWeek"]
+                week_schedule = Schedule.get_or_create(calendar_week=calendar_week, calendar_year=calendar_year)
+                if segment.start_time < datetime.now().astimezone():
+                    continue
+                if schedule_segment := ScheduleSegment.get_or_none(
+                        ScheduleSegment.id == segment.id):
+                    schedule_segment.update(start_time=segment.start_time, end_time=segment.end_time,
+                                            title=segment.title, schedule=week_schedule[0].id) \
+                        .where(ScheduleSegment.id == segment.id).execute()
+                else:
+                    ScheduleSegment.create(id=segment.id, start_time=segment.start_time, end_time=segment.end_time,
+                                           title=segment.title, channel=user.id, schedule=week_schedule[0].id)
+
+            remove_cancelled_streams(user, schedule.segments)
+
+
+async def setup(bot: commands.Bot) -> None:
+    await bot.add_cog(TwitchSchedule(bot))
diff --git a/leaderboard.py b/leaderboard.py
deleted file mode 100644
index b4bc893..0000000
--- a/leaderboard.py
+++ /dev/null
@@ -1,73 +0,0 @@
-import json
-
-import discord
-from discord.ext import commands
-
-
-class Leaderboard(commands.Cog):
-    def __init__(self, bot):
-        self.bot = bot
-        self.highscores = self.load()
-
-    def load(self):
-        """ Load highscores from json file """
-        with open("highscores.json", mode="r") as highscore_file:
-            return json.load(highscore_file)
-
-    def save(self):
-        """ Save highscores to json file """
-        with open("highscores.json", mode="w") as highscore_file:
-            json.dump(self.highscores, highscore_file)
-
-    @commands.command(name="highscore")
-    async def cmd_highscore(self, ctx, score: int):
-        """ Add highscore for Dorfromantik leaderboard """
-
-        if score > 50:
-            if highscore := self.highscores.get(str(ctx.author.id)):
-                self.highscores[str(ctx.author.id)] = max(highscore, score)
-            else:
-                self.highscores[str(ctx.author.id)] = score
-            self.save()
-
-            await ctx.send(
-                f"Vielen Dank für deine Einreichung. Du bist damit auf Platz {self.get_place(ctx.author.id)} der Rangliste gelandet.")
-
-    @commands.command(name="romantikboard", aliases=["dorfpranger"])
-    async def cmd_romantikboard(self, ctx, all=None):
-
-        embed = discord.Embed(title="Dorfromantik Leaderboard",
-                              description="Offizielles inoffizielles Leaderborad des kultigen Karten-Lege-Spiels Dorfromantik der geilsten Powercommunity! Highscores, die HIER nicht eingetragen sind, zählen nicht!")
-        embed.set_thumbnail(url="https://img.itch.zone/aW1nLzQ2ODEyMTUuanBn/original/SVutRj.jpg")
-
-        places = scores = ""
-        place = 0
-        max = 0 if all == "all" else 10
-        ready = False
-        for key, value in sorted(self.highscores.items(), key=lambda item: item[1], reverse=True):
-            try:
-                place += 1
-
-                if 0 < max < place:
-                    if ready:
-                        break
-                    elif str(ctx.author.id) != key:
-                        continue
-                places += f"{place}: <@!{key}>\n"
-                scores += f"{value:,}\n".replace(",", ".")
-
-                if str(ctx.author.id) == key:
-                    ready = True
-            except:
-                pass
-
-        embed.add_field(name=f"Romantiker", value=places)
-        embed.add_field(name=f"Punkte", value=scores)
-        await ctx.send("", embed=embed)
-
-    def get_place(self, id):
-        place = 0
-        for key, value in sorted(self.highscores.items(), key=lambda item: item[1], reverse=True):
-            place += 1
-            if key == str(id):
-                return place
diff --git a/models.py b/models.py
new file mode 100644
index 0000000..9428adb
--- /dev/null
+++ b/models.py
@@ -0,0 +1,41 @@
+from datetime import datetime, timedelta
+
+from peewee import *
+
+db = SqliteDatabase("strolly.db")
+
+
+class BaseModel(Model):
+    class Meta:
+        database = db
+
+
+class TwitchChannel(BaseModel):
+    user_id = IntegerField(primary_key=True)
+    display_name = CharField()
+    emoji = CharField()
+
+
+class Schedule(BaseModel):
+    calendar_year = IntegerField()
+    calendar_week = IntegerField()
+    message_id = IntegerField(null=True)
+
+
+class ScheduleSegment(BaseModel):
+    id = CharField(primary_key=True)
+    start_time = DateTimeField()
+    end_time = DateTimeField(null=True)
+    title = CharField()
+    channel = ForeignKeyField(TwitchChannel, backref="schedule_segments")
+    schedule = ForeignKeyField(Schedule, backref="schedule_segments")
+
+    def timeframe(self):
+        tf = f"<t:{int(datetime.fromisoformat(self.start_time).timestamp())}:t> - "
+        end_time = datetime.fromisoformat(self.end_time) if self.end_time else datetime.fromisoformat(
+            self.start_time) + timedelta(hours=4)
+        tf += f"<t:{int(end_time.timestamp())}:t>"
+        return tf
+
+
+db.create_tables([TwitchChannel, Schedule, ScheduleSegment], safe=True)
diff --git a/poll_cog.py b/poll_cog.py
deleted file mode 100644
index 50fc600..0000000
--- a/poll_cog.py
+++ /dev/null
@@ -1,118 +0,0 @@
-import discord
-from discord.ext import commands
-
-OPTIONS = ["🇦", "🇧", "🇨", "🇩", "🇪", "🇫", "🇬", "🇭", "🇮", "🇯", "🇰", "🇱", "🇲", "🇳", "🇴", "🇵", "🇶", "🇷"]
-
-
-class PollCog(commands.Cog):
-    def __init__(self, bot):
-        self.bot = bot
-
-    @commands.command(name="poll")
-    async def cmd_poll(self, ctx, question, *answers):
-        """ Create poll """
-
-        await Poll(self.bot, question, answers, ctx.author.id).send_poll(ctx)
-
-    @commands.Cog.listener()
-    async def on_raw_reaction_add(self, payload):
-        if payload.user_id == self.bot.user.id:
-            return
-
-        if payload.emoji.name in ["🗑️", "🛑"]:
-            channel = await self.bot.fetch_channel(payload.channel_id)
-            message = await channel.fetch_message(payload.message_id)
-            if len(message.embeds) > 0 and message.embeds[0].title == "Umfrage":
-                poll = Poll(self.bot, message=message)
-                if str(payload.user_id) == poll.author:
-                    if payload.emoji.name == "🗑️":
-                        await poll.delete_poll()
-                    else:
-                        await poll.close_poll()
-
-
-class Poll:
-
-    def __init__(self, bot, question=None, answers=None, author=None, message=None):
-        self.bot = bot
-        self.question = question
-        self.answers = answers
-        self.author = author
-
-        if message:
-            self.message = message
-            self.answers = []
-            embed = message.embeds[0]
-            self.author = embed.fields[0].value[3:-1]
-            self.question = embed.description
-            for i in range(2, len(embed.fields)):
-                self.answers.append(embed.fields[i].value)
-
-    async def send_poll(self, channel, result=False, message=None):
-        option_ctr = 0
-        title = "Umfrage"
-
-        if result:
-            title += " Ergebnis"
-
-        if len(self.answers) > len(OPTIONS):
-            await channel.send(
-                f"Fehler beim Erstellen der Umfrage! Es werden nicht mehr als {len(OPTIONS)} Optionen unterstützt!")
-            return
-
-        embed = discord.Embed(title=title, description=self.question)
-        embed.add_field(name="Erstellt von", value=f'<@!{self.author}>', inline=False)
-        embed.add_field(name="\u200b", value="\u200b", inline=False)
-
-        for i in range(0, len(self.answers)):
-            name = f'{OPTIONS[i]}'
-            value = f'{self.answers[i]}'
-
-            if result:
-                reaction = self.get_reaction(name)
-                if reaction:
-                    name += f' : {reaction.count - 1}'
-                    # value += f'\nStimmen: '
-
-                    # async for user in reaction.users():
-                    #     if self.bot.user == user:
-                    #         continue
-                    #     ping = f'<@!{str(user.id)}> '
-                    #
-                    #     if len(value) + len(ping) > 1024:
-                    #         embed.add_field(name=name, value=value, inline=False)
-                    #         answer = f''
-                    #         name = "\u200b"
-                    #     elif
-                    #
-                    #     value += ping
-
-            embed.add_field(name=name, value=value, inline=False)
-            option_ctr += 1
-
-        if message:
-            await message.edit(embed=embed)
-        else:
-            message = await channel.send("", embed=embed)
-
-        if not result:
-            for i in range(0, len(self.answers)):
-                await message.add_reaction(OPTIONS[i])
-
-            await message.add_reaction("🗑️")
-            await message.add_reaction("🛑")
-
-    async def close_poll(self):
-        await self.send_poll(self.message.channel, result=True)
-        await self.delete_poll()
-
-    async def delete_poll(self):
-        await self.message.delete()
-
-    def get_reaction(self, reaction):
-        if self.message:
-            reactions = self.message.reactions
-
-            for react in reactions:
-                if react.emoji == reaction:
-                    return react
diff --git a/requirements.txt b/requirements.txt
index 07ab343..4f3f15e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,10 +1,13 @@
-aiohttp==3.7.4.post0
-async-timeout==3.0.1
-attrs==20.3.0
-chardet==4.0.0
-discord.py==1.6.0
-idna==3.1
-multidict==5.1.0
-python-dotenv==0.16.0
-typing-extensions==3.7.4.3
-yarl==1.6.3
+aiohttp==3.8.3
+aiosignal==1.3.1
+async-timeout==4.0.2
+attrs==22.1.0
+charset-normalizer==2.1.1
+discord.py==2.1.0
+frozenlist==1.3.3
+idna==3.4
+multidict==6.0.3
+peewee==3.15.4
+python-dotenv==0.21.0
+yarl==1.8.2
+twitchio
\ No newline at end of file
diff --git a/roll_cog.py b/roll_cog.py
deleted file mode 100644
index 6bf3111..0000000
--- a/roll_cog.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import random
-
-from discord.ext import commands
-
-
-class RollCog(commands.Cog):
-    def __init__(self, bot):
-        self.bot = bot
-
-    @commands.command(name="roll")
-    async def cmd_roll(self, ctx, dice="w6", qty=1):
-        """ Roll a/multiple dice """
-
-        eyes = int(dice[1:])
-        answer = f"Es wurden {qty} {dice.upper()} geworfen, mit folgenden Ergebnissen:\n"
-        for i in range(qty):
-            answer += f"{i + 1}. Wurf: {random.randrange(1, eyes + 1)}\n"
-
-        await ctx.send(answer)
diff --git a/schedule.py b/schedule.py
deleted file mode 100644
index 5e0f8e8..0000000
--- a/schedule.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import json
-import os
-from datetime import datetime
-
-import discord
-from aiohttp import ClientSession
-from discord.ext import commands, tasks
-
-
-async def get_schedule():
-    async with ClientSession() as session:
-        auth = "kimne78kx3ncx6brgo4mv6wki5h1ko"
-        headers = {"client-id": f"{auth}", "Content-Type": "application/json"}
-
-        async with session.post("https://gql.twitch.tv/gql",
-                                headers=headers,
-                                json={
-                                    "query": "query {\r\n channel(name: \"indiestrolche\") {\r\n schedule {\r\n segments(includeFutureSegments: true) {\r\n id\r\n startAt\r\n title\r\n categories {\r\n displayName\r\n boxArtURL\r\n }\r\n }\r\n }\r\n }\r\n}"}) as r:
-            if r.status == 200:
-                return {segment["id"]: segment for segment in
-                        (await r.json())["data"]["channel"]["schedule"]["segments"]}
-    return None
-
-
-class Schedule(commands.Cog):
-    def __init__(self, bot):
-        self.bot = bot
-        self.update_schedule.start()
-        self.schedule_file = "schedule.json"
-        self.schedule = self.load()
-
-    def load(self):
-        schedule_file = open(self.schedule_file, mode="r")
-        return json.load(schedule_file)
-
-    def save(self):
-        schedule_file = open(self.schedule_file, mode="w")
-        json.dump(self.schedule, schedule_file)
-
-    @tasks.loop(hours=1)
-    async def update_schedule(self):
-        new_schedule = await get_schedule()
-
-        for id, segment in new_schedule.items():
-            if id in self.schedule.keys():
-                old_segment = self.schedule.get(id)
-                if old_segment["startAt"] != segment["startAt"]:
-                    self.schedule[id] = segment
-                    await self.announce_segment(segment, new=False)
-            else:
-                self.schedule[id] = segment
-                await self.announce_segment(segment)
-        self.save()
-
-    async def announce_segment(self, segment, new=True):
-        channel = await self.bot.fetch_channel(int(os.getenv("DURCHSAGEN_CHANNEL")))
-        start_at = datetime.fromisoformat(f"{segment['startAt'][:-1]}+00:00").astimezone().strftime("%d.%m.%Y %H:%M")
-        title = "<:ja:836282702248411217> <:aa:836282738709233675> <:aa:836282738709233675> <:aa:836282738709233675> <:aa:836282738709233675>" if new else "Achtung Leute aufgepasst!!!"
-        description = "Wie geil ist es? Ein neuer Stream ist in den Kalender geglitten\n" if new else "Es gibt eine kleine Änderung im Programmablauf!\n"
-        game = "Lass dich einfach überraschen!"
-        url = "https://static-cdn.jtvnw.net/ttv-static/404_boxart-144x192.jpg"
-        if categories := segment.get("categories"):
-            game = categories[0]['displayName']
-            url = categories[0]['boxArtURL'].replace('-{width}x{height}', '').replace("/./", "/")
-        embed = discord.Embed(title=title, description=description)
-        embed.set_thumbnail(url=url)
-        embed.add_field(name=segment["title"], value=game)
-        embed.add_field(name="Wann?", value=start_at)
-        await channel.send(embed=embed)
diff --git a/strolly.py b/strolly.py
index a77318e..aff9bd3 100644
--- a/strolly.py
+++ b/strolly.py
@@ -1,42 +1,26 @@
 import os
+from typing import List
 
 import discord
 from discord.ext import commands
 from dotenv import load_dotenv
 
-from armin import Armin
-from leaderboard import Leaderboard
-from poll_cog import PollCog
-from roll_cog import RollCog
-from schedule import Schedule
-
 # .env file is necessary in the same directory, that contains several strings.
 load_dotenv()
-TOKEN = os.getenv('DISCORD_TOKEN')
-ACTIVITY = os.getenv('DISCORD_ACTIVITY')
-
-intents = discord.Intents.all()
-bot = commands.Bot(command_prefix='!', help_command=None, activity=discord.Game(ACTIVITY), intents=intents)
-bot.add_cog(PollCog(bot))
-bot.add_cog(RollCog(bot))
-bot.add_cog(Leaderboard(bot))
-bot.add_cog(Armin(bot))
-bot.add_cog(Schedule(bot))
-
 
-@bot.event
-async def on_ready():
-    print("Client started!")
 
+class Strolly(commands.Bot):
+    def __init__(self, *args, initial_extensions: List[str], **kwargs):
+        super(Strolly, self).__init__(*args, **kwargs)
+        self.initial_extensions: List[str] = initial_extensions
 
-@bot.event
-async def on_member_update(before, after):
-    if before.id == 250613346653569025:
-        if after.activity and "Blender" in after.activity.name:
-            if not before.activity or (before.activity and "Blender" not in before.activity.name):
-                channel = await bot.fetch_channel(811980578621620235)
-                await channel.send(
-                    "Achtung <@!490167202625093634>!!! Er tut es schon wieder! Marcus hat gerade die Kultsoftware Blender gestartet!")
+    async def setup_hook(self) -> None:
+        for extension in self.initial_extensions:
+            await self.load_extension(f"extensions.{extension}")
+        await self.tree.sync()
 
 
-bot.run(TOKEN)
+extensions = ["schedule"]
+bot = Strolly(command_prefix="!", help_command=None, activity=discord.Game(os.getenv('DISCORD_ACTIVITY')),
+              intents=discord.Intents.all(), initial_extensions=extensions)
+bot.run(os.getenv('DISCORD_TOKEN'))
diff --git a/utils.py b/utils.py
deleted file mode 100644
index 74c7dc5..0000000
--- a/utils.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import os
-
-import discord
-
-
-async def send_dm(user, message, embed=None):
-    """ Send DM to a user/member """
-
-    if type(user) is discord.User or type(user) is discord.Member:
-        if user.dm_channel is None:
-            await user.create_dm()
-
-        await user.dm_channel.send(message, embed=embed)
-
-
-def is_mod(ctx):
-    author = ctx.author
-    roles = author.roles
-
-    for role in roles:
-        if role.id == int(os.getenv("DISCORD_MOD_ROLE")):
-            return True
-
-    return False
-- 
GitLab