diff options
-rw-r--r-- | bot.py | 53 | ||||
-rw-r--r-- | commands.py | 46 | ||||
-rw-r--r-- | config.py | 5 |
3 files changed, 88 insertions, 16 deletions
@@ -16,6 +16,7 @@ class Cupido(commands.Bot): super().__init__(*args, **kwargs) self.meta_channel = None self.lobby_channel = None + self.notify_channel = None self.pair_channels = [] self.task = None self.reaction_map = {} @@ -82,6 +83,37 @@ class Cupido(commands.Bot): await answer(ctx, f'info: voice channel created "{lobby}" ({lobby.id})') return lobby + async def create_notify_channel(self, ctx): + channel = await ctx.guild.create_text_channel( + config.NOTIFY_CHANNEL_NAME, + category=self.meta_channel, + topic=config.NOTIFY_CHANNEL_TOPIC, + overwrites={ + self.user: discord.PermissionOverwrite( + add_reactions=True, + send_messages=True, + mention_everyone=True, + manage_roles=True, + manage_permissions=True, + manage_messages=True, + manage_channels=True, + read_messages=True, + read_message_history=True, + embed_links=True, + ), + ctx.guild.default_role: discord.PermissionOverwrite( + add_reactions=False, + send_messages=False, + send_tts_messages=False, + embed_links=False, + attach_files=False, + mention_everyone=False, + ), + } + ) + await answer(ctx, f'info: text channel created "{channel}" ({channel.id})') + return channel + def get_meta_channel(self, ctx): return self.meta_channel or discord.utils.get(ctx.guild.categories, name=config.CATEGORY_CHANNEL_NAME) @@ -93,6 +125,14 @@ class Cupido(commands.Bot): category=meta_channel )) + def get_notify_channel(self, ctx, meta_channel): + return (self.notify_channel + or discord.utils.get( + ctx.guild.text_channels, + name=config.NOTIFY_CHANNEL_NAME, + category=meta_channel + )) + def get_pair_channels_no_cache(self, ctx, meta_channel): return sorted((channel for channel in ctx.guild.voice_channels if channel.category == meta_channel @@ -157,7 +197,8 @@ class Cupido(commands.Bot): futures = [] for i in range(1, n + 1): futures.append(self.create_voice_channel(ctx, str(i), category=meta_channel)) - return await await_n(futures) + channels = await await_n(futures) + return channels async def get_channels(self, ctx, msg=True): meta_channel = self.get_meta_channel(ctx) @@ -246,6 +287,16 @@ class Cupido(commands.Bot): embed = discord.Embed(title=title, type="rich", description=text, colour=color) await (await channel).send(embed=embed) + async def print_scoreboard(self, ctx, target): + text = config.SCOREBOARD_TEXT + scores = [i for i in self.score_map.items()] + scores = sorted(scores, reverse=True, key=lambda i: i[1]) + for n, (member, score) in enumerate(scores): + if score > 0: + text += f'\n {n+1}. {self.get_username(member)} hat {score} Punkt{"" if score == 1 else "e"}' + embed = discord.Embed(title=config.SCOREBOARD_TITLE, type="rich", description=text, colour=discord.Colour.purple()) + await target.send(embed=embed) + def main(): token = getenv(config.TOKEN_ENV_VAR) diff --git a/commands.py b/commands.py index 92a1dd9..ff0c894 100644 --- a/commands.py +++ b/commands.py @@ -8,8 +8,15 @@ import discord from discord.ext import commands +async def try_await(future): + try: + return await future + except Exception as e: + print(f'error occured: {e}') + + async def await_n(it) -> List[Any]: - lst = [asyncio.create_task(task) for task in it] + lst = [asyncio.create_task(try_await(task)) for task in it] if not lst: return [] done, _ = await asyncio.wait(lst) @@ -32,7 +39,8 @@ async def get_members(guild, channel): futures.append(guild.fetch_member(i)) else: insts.append(inst) - return insts + await await_n(futures) + members = insts + await await_n(futures) + return members @commands.command(help='display this help message', aliases=('hepl', 'h', '?')) @@ -50,6 +58,7 @@ async def init(ctx: commands.Context): if not is_admin_channel(ctx): return ctx.bot.meta_channel = ctx.bot.get_meta_channel(ctx) or await ctx.bot.create_category(ctx) ctx.bot.lobby_channel = ctx.bot.get_lobby_channel(ctx, ctx.bot.meta_channel) or await ctx.bot.create_lobby(ctx) + ctx.bot.notify_channel = ctx.bot.get_notify_channel(ctx, ctx.bot.meta_channel) or await ctx.bot.create_notify_channel(ctx) @commands.command(help=f'destruct all {config.NAME} channels', aliases=('kill', 'desctruction', 'genocide', '-')) @@ -164,10 +173,17 @@ async def stop(ctx: commands.Context, cancel_loop=True): await ctx.bot.destroy_pair_channels(ctx, meta_channel) -async def loop_cycle(ctx, t, g, isfirst, islast): +async def loop_cycle(ctx, t, nt, g, isfirst, islast): if not await shuffle(ctx, g, frompairchannels=not isfirst): return False - await asyncio.sleep(t) + if nt >= t: + await asyncio.sleep(t) + else: + await asyncio.sleep(nt) + notify_channel = ctx.bot.get_notify_channel(ctx, ctx.bot.get_meta_channel(ctx)) + embed = discord.Embed(title=f"Noch {nt} Sekunden", type="rich", description="", colour=discord.Colour.blue()) + await notify_channel.send(embed=embed) + await asyncio.sleep(t - nt) await ctx.bot.update_scores(ctx.guild) if islast: await stop(ctx, cancel_loop=False) @@ -178,7 +194,7 @@ async def loop_cycle(ctx, t, g, isfirst, islast): help=f'repeat "shuffle" and "stop" <n> (default: {config.DEFAULT_LOOP_COUNT}) times and <t>' f' (default: {config.DEFAULT_LOOP_TIME}) seconds', aliases=('repeat', 'shuffleloop')) -async def loop(ctx: commands.Context, n=config.DEFAULT_LOOP_COUNT, t=config.DEFAULT_LOOP_TIME, g=3): +async def loop(ctx: commands.Context, n=config.DEFAULT_LOOP_COUNT, t=config.DEFAULT_LOOP_TIME, nt=config.DEFAULT_NOTIFY_TIME, g=3): if not is_admin_channel(ctx): return try: n, t = int(n), int(t) @@ -187,7 +203,7 @@ async def loop(ctx: commands.Context, n=config.DEFAULT_LOOP_COUNT, t=config.DEFA return await answer(ctx, f'repeat shuffling {n} times and each {t} seconds') for i in range(n): - result = await ctx.bot.await_coroutine(loop_cycle(ctx, t, g, i == 0, i == n-1)) + result = await ctx.bot.await_coroutine(loop_cycle(ctx, t, nt, g, i == 0, i == n-1)) message = { 'cancelled': 'cancelled loop command', 'already running': 'cannot start loop, another task is running...' @@ -252,14 +268,16 @@ async def list(ctx: commands.Context): aliases=('scores', 'score', 'points') ) async def scoreboard(ctx: commands.Context): - text = config.SCOREBOARD_TEXT - scores = [i for i in ctx.bot.score_map.items()] - scores = sorted(scores, reverse=True, key=lambda i: i[1]) - for n, (member, score) in enumerate(scores): - if score > 0: - text += f'\n {n+1}. {ctx.bot.get_username(member)} hat {score} Punkt{"" if score == 1 else "e"}' - embed = discord.Embed(title=config.SCOREBOARD_TITLE, type="rich", description=text, colour=discord.Colour.purple()) - await ctx.send(embed=embed) + await ctx.bot.print_scoreboard(ctx, ctx) + + +@commands.command( + help='notify the scoreboard', + aliases=('notify',) +) +async def notifyscoreboard(ctx: commands.Context): + if is_admin_channel(ctx): + await ctx.bot.print_scoreboard(ctx, ctx.bot.get_notify_channel(ctx, ctx.bot.get_meta_channel(ctx))) @commands.command( @@ -14,11 +14,14 @@ This software is open-source https://git.kobert.dev/lovefinderrz.git/ CATEGORY_CHANNEL_NAME = 'KENNENLERNEN' LOBBY_CHANNEL_NAME = 'Lobby' +NOTIFY_CHANNEL_NAME = 'notify' +NOTIFY_CHANNEL_TOPIC = f'Hier siehst du Nachrichten des {NAME.title()}s' # time that one loop cycle needs (in seconds) DEFAULT_LOOP_TIME = 3 * 60 +DEFAULT_NOTIFY_TIME = 3 * 60 - 20 # time that cycles, that "loop" passes -DEFAULT_LOOP_COUNT = 3 +DEFAULT_LOOP_COUNT = 18 EMOJI_POOL = ['👾', '🤖', '👻', '🦧', '🍴', '🎮', '🎷', '😈', '🦄', '🐮', '🌻', '🐘', '🍕', '🦉'] PANEL_TITLE = 'Wer ist Tutor?' |