diff --git a/README.md b/README.md index d9820bf..ce0ca5b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,15 @@ Discord bot to give questionable elevator therapy +## Privacy + +This bot does not persistently store any data except for the numerical +IDs of each server it's in, and the numerical ID of the channel it +creates for itself in each server. It does not make use of any data +except for the list of channels. It does not read message +contents. It only creates one channel for itself, and does not +interact at all outside of that channel. + ## Discord setup Required permissions: @@ -9,8 +18,7 @@ Required permissions: - Read messages/view channels - Send messages - -## Setup +## Bot setup git clone https://git.xeno.science/xenofem/mikage-bot cd mikage-bot diff --git a/bot.py b/bot.py index 3895324..faa1396 100644 --- a/bot.py +++ b/bot.py @@ -1,18 +1,31 @@ -import discord - import asyncio import json +import random import sys +import discord + STATE_FILE = 'state.json' CHANNEL_NAME = 'therapy-elevator' -DELETION_SECONDS = 300 +DELETION_SECONDS = 15 +TYPING_DELAY = 2 SETUP_MESSAGE = 'Welcome to Nemuro Memorial Hall. Please give your name and class year for our records.' INITIAL_MESSAGE = 'All right, please begin.' -BUTTERFLIES = ['🦋', '🥐', 'Deeper. Go deeper.' '🐛', '🍃'] +BUTTERFLIES = ['🦋', 'Deeper. Go deeper.', '🥐', '🐛', '🥚', '🍃'] +ELEVATOR_SHIT_PERIOD = 5 +ELEVATOR_SHIT = [ + '*the elevator creaks eerily*', + '*menacing discordant music plays*', + '*drawers rush past on the walls outside*', + '*the lights flicker*', + '*the elevator jolts, then continues its descent*', + '*a rattling. the elevator begins to shake*', + '*a squealing of cables and pulleys*', +] +CRASH = ('|\n'*10) + '***the elevator crashes to the bottom***' + ('\n'*10) + '...' FINAL_MESSAGE = 'I understand. Your only choice is to revolutionize the world. The path you must take has been prepared for you.' -ROSE = '🌹' +ROSE = '🌹💍' async def try_send(channel, message): try: @@ -20,6 +33,13 @@ async def try_send(channel, message): except discord.DiscordException as e: print(f"error sending message in channel {channel}: {e}", file=sys.stderr) +async def try_move(channel, **kwargs): + try: + await channel.move(**kwargs) + except discord.DiscordException as e: + print(f"error moving channel {channel}: {e}", file=sys.stderr) + await try_send(channel, "Dammit, the elevator's stuck!") + def text_only(channels): return [channel for channel in channels if isinstance(channel, discord.TextChannel)] @@ -27,18 +47,19 @@ class MikageClient(discord.Client): def __init__(self): super().__init__() try: - with open(STATE_FILE) as f: + with open(STATE_FILE, encoding='utf-8') as f: self.state = json.load(f) - except: + except FileNotFoundError: self.state = {} self.save_state() def save_state(self): - with open(STATE_FILE, 'w') as f: + with open(STATE_FILE, 'w', encoding='utf-8') as f: json.dump(self.state, f) async def on_ready(self): print(f"logged in as {self.user}", file=sys.stderr) + await self.change_presence(activity=discord.Game('the dueling game, for keeps')) for guild in self.guilds: await self.initialize_elevator(guild) @@ -51,8 +72,12 @@ class MikageClient(discord.Client): if guild_id in self.state and guild.get_channel(self.state[guild_id]['channel']) is not None: return try: - (top_category, channels) = guild.by_category()[0] - channel = await guild.create_text_channel(CHANNEL_NAME, category=top_category) + top_category = guild.by_category()[0][0] + channel = await guild.create_text_channel( + CHANNEL_NAME, + category=top_category, + topic="the he/they therapist - you know, the one who lives in the morgue in the basement of that building that doesn't exist? - is in" + ) await channel.move(category=top_category, beginning=True) self.state[guild_id] = {'channel': channel.id} self.save_state() @@ -78,39 +103,34 @@ class MikageClient(discord.Client): if category_index == 0 and channel_index == 0: await try_send(message.channel, INITIAL_MESSAGE) - if channel_index == len(channels) - 1: - if category_index == len(categories) - 1: - return - target_category = categories[category_index+1][0] - target_position = 0 - else: - target_category = category - target_position = channel_index+1 - try: - await message.channel.move(category=target_category, beginning=True, offset=target_position) - except discord.DiscordException as e: - print(f"error moving channel {message.channel} in guild {message.guild}: {e}", file=sys.stderr) - await try_send(message.channel, "Dammit, the elevator's stuck!") + if category_index == len(categories) - 1: return - - if target_position == 0: - await try_send(message.channel, BUTTERFLIES[int(category_index*len(BUTTERFLIES)/(len(categories)-1))]) - - final_category_channels = text_only(message.guild.by_category()[-1][1]) - if len(final_category_channels) > 0 and message.channel == final_category_channels[-1]: - await try_send(message.channel, FINAL_MESSAGE) - await try_send(message.channel, ROSE) - await asyncio.sleep(DELETION_SECONDS) - try: - await message.channel.delete() - del self.state[guild_id] - self.save_state() - except discord.DiscordException as e: - print(f"error deleting elevator for guild {message.guild}: {e}", file=sys.stderr) + if channel_index == len(channels) - 1: + if category_index == len(categories) - 2: + await message.channel.move(category=categories[-1][0], end=True) + await try_send(message.channel, CRASH) + await asyncio.sleep(TYPING_DELAY) + await try_send(message.channel, FINAL_MESSAGE) + await asyncio.sleep(TYPING_DELAY) + await try_send(message.channel, ROSE) + await asyncio.sleep(DELETION_SECONDS) + try: + await message.channel.delete() + del self.state[guild_id] + self.save_state() + except discord.DiscordException as e: + print(f"error deleting elevator for guild {message.guild}: {e}", file=sys.stderr) + return + await self.initialize_elevator(message.guild) return - await self.initialize_elevator(message.guild) + await try_move(message.channel, category=categories[category_index+1][0], beginning=True) + await try_send(message.channel, BUTTERFLIES[int(category_index*len(BUTTERFLIES)/(len(categories)-2))]) + else: + await try_move(message.channel, category=category, beginning=True, offset=channel_index+1) + if random.randrange(ELEVATOR_SHIT_PERIOD) == 0: + await try_send(message.channel, random.choice(ELEVATOR_SHIT)) client = MikageClient() -with open('token') as f: +with open('token', encoding='utf-8') as f: token = f.read().strip() client.run(token)