Compare commits

..

No commits in common. "main" and "ac87fa9b9046a70d3bcdce2b04e5d7cb0c42d4f4" have entirely different histories.

2 changed files with 41 additions and 69 deletions

View file

@ -2,15 +2,6 @@
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:
@ -18,7 +9,8 @@ Required permissions:
- Read messages/view channels
- Send messages
## Bot setup
## Setup
git clone https://git.xeno.science/xenofem/mikage-bot
cd mikage-bot

98
bot.py
View file

@ -1,31 +1,18 @@
import discord
import asyncio
import json
import random
import sys
import discord
STATE_FILE = 'state.json'
CHANNEL_NAME = 'therapy-elevator'
DELETION_SECONDS = 15
TYPING_DELAY = 2
DELETION_SECONDS = 300
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.', '🥐', '🐛', '🥚', '🍃']
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) + '...'
BUTTERFLIES = ['🦋', '🥐', 'Deeper. Go deeper.' '🐛', '🍃']
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:
@ -33,13 +20,6 @@ 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)]
@ -47,19 +27,18 @@ class MikageClient(discord.Client):
def __init__(self):
super().__init__()
try:
with open(STATE_FILE, encoding='utf-8') as f:
with open(STATE_FILE) as f:
self.state = json.load(f)
except FileNotFoundError:
except:
self.state = {}
self.save_state()
def save_state(self):
with open(STATE_FILE, 'w', encoding='utf-8') as f:
with open(STATE_FILE, 'w') 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)
@ -72,12 +51,8 @@ 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 = 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"
)
(top_category, channels) = guild.by_category()[0]
channel = await guild.create_text_channel(CHANNEL_NAME, category=top_category)
await channel.move(category=top_category, beginning=True)
self.state[guild_id] = {'channel': channel.id}
self.save_state()
@ -103,34 +78,39 @@ class MikageClient(discord.Client):
if category_index == 0 and channel_index == 0:
await try_send(message.channel, INITIAL_MESSAGE)
if category_index == len(categories) - 1:
return
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)
if category_index == len(categories) - 1:
return
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))])
target_category = categories[category_index+1][0]
target_position = 0
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))
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!")
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)
return
await self.initialize_elevator(message.guild)
client = MikageClient()
with open('token', encoding='utf-8') as f:
with open('token') as f:
token = f.read().strip()
client.run(token)