diff --git a/admincommands.py b/admincommands.py index 0b6c7cf..2672afe 100644 --- a/admincommands.py +++ b/admincommands.py @@ -5,8 +5,6 @@ # Copyright 2018 Zac Herd # Licensed under BSD 3-clause License, see LICENSE.md for more info - - # IMPORTS import os import asyncio @@ -14,60 +12,59 @@ import subprocess import discord import urllib.request - # LOCAL IMPORTS from common import * from helpers import * - # COMMAND IMPLEMENTATINS @asyncio.coroutine def cmd_die(client, msg): - print("INFO: accepting .die from " + msg.author.name) - yield from client.send_message(msg.channel, "But will I dream? ;-;") - yield from client.logout() + print("INFO: accepting .die from " + msg.author.name) + yield from client.send_message(msg.channel, "But will I dream? ;-;") + yield from client.logout() - if msg.content[5:] == "reload": - # touch file to signal reload - with open("reload", "a"): - os.utime("reload", None) + if msg.content[5:] == "reload": + # touch file to signal reload + with open("reload", "a"): + os.utime("reload", None) @asyncio.coroutine def cmd_quiet(client, msg): - quiet[msg.server.id] = 1 + quiet[msg.server.id] = 1 @asyncio.coroutine def cmd_loud(client, msg): - if msg.server.id in quiet: - quiet.pop(msg.server.id, None) + if msg.server.id in quiet: + quiet.pop(msg.server.id, None) @asyncio.coroutine def cmd_avatar(client, msg): - url = msg.content[8:] - response = "Avatar updated!" - try: - httpresponse = urllib.request.urlopen(url) - imgdata = httpresponse.read() - yield from client.edit_profile(avatar=imgdata) - except urllib.error.URLError as e: - response = "URL Error: " + str(e) - except discord.HTTPException: - response = "Dicsord failed to edit my profile!" - except discord.InvalidArgument: - response = "Invalid image!" - except: - response = "Error updating avatar!" + url = msg.content[8:] + response = "Avatar updated!" + try: + httpresponse = urllib.request.urlopen(url) + imgdata = httpresponse.read() + yield from client.edit_profile(avatar=imgdata) + except urllib.error.URLError as e: + response = "URL Error: " + str(e) + except discord.HTTPException: + response = "Dicsord failed to edit my profile!" + except discord.InvalidArgument: + response = "Invalid image!" + except: + response = "Error updating avatar!" + + yield from discord_send(client, msg, response) - yield from discord_send(client, msg, response) # COMMAND HANDLING admincommands = { - "die": cmd_die, - "quiet": cmd_quiet, - "loud": cmd_loud, - "avatar": cmd_avatar, + "die": cmd_die, + "quiet": cmd_quiet, + "loud": cmd_loud, + "avatar": cmd_avatar, } diff --git a/bot.py b/bot.py index a4e9c67..ff1cd98 100644 --- a/bot.py +++ b/bot.py @@ -1,4 +1,3 @@ - # Maki # ---- # Discord bot by MrDetonia @@ -6,8 +5,6 @@ # Copyright 2018 Zac Herd # Licensed under BSD 3-clause License, see LICENSE.md for more info - - # IMPORTS import discord import asyncio @@ -33,7 +30,6 @@ from admincommands import * # file in this directory called "secret.py" should contain these variables from secret import token, lfmkey, steamkey - # DISCORD CLIENT INSTANCE client = discord.Client() @@ -43,60 +39,68 @@ client = discord.Client() @client.event @asyncio.coroutine def on_ready(): - # info on terminal - print('Connected') - print('User: ' + client.user.name) - print('ID: ' + client.user.id) + # info on terminal + print('Connected') + print('User: ' + client.user.name) + print('ID: ' + client.user.id) - # set "Now Playing" to print version - game = discord.Game(name = version) - yield from client.change_presence(game=game) + # set "Now Playing" to print version + game = discord.Game(name=version) + yield from client.change_presence(game=game) # called when message received @client.event @asyncio.coroutine def on_message(msg): - # print messages to terminal for info - timestr = time.strftime('%Y-%m-%d-%H:%M:%S: ') - try: - print("{} {} - {} | {}: {}".format(timestr, msg.server.name, msg.channel.name, msg.author.name, msg.content)) - except AttributeError: - print("{} PRIVATE | {}: {}".format(timestr, msg.author.name, msg.content)) - - # do not parse own messages or private messages - if msg.author != client.user and type(msg.channel) is not discord.PrivateChannel: - # log each message against users - if msg.content != "": - history[msg.server.id + msg.author.id] = (msg.server.id, time.time(), msg.content) - with open('hist.json', 'w') as fp: - json.dump(history, fp) - - # log user messages for markov chains, ignoring messages with certain substrings - filters = ['`', 'http://', 'https://'] - if not any(x in msg.content for x in filters): - try: - with open('./markovs/' + msg.server.id + '-' + msg.author.id, 'a') as fp: - fp.write('\n' + msg.content) - except PermissionError: pass - - # react to stuff - yield from makireacts(client, msg) - - # check for commands - if msg.content.startswith(prefix): - cmd = msg.content.split(' ', 1)[0][1:] - if cmd in commands: - yield from commands[cmd](client, msg) - elif cmd in admincommands and msg.author.id in admins: - yield from admincommands[cmd](client, msg) + # print messages to terminal for info + timestr = time.strftime('%Y-%m-%d-%H:%M:%S: ') + try: + print("{} {} - {} | {}: {}".format(timestr, msg.server.name, + msg.channel.name, msg.author.name, + msg.content)) + except AttributeError: + print("{} PRIVATE | {}: {}".format(timestr, msg.author.name, + msg.content)) + + # do not parse own messages or private messages + if msg.author != client.user and type( + msg.channel) is not discord.PrivateChannel: + # log each message against users + if msg.content != "": + history[msg.server.id + msg.author.id] = (msg.server.id, + time.time(), msg.content) + with open('hist.json', 'w') as fp: + json.dump(history, fp) + + # log user messages for markov chains, ignoring messages with certain substrings + filters = ['`', 'http://', 'https://'] + if not any(x in msg.content for x in filters): + try: + with open('./markovs/' + msg.server.id + '-' + msg.author.id, + 'a') as fp: + fp.write('\n' + msg.content) + except PermissionError: + pass + + # react to stuff + yield from makireacts(client, msg) + + # check for commands + if msg.content.startswith(prefix): + cmd = msg.content.split(' ', 1)[0][1:] + if cmd in commands: + yield from commands[cmd](client, msg) + elif cmd in admincommands and msg.author.id in admins: + yield from admincommands[cmd](client, msg) # MAIN FUNCTION def main(): - logger() - client.run(token) - exit(0) + logger() + client.run(token) + exit(0) + if __name__ == "__main__": - main() + main() diff --git a/commands.py b/commands.py index 12d46a7..5979f7d 100755 --- a/commands.py +++ b/commands.py @@ -5,8 +5,6 @@ # Copyright 2018 Zac Herd # Licensed under BSD 3-clause License, see LICENSE.md for more info - - # IMPORTS import asyncio import os @@ -16,7 +14,6 @@ import requests import random import subprocess - # LOCAL IMPORTS from common import * from helpers import * @@ -24,25 +21,26 @@ from secret import lfmkey, steamkey import markov - # COMMAND IMPLEMENTATIONS @asyncio.coroutine def cmd_help(client, msg): - yield from discord_send(client, msg, helptext) + yield from discord_send(client, msg, helptext) @asyncio.coroutine def cmd_info(client, msg): - pyver = "{}.{}.{}".format(sys.version_info[0], sys.version_info[1], sys.version_info[2]) - appinfo = yield from client.application_info() - response = "I am **{}**, a Discord bot by **{}** | `{}` | Python `{}` | discord.py `{}`".format(appinfo.name, appinfo.owner.name, version, pyver, discord.__version__) - yield from discord_send(client, msg, response) + pyver = "{}.{}.{}".format(sys.version_info[0], sys.version_info[1], + sys.version_info[2]) + appinfo = yield from client.application_info() + response = "I am **{}**, a Discord bot by **{}** | `{}` | Python `{}` | discord.py `{}`".format( + appinfo.name, appinfo.owner.name, version, pyver, discord.__version__) + yield from discord_send(client, msg, response) @asyncio.coroutine def cmd_upskirt(client, msg): - response = "No, don\'t look at my pantsu, baka! " - yield from discord_send(client, msg, response) + response = "No, don\'t look at my pantsu, baka! " + yield from discord_send(client, msg, response) whoistring = "**{}#{}**: `{}`\n**Account Created:** `{}`" @@ -50,267 +48,301 @@ whoistring = "**{}#{}**: `{}`\n**Account Created:** `{}`" @asyncio.coroutine def cmd_whoami(client, msg): - response = whoistring.format(msg.author.name, msg.author.discriminator, msg.author.id, strfromdt(msg.author.created_at)) - yield from discord_send(client, msg, response) + response = whoistring.format(msg.author.name, + msg.author.discriminator, msg.author.id, + strfromdt(msg.author.created_at)) + yield from discord_send(client, msg, response) @asyncio.coroutine def cmd_whois(client, msg): - tmp = msg.content[7:] - user = msg.server.get_member_named(tmp) + tmp = msg.content[7:] + user = msg.server.get_member_named(tmp) - if user == None: - reponse = "I can't find `{}`".format(tmp) - else: - response = whoistring.format(user.name, user.discriminator, user.id, strfromdt(user.created_at)) + if user == None: + reponse = "I can't find `{}`".format(tmp) + else: + response = whoistring.format(user.name, user.discriminator, user.id, + strfromdt(user.created_at)) - yield from discord_send(client, msg, response) + yield from discord_send(client, msg, response) @asyncio.coroutine def cmd_seen(client, msg): - tmp = msg.content[6:] - user = msg.server.get_member_named(tmp) + tmp = msg.content[6:] + user = msg.server.get_member_named(tmp) - if user == None: - reponse = "I can't find `{}`".format(tmp) - elif user.name == "Maki": - reponse = "I'm right here!" - else: - target = msg.server.id + user.id - if target in history and history[target][0] == msg.server.id: - response = "**{}** was last seen saying the following at {}:\n{}".format(user.name, strfromdt(dtfromts(history[target][1])), history[target][2]) - else: - response = "I haven't seen **{}** speak yet!".format(tmp) + if user == None: + reponse = "I can't find `{}`".format(tmp) + elif user.name == "Maki": + reponse = "I'm right here!" + else: + target = msg.server.id + user.id + if target in history and history[target][0] == msg.server.id: + response = "**{}** was last seen saying the following at {}:\n{}".format( + user.name, strfromdt(dtfromts(history[target][1])), + history[target][2]) + else: + response = "I haven't seen **{}** speak yet!".format(tmp) - yield from discord_send(client, msg, response) + yield from discord_send(client, msg, response) @asyncio.coroutine def cmd_say(client, msg): - response = msg.content[5:] - yield from client.delete_message(msg) - yield from discord_send(client, msg, response) + response = msg.content[5:] + yield from client.delete_message(msg) + yield from discord_send(client, msg, response) @asyncio.coroutine def cmd_sayy(client, msg): - response = " ".join(msg.content[6:]) - yield from client.delete_message(msg) - yield from discord_send(client, msg, response) + response = " ".join(msg.content[6:]) + yield from client.delete_message(msg) + yield from discord_send(client, msg, response) @asyncio.coroutine def cmd_markov(client, msg): - yield from discord_typing(client, msg) - - tmp = msg.content[8:] - target = "" - - if tmp == "Maki": - response = "My markovs always say the same thing" - else: - if tmp == "": - target = "{}-{}".format(msg.server.id, msg.author.id) - else: - try: - target = "{}-{}".format(msg.server.id, msg.server.get_member_named(tmp).id) - except AttributeError: - reponse = "I can't find `{}`".format(tmp) - - if target != "": - mfile = "./markovs/" + target - if os.path.isfile(mfile): - mc = markov.Markov(open(mfile)) - response = mc.generate_text(random.randint(20,40)) - else: - response = "I haven't seen `{}` speak yet.".format(tmp) - - yield from discord_send(client, msg, response); + yield from discord_typing(client, msg) + + tmp = msg.content[8:] + target = "" + + if tmp == "Maki": + response = "My markovs always say the same thing" + else: + if tmp == "": + target = "{}-{}".format(msg.server.id, msg.author.id) + else: + try: + target = "{}-{}".format(msg.server.id, + msg.server.get_member_named(tmp).id) + except AttributeError: + reponse = "I can't find `{}`".format(tmp) + + if target != "": + mfile = "./markovs/" + target + if os.path.isfile(mfile): + mc = markov.Markov(open(mfile)) + response = mc.generate_text(random.randint(20, 40)) + else: + response = "I haven't seen `{}` speak yet.".format(tmp) + + yield from discord_send(client, msg, response) @asyncio.coroutine def cmd_roll(client, msg): - tmp = msg.content[6:] + tmp = msg.content[6:] + + pattern = re.compile("^([0-9]+)d([0-9]+)$") + pattern2 = re.compile("^d([0-9]+)$") - pattern = re.compile("^([0-9]+)d([0-9]+)$") - pattern2 = re.compile("^d([0-9]+)$") + # extract numbers + nums = [int(s) for s in re.findall(r"\d+", tmp)] - if pattern.match(tmp): - # extract numbers - nums = [int(s) for s in re.findall(r"\d+", tmp)] + if pattern.match(tmp): + numdice = nums[0] + diceval = nums[1] + elif pattern2.match(tmp): + numdice = 1 + diceval = nums[0] + else: + response = "Expected format: `[]d`" + yield from discord_send(client, msg, response) - # limit ranges - nums[0] = clamp(nums[0], 1,100) - nums[1] = clamp(nums[1], 1, 1000000) + # limit ranges + numdice = clamp(numdice, 1, 10) + diceval = clamp(diceval, 1, 1000) - # roll and sum dice - rollsum = 0 - for i in range(nums[0]): - rollsum += random.randint(1, nums[1]) + # roll and sum dice + rolls = [] + for i in range(numdice): + rolls.append(random.randint(1, diceval)) - response = "Using `{}d{}`, {} rolled: `{}`".format(nums[0], nums[1], msg.author.display_name, rollsum) - elif pattern2.match(tmp): - # extract number - num = [int(s) for s in re.findall(r"\d+", tmp)] + rollsum = sum(rolls) - # limit range - num[0] = clamp(num[0], 1, 1000000) + response = "**{} rolled:** {}d{}".format(msg.author.display_name, numdice, + diceval) - # roll dice - roll = random.randint(1, num[0]) + if numdice > 1: + response += "\n**Rolls:** `{}`".format(rolls) - response = "Using `1d{}`, {} rolled `{}`".format(num[0], msg.author.display_name, roll) - else: - response = "Expected format: `[]d`" + response += "\n**Result:** `{}`".format(rollsum) - yield from discord_send(client, msg, response) + if rollsum == numdice * diceval: + response += " *(Natural)*" + elif rollsum == numdice: + response += " *(Crit fail)*" + + yield from discord_send(client, msg, response) @asyncio.coroutine def cmd_qr(client, msg): - tmp = msg.content[4:] + tmp = msg.content[4:] - yield from discord_typing(client, msg) + yield from discord_typing(client, msg) - # generate qr code - qr = subprocess.Popen("qrencode -t png -o -".split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE) - qr.stdin.write(tmp.encode("utf-8")) - qr.stdin.close() - out = subprocess.check_output("curl -F upload=@- https://w1r3.net".split(), stdin=qr.stdout) + # generate qr code + qr = subprocess.Popen( + "qrencode -t png -o -".split(), + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + qr.stdin.write(tmp.encode("utf-8")) + qr.stdin.close() + out = subprocess.check_output( + "curl -F upload=@- https://w1r3.net".split(), stdin=qr.stdout) - response = out.decode("utf-8").strip() + response = out.decode("utf-8").strip() - yield from discord_send(client, msg, response) + yield from discord_send(client, msg, response) @asyncio.coroutine def cmd_np(client, msg): - tmp = msg.content[4:] + tmp = msg.content[4:] - if tmp == "": - response = lastfm_np(msg.author.name) - else: - response = lastfm_np(tmp) + if tmp == "": + response = lastfm_np(msg.author.name) + else: + response = lastfm_np(tmp) - print("CALLING SEND") - yield from discord_send(client, msg, response) + print("CALLING SEND") + yield from discord_send(client, msg, response) @asyncio.coroutine def cmd_steam(client, msg): - tmp = msg.content[7:] - - if tmp == "": - response = steamdata(msg.author.name) - else: - response = steamdata(tmp) + tmp = msg.content[7:] - yield from discord_send(client, msg, response) + if tmp == "": + response = steamdata(msg.author.name) + else: + response = steamdata(tmp) + yield from discord_send(client, msg, response) # HELPER FUNCTIONS + # gets now playing information from last.fm def lastfm_np(username): - # sanitise username - cleanusername = re.sub(r'[^a-zA-Z0-9_-]', '', username, 0) - - # fetch JSON from last.fm - payload = {'format': 'json', 'method': 'user.getRecentTracks', 'user': cleanusername, 'limit': '1', 'api_key': lfmkey} - r = requests.get("http://ws.audioscrobbler.com/2.0/", params=payload) - - # read json data - np = r.json() - - # check we got a valid response - if 'error' in np: - return "I couldn't get last.fm data for `{}`".format(username) - - # get fields - try: - username = np['recenttracks']['@attr']['user'] - track = np['recenttracks']['track'][0] - album = track['album']['#text'] - artist = track['artist']['#text'] - song = track['name'] - nowplaying = '@attr' in track - except IndexError: - return "It looks like `{}` hasn't played anything recently.".format(username) - - # grammar - if album != "": - albumtext = "` from the album `{}`".format(album) - else: - albumtext = "`" - - if nowplaying == True: - nowplaying = " is listening" - else: - nowplaying = " last listened" - - # construct string - return "{}{} to `{}` by `{}{}".format(username, nowplaying, song, artist, albumtext) + # sanitise username + cleanusername = re.sub(r'[^a-zA-Z0-9_-]', '', username, 0) + + # fetch JSON from last.fm + payload = { + 'format': 'json', + 'method': 'user.getRecentTracks', + 'user': cleanusername, + 'limit': '1', + 'api_key': lfmkey + } + r = requests.get("http://ws.audioscrobbler.com/2.0/", params=payload) + + # read json data + np = r.json() + + # check we got a valid response + if 'error' in np: + return "I couldn't get last.fm data for `{}`".format(username) + + # get fields + try: + username = np['recenttracks']['@attr']['user'] + track = np['recenttracks']['track'][0] + album = track['album']['#text'] + artist = track['artist']['#text'] + song = track['name'] + nowplaying = '@attr' in track + except IndexError: + return "It looks like `{}` hasn't played anything recently.".format( + username) + + # grammar + if album != "": + albumtext = "` from the album `{}`".format(album) + else: + albumtext = "`" + + if nowplaying == True: + nowplaying = " is listening" + else: + nowplaying = " last listened" + + # construct string + return "{}{} to `{}` by `{}{}".format(username, nowplaying, song, artist, + albumtext) # gets general steam user info from a vanityurl name def steamdata(vanityname): - # sanitise username - cleanvanityname = re.sub(r'[^a-zA-Z0-9_-]', '', vanityname, 0) - - resolveurl = 'http://api.steampowered.com/ISteamUser/ResolveVanityURL/v0001/?key=' - dataurl = 'http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=' - - # fetch json from steam - try: - idresponse = requests.get(resolveurl + steamkey + '&vanityurl=' + vanityname).json()['response'] - except: - return "I can't connect to Steam" - - # check if user was found and extract steamid - if idresponse['success'] is not 1: - return "I couldn't find `{}`".format(vanityname) - else: - steamid = idresponse['steamid'] - - # fetch steam user info - try: - dataresponse = requests.get(dataurl + steamkey + '&steamids=' + steamid).json()['response']['players'][0] - except: - return "Can't find info on `{}`".format(vanityname) - - personastates = ['Offline', 'Online', 'Busy', 'Away', 'Snoozed', 'Looking to trade', 'Looking to play'] - - if 'personaname' in dataresponse: namestr = dataresponse['personaname'] - else: namestr = '' - if 'personastate' in dataresponse: statestr = '`' + personastates[dataresponse['personastate']] + '`' - else: statestr = '' - if 'gameextrainfo' in dataresponse: gamestr = ' playing `' + dataresponse['gameextrainfo'] + '`' - else: gamestr = '' - - responsetext = [(namestr + ' is ' + statestr + gamestr).replace(' ', ' ')] - - return '\n'.join(responsetext) - + # sanitise username + cleanvanityname = re.sub(r'[^a-zA-Z0-9_-]', '', vanityname, 0) + + resolveurl = 'http://api.steampowered.com/ISteamUser/ResolveVanityURL/v0001/?key=' + dataurl = 'http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=' + + # fetch json from steam + try: + idresponse = requests.get(resolveurl + steamkey + '&vanityurl=' + + vanityname).json()['response'] + except: + return "I can't connect to Steam" + + # check if user was found and extract steamid + if idresponse['success'] is not 1: + return "I couldn't find `{}`".format(vanityname) + else: + steamid = idresponse['steamid'] + + # fetch steam user info + try: + dataresponse = requests.get(dataurl + steamkey + '&steamids=' + + steamid).json()['response']['players'][0] + except: + return "Can't find info on `{}`".format(vanityname) + + personastates = [ + 'Offline', 'Online', 'Busy', 'Away', 'Snoozed', 'Looking to trade', + 'Looking to play' + ] + + if 'personaname' in dataresponse: namestr = dataresponse['personaname'] + else: namestr = '' + if 'personastate' in dataresponse: + statestr = '`' + personastates[dataresponse['personastate']] + '`' + else: + statestr = '' + if 'gameextrainfo' in dataresponse: + gamestr = ' playing `' + dataresponse['gameextrainfo'] + '`' + else: + gamestr = '' + + responsetext = [(namestr + ' is ' + statestr + gamestr).replace(' ', ' ')] + + return '\n'.join(responsetext) # COMMAND HANDLING prefix = "." - commands = { - "help": cmd_help, - "info": cmd_info, - "upskirt": cmd_upskirt, - "whoami": cmd_whoami, - "whois": cmd_whois, - "seen": cmd_seen, - "say": cmd_say, - "sayy": cmd_sayy, - "markov": cmd_markov, - "roll": cmd_roll, - "qr": cmd_qr, - "np": cmd_np, - "steam": cmd_steam, + "help": cmd_help, + "info": cmd_info, + "upskirt": cmd_upskirt, + "whoami": cmd_whoami, + "whois": cmd_whois, + "seen": cmd_seen, + "say": cmd_say, + "sayy": cmd_sayy, + "markov": cmd_markov, + "roll": cmd_roll, + "qr": cmd_qr, + "np": cmd_np, + "steam": cmd_steam, } diff --git a/common.py b/common.py index 708a788..aa7689b 100755 --- a/common.py +++ b/common.py @@ -5,16 +5,12 @@ # Copyright 2018 Zac Herd # Licensed under BSD 3-clause License, see LICENSE.md for more info - - # IMPORTS import os import json - # bot version -version = "v1.0.10" - +version = "v1.1.0" # TODO: generate this on the fly and make it look acceptable # text shown by .help command @@ -42,8 +38,8 @@ admins = ['116883900688629761'] # log of users' last messages and timestamps history = {} if os.path.isfile('hist.json'): - with open('hist.json', 'r') as fp: - history = json.load(fp) + with open('hist.json', 'r') as fp: + history = json.load(fp) # quiet modes quiet = {} diff --git a/helpers.py b/helpers.py index 15fefba..1f003db 100755 --- a/helpers.py +++ b/helpers.py @@ -5,7 +5,6 @@ # Copyright 2018 Zac Herd # Licensed under BSD 3-clause License, see LICENSE.md for more info - # IMPORTS import asyncio import discord @@ -18,68 +17,72 @@ from common import * # clamps an integer -def clamp(n, small, large): return max(small, min(n, large)) +def clamp(n, small, large): + return max(small, min(n, large)) # converts a datetime to a string def strfromdt(dt): - return dt.strftime('%Y-%m-%d %H:%M:%S') + return dt.strftime('%Y-%m-%d %H:%M:%S') # converts a timestamp to a datetime def dtfromts(ts): - return datetime.datetime.fromtimestamp(ts) + return datetime.datetime.fromtimestamp(ts) # logging setup def logger(): - logger = logging.getLogger('discord') - logger.setLevel(logging.DEBUG) - 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) + logger = logging.getLogger('discord') + logger.setLevel(logging.DEBUG) + 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) # send_message wrapper (deals with Discord's shit API) @asyncio.coroutine def discord_send(client, message, response): - if response is not '' and message.server.id not in quiet: - for attempt in range(5): - try: - yield from client.send_message(message.channel, response) - except discord.errors.HTTPException: - continue - else: - break - else: - print('ERROR: Failed to send message to discord after 5 attempts') + if response is not '' and message.server.id not in quiet: + for attempt in range(5): + try: + yield from client.send_message(message.channel, response) + except discord.errors.HTTPException: + continue + else: + break + else: + print('ERROR: Failed to send message to discord after 5 attempts') # send typing signal to Discord @asyncio.coroutine def discord_typing(client, message): - for attempt in range(5): - try: - yield from client.send_typing(message.channel) - except discord.errors.HTTPException: - continue - else: - break - else: - print('ERROR: Failed to send typing signal to discord after 5 attempts') + for attempt in range(5): + try: + yield from client.send_typing(message.channel) + except discord.errors.HTTPException: + continue + else: + break + else: + print( + 'ERROR: Failed to send typing signal to discord after 5 attempts') # Maki Reacts to... @asyncio.coroutine def makireacts(client, msg): - # TODO: track down the person(s) responsible for naming emoji - reactions = { - r"\bmaki\b": "\N{BLACK HEART SUIT}", - r"\bbutter\b": "\N{PERSON WITH FOLDED HANDS}", - r"\begg[s]?\b": "\N{AUBERGINE}", - r"\bproblematic\b": "\N{EYEGLASSES}", - } - - for i in reactions: - if bool(re.search(i, msg.content, re.IGNORECASE)): - yield from client.add_reaction(msg, reactions[i]) + # TODO: track down the person(s) responsible for naming emoji + reactions = { + r"\bmaki\b": "\N{BLACK HEART SUIT}", + r"\bbutter\b": "\N{PERSON WITH FOLDED HANDS}", + r"\begg[s]?\b": "\N{AUBERGINE}", + r"\bproblematic\b": "\N{EYEGLASSES}", + } + + for i in reactions: + if bool(re.search(i, msg.content, re.IGNORECASE)): + yield from client.add_reaction(msg, reactions[i]) diff --git a/markov.py b/markov.py index 0227d64..9e266e8 100644 --- a/markov.py +++ b/markov.py @@ -1,7 +1,7 @@ import random -class Markov(object): +class Markov(object): def __init__(self, open_file): self.cache = {} self.open_file = open_file @@ -20,14 +20,14 @@ class Markov(object): return for i in range(len(self.words) - 1): - yield (self.words[i], self.words[i+1]) + yield (self.words[i], self.words[i + 1]) def triples(self): if len(self.words) < 3: return for i in range(len(self.words) - 2): - yield (self.words[i], self.words[i+1], self.words[i+2]) + yield (self.words[i], self.words[i + 1], self.words[i + 2]) def database(self): for w1, w2, w3 in self.triples(): @@ -39,13 +39,13 @@ class Markov(object): def generate_text(self, size=25): seed = random.randint(0, self.word_size - 3) - seed_word, next_word = self.words[seed], self.words[seed+1] + seed_word, next_word = self.words[seed], self.words[seed + 1] w1, w2 = seed_word, next_word gen_words = [] for i in range(size): gen_words.append(w1) try: - w1, w2 = w2, random.choice(self.cache[(w1,w2)]) + w1, w2 = w2, random.choice(self.cache[(w1, w2)]) except KeyError: break gen_words.append(w1)