From 24af20e7707aebafc129743f9046777ec20e1c7c Mon Sep 17 00:00:00 2001 From: Zac Herd Date: Thu, 5 May 2016 21:27:00 +0100 Subject: [PATCH] Updated for new discord.py features, removed tells, removed bentracker, multiple bug fixes and improvements, v0.15.0 --- bot.py | 165 +++++++++++++++++++++-------------------------------------------- 1 file changed, 53 insertions(+), 112 deletions(-) diff --git a/bot.py b/bot.py index b9df63d..2286e8d 100644 --- a/bot.py +++ b/bot.py @@ -5,6 +5,7 @@ # Copyright 2016 Zac Herd # Licensed under BSD 3-clause License, see LICENSE.md for more info + # IMPORTS import discord import asyncio @@ -14,6 +15,7 @@ import sys import time import datetime import random +import re import json import logging @@ -29,7 +31,7 @@ from secret import token name = "Maki" # bot version -version = "v0.13.1" +version = "v0.15.0" # text shown by .help command helptext = """I am a bot written in Python by MrDetonia @@ -47,6 +49,7 @@ My commands are: .say - say something .sayy - say something a e s t h e t i c a l l y .markov - generate sentence using markov chains over a user's chat history +.roll d - roll x number of y sided dice ```""" # IDs of admin users @@ -55,13 +58,8 @@ admins = ['116883900688629761'] # default posting channel def_chan = '116884620032606215' -# GLOBALS -# number of times Ben has mentioned his meme boards -bentrack = {'ck':0, 'fit':0} -if os.path.isfile('bentrack.json'): - with open('bentrack.json', 'r') as fp: - bentrack = json.load(fp) +# GLOBALS # log of users' last messages and timestamps history = {} @@ -75,12 +73,6 @@ if os.path.isfile('welcomes.json'): with open('welcomes.json', 'r') as fp: welcomes = json.load(fp) -# seen users and IDs -users = {} -if os.path.isfile('users.json'): - with open('users.json', 'r') as fp: - users = json.load(fp) - # messages left for users tells = {} if os.path.isfile('tells.json'): @@ -90,9 +82,6 @@ if os.path.isfile('tells.json'): # this instance of the Discord client client = discord.Client() -# are we running? -run = True - # logging setup logger = logging.getLogger('discord') logger.setLevel(logging.DEBUG) @@ -100,6 +89,7 @@ handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w' handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) logger.addHandler(handler) + # FUNCTIONS # converts a datetime to a string @@ -132,72 +122,32 @@ def on_ready(): def on_member_update(before, after): # display welcome message if user comes online: if before.status == discord.Status.offline and after.status == discord.Status.online: - if after.name in welcomes: + if after.id in welcomes: # print custom welcome - yield from client.send_message(client.get_channel(def_chan), welcomes[after.name]) + yield from client.send_message(client.get_channel(def_chan), welcomes[after.id]) else: yield from client.send_message(client.get_channel(def_chan), after.name + ' is now online') - # track usernames and IDs: - if after.name not in users: - # store user ID - users[after.name] = after.id - - # delete old entry if username changed - if after.name != before.name: - try: - users.pop(before.name, None) - except KeyError: - pass - - # update JSON file - with open('users.json', 'w') as fp: - json.dump(users, fp) - # called when message received @client.event @asyncio.coroutine def on_message(message): # print messages to terminal for info - print(message.author.name + ': ' + message.content) - - # ensure we store this user's ID - if message.author.name not in users: - users[message.author.name] = message.author.id - - # update JSON file - with open('users.json', 'w') as fp: - json.dump(users, fp) + try: + print(message.server.name + '-' + message.channel.name + '-' + message.author.name + ': ' + message.content) + except AttributeError: + print('PRIV-' + message.author.name + ': ' + message.content) # do not parse own messages or private messages if message.author != client.user and type(message.channel) is not discord.PrivateChannel: # response to send to channel response = '' - # send any messages we have for author: - if message.author.name in tells: - for msg in tells[message.author.name]: - for attempt in range(5): - try: - yield from client.send_message(message.author, msg[0] + ' says "' + msg[1] + '"') - except discord.errors.HTTPException: - continue - else: - break - else: - print('ERROR: Failed to send private message after 5 attempts') - - # delete this user's entry - del tells[message.author.name] - - # update messages - with open('tells.json', 'w') as fp: - json.dump(tells, fp) - # parse messages for commands if message.content.startswith('.info'): # print bot info - response = 'I am ' + name + ', a Discord bot by MrDetonia | ' + version + ' | Python 3.4 | discord.py ' + discord.__version__ + pyver = str(sys.version_info[0]) + '.' + str(sys.version_info[1]) + '.' + str(sys.version_info[2]) + response = 'I am ' + name + ', a Discord bot by MrDetonia | ' + version + ' | Python ' + pyver + ' | discord.py ' + discord.__version__ elif message.content.startswith('.help'): # print command list @@ -225,20 +175,21 @@ def on_message(message): elif message.content.startswith('.whois '): # show info about another user tmp = message.content[7:] - if tmp in users: - user = message.server.get_member(users[tmp]) - response = 'User: ' + user.name + ' ID: ' + user.id + ' Discriminator: ' + user.discriminator + '\nAccount Created: ' + strfromdt(user.created_at) + user = message.server.get_member_named(tmp) + if user == None: + response = 'I can\'t find ' + tmp else: - response = 'I haven\'t seen ' + tmp + ' yet! :(' + response = 'User: ' + user.name + ' ID: ' + user.id + ' Discriminator: ' + user.discriminator + '\nAccount Created: ' + strfromdt(user.created_at) elif message.content.startswith('.welcome '): # manage welcome messages if message.author.id in admins: tmp = message.content[9:].split(' ',1) - welcomes[tmp[0]] = tmp[1] - response = 'Okay, I will now greet ' + tmp[0] + ' with "' + tmp[1] + '"' + target = message.server.get_member(tmp[0]).id + welcomes[target] = tmp[1] + response = 'Okay, I will now greet ' + message.server.get_member(target).name + ' with "' + tmp[1] + '"' else: - welcomes[message.author.name] = message.content[9:] + welcomes[message.author.id] = message.content[9:] response = 'Okay, I will now greet ' + message.author.name + ' with "' + message.content[9:] + '"' # save welcomes @@ -247,7 +198,8 @@ def on_message(message): elif message.content.startswith('.seen '): # print when user was last seen - target = users[message.content[6:]] + target = message.server.get_member_named(message.content[6:]).id + if target in history: # user logged, print last message and time response = 'user ' + message.content[6:] + ' was last seen saying "' + history[target][0] + '" at ' + strfromdt(dtfromts(history[target][1])) @@ -258,21 +210,6 @@ def on_message(message): # user not logged response = 'user not seen yet' - elif message.content.startswith('.tell '): - # store message to tell user - tmp = message.content[6:].split(' ',1) - try: - tells[tmp[0]].append((message.author.name, tmp[1])) - except (NameError, KeyError): - tells[tmp[0]] = [(message.author.name, tmp[1])] - - # save messages - with open('tells.json', 'w') as fp: - json.dump(tells, fp) - - # let user know message is ready - response = 'Okay ' + message.author.name + ', I\'ll tell ' + tmp[0] + ' when I next see them!' - elif message.content.startswith('.say '): # delete calling message for effect yield from client.delete_message(message) @@ -299,14 +236,36 @@ def on_message(message): # generate a markov chain sentence based on the user's chat history tmp = message.content[8:] - if tmp in users and os.path.isfile('./markovs/' + users[tmp]): - mc = markov.Markov(open('./markovs/' + users[tmp])) - try: - response = mc.generate_text(random.randint(20,40)) - except KeyError: - response = 'Something went wrong :( Maybe you haven\'t spoken enough yet?' + target = message.server.get_member_named(tmp).id + if os.path.isfile('./markovs/' + target): + mc = markov.Markov(open('./markovs/' + target)) + response = mc.generate_text(random.randint(20,40)) else: - response = 'I haven\'t seen that user speak yet!' + response = 'I haven\'t seen them speak yet!' + + elif message.content.startswith('.roll '): + # DnD style dice roll + tmp = message.content[6:] + + #check syntax is valid + pattern = re.compile('^([0-9]+)d([0-9]+)$') + + if pattern.match(tmp): + # extract numbers + nums = [int(s) for s in re.findall(r'\d+', message.content)] + + # limit range + if nums[0] > 100: nums[0] = 100 + if nums[1] > 1000000: nums[1] = 1000000 + + # roll dice multiple times and sum + rollsum = 0 + for i in range(nums[0]): + rollsum += random.randint(1, nums[1]) + + response = 'You rolled: ' + str(rollsum) + else: + response = 'you did it wrong!' # Stuff that happens when message is not a bot command: else: @@ -322,21 +281,6 @@ def on_message(message): with open('./markovs/' + message.author.id, 'a') as fp: fp.write('\n' + message.content) - # Ben meme trackers - if '/ck/' in message.content and message.author.name == "Ben.H": - bentrack['ck'] += 1 - response = 'I have seen Ben reference /ck/ ' + str(bentrack['ck']) + ' times now.' - # save count - with open('bentrack.json', 'w') as fp: - json.dump(bentrack, fp) - - elif '/fit/' in message.content and message.author.name == "Ben.H": - bentrack['fit'] += 1 - response = 'I have seen Ben reference /fit/ ' + str(bentrack['fit']) + ' times now.' - # save count - with open('bentrack.json', 'w') as fp: - json.dump(bentrack, fp) - # send response to channel if needed: if response is not '': for attempt in range(5): @@ -349,9 +293,6 @@ def on_message(message): else: print('ERROR: Failed to send message to discord after 5 attempts') -# Setup stdout encoding -sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding=sys.stdout.encoding, errors="backslashreplace", line_buffering=True) - # Run the client client.run(token)