hellsbot.py 15.6 KB
import requests
import discord
import random
import datetime
from dateutil.parser import parse

from discord.object import Object
from ago import human
import simplejson as json
from collections import defaultdict

member_status = 'members.json'
deliveries_file = 'deliveries.json'
fortune_file = 'fortunes.json'
games_file = 'games.json'
credentials = 'creds.json'

client = discord.Client()

json_data=open(credentials).read()
creds = json.loads(json_data)
client.login(creds['username'], creds['password'])

def leaders(xs, top=20):
    counts = defaultdict(int)
    for x in xs:
        counts[x] += 1
    return sorted(counts.items(), reverse=True, key=lambda tup: tup[1])[:top]

def byteify(input):
    if isinstance(input, dict):
        return {byteify(key):byteify(value) for key,value in input.iteritems()}
    elif isinstance(input, list):
        return [byteify(element) for element in input]
    elif isinstance(input, unicode):
        return input.encode('utf-8')
    else:
        return input

@client.event
def on_socket_raw_send(payload, binary=False):
    check_msg_queue()

@client.event
def on_status(member):
    print("Status Changed %s" % (member,))
    try:
        json_data=open(member_status).read()
        data = json.loads(json_data)
    except ValueError:
        data = {}
    if not data:
        data = {}
    try:
        username = member.name.lower()
        user_id = member.id
        mention = member.mention()
        if username in data:
            is_afk = data[username]['is_afk']
            afk_at = data[username]['afk_at']
            status = data[username]['status']
            prev_status = data[username]['prev_status']
            status_change_at = data[username]['status_change_at']
            game_id = data[username]['game_id']
            games_played = data[username]['games_played']
        else:
            is_afk = False
            afk_at = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
            status = 'online'
            prev_status = 'offline'
            status_change_at = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
            game_id = None
            games_played = []
        if member.status == 'idle':
            afk_at = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
            is_afk = True
        else:
            is_afk = False
        if status != member.status:
            prev_status = status
            status = member.status
            status_change_at = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
        if game_id != member.game_id:
            game_id = member.game_id
            if game_id not in games_played:
                games_played.append(game_id)
        data[username] = {
            'id': user_id,
            'mention': mention,
            'is_afk': is_afk,
            'afk_at': afk_at,
            'status': status,
            'prev_status': prev_status,
            'status_change_at': status_change_at,
            'game_id': game_id,
            'games_played': games_played
        }
        print('Status Change: %s' % (data,))
        jdata = json.dumps(data, ensure_ascii=False)
    except Exception as e:
        print('Error saving status change: %s' % (e),)
        return            

    open(member_status, 'wb+').write(jdata.encode('utf8'))
    

def get_game_names(game_id_list):
    json_data=open(games_file).read()
    data = json.loads(json_data)
    result = []
    for game_id in game_id_list:
        for game in data:
            if game['id'] == game_id:
                result.append(game['name'])
    return result

def get_mention_status(mention):
    try:
        json_data=open(member_status).read()
        data = json.loads(json_data)
    except ValueError:
        data = {}
    if not data:
        data = {}
    for user in data:
        if 'mention' in data[user]:
            if data[user]['mention'] == mention:
                return data[user]
    return None

def check_msg_queue():
    print("checking messages")
    try:
        json_data=open(deliveries_file).read()
        data = json.loads(json_data)
    except ValueError:
        data = {}
    if not data:
        data = {}    
    print("Data: %s" % data)
    new_data = {}
    for username in data:
        for author in data[username]:
            print("Message: %s" % data[username][author])
            delivery = datetime.datetime.strptime(data[username][author]['delivery_time'], '%Y/%m/%d %H:%M:%S')
            if delivery <= datetime.datetime.now():
                offline = False
                for member in client.get_all_members():
                    print('MEMBER MENTION: %s USERNAME: %s' % (member.mention(), username))
                    
                    if username == member.mention():
                        if member.status != 'online':
                            print('OFFLINE USER, TRY AGAIN LATER')
                            offline = True
                            break
                if offline:
                    break
                channel = Object(data[username][author]['channel'])                
                message = data[username][author]['message']
                client.send_message(channel, '{}, {} asked me to tell you "{}"'.format(username, author, message))
            else:
                new_data[username] = {}
                new_data[username][author] = data[username][author]
    
    jdata = json.dumps(new_data, ensure_ascii=False)
    print("New Data: %s" % new_data)
    open(deliveries_file, 'wb+').write(jdata.encode('utf8'))
    return    


@client.event
def on_message(message):
    print message.content
    print message.author
    print client.user
    # we do not want the bot to reply to itself
    if message.author == client.user:
        return

    if message.content.lower().startswith(client.user.name.lower()):
        print('Someone is talking to %s' % (client.user.name.lower(),))
        if ' or ' in message.content:
            questions = message.content[len(client.user.name)+1:].replace('?', '').split(' or ')
            client.send_message(message.channel, '{} I choose: {}'.format(message.author.mention(), random.choice(questions).encode('utf-8',errors='ignore')))


    if message.content.startswith('!help') or message.content.startswith('!commands'):
        client.send_message(message.channel, 
            """{} Available Commands:
You can ask compound or questions and I will choose. Example: HellsBot Rui is a Faggot or Rui is a faggot?
    !msg <username> in 5 minutes Tea is ready
    !msg <username> in 45 seconds Your finished masterbating
    !msg <username> in 2 hours The movie is over
    !msg <username> on 12/22/2015 Happy Birthday!
    !games <username> - Returns a list of games played for a username.
    !gameslist - Returns a list of the top 20 games and the number of people who have played that game.
    !lastseen <username> - Returns info on when the user was last seen and their status.
    !addfortune <fortune> - Adds a new fortune.
    !fortune - Returns your fortune
    !secret
    !bemyirlwaifu""".format(message.author.mention()))
        return

    if message.content.startswith('!lastseen'):
        data = None
        try:
            json_data=open(member_status).read()
            data = json.loads(json_data)
        except ValueError:
            pass
        if not data:
            client.send_message(message.channel, 'I am a bit confused right now.. maybe I need more data. {}!'.format(message.author.mention()))            
        else:
            username = message.content[10:].replace('@', '').lower()
            if username in data:
                out_string = ''
                if data[username]['is_afk'] == True:
                    out_string = 'Went AFK at: {}\n'.format(data[username]['afk_at'])
                elif data[username]['status'] == 'offline':
                    out_string = 'Currently Offline\n'                    
                else:
                    out_string = 'Currently Online\n'
                out_string += 'Last Status: {} at {} which was {}\nPrevious Status: {}\n'.format(data[username]['status'], 
                    data[username]['status_change_at'], 
                    human(datetime.datetime.strptime(data[username]['status_change_at'], '%Y/%m/%d %H:%M:%S')),
                    data[username]['prev_status'])

                client.send_message(message.channel, 'Last Information on {}:\n{}'.format(username, out_string))
            else:
                client.send_message(message.channel, 'I don\'t have any data on {} yet {}'.format(username, message.author.mention()))

    if message.content.startswith('!gameslist'):
        data = None
        try:
            json_data=open(member_status).read()
            data = json.loads(json_data)
        except ValueError:
            pass
        if not data:
            client.send_message(message.channel, 'I am a bit confused right now.. maybe I need more data. {}!'.format(message.author.mention()))            
        else:
            game_list = []
            for user in data:
                if 'games_played' in data[user]:
                    print('%s' % data[user])

                    game_list += data[user]['games_played']
            print('%s' % game_list)
            games_sorted = leaders(get_game_names(game_list))
            print('%s' % games_sorted)
            out_string = ''
            for game in games_sorted:
                #print('%s' % game)
                out_string += '    {} - {}\n'.format(game[1], game[0])
            
            client.send_message(message.channel, 'The games I have seen people playing are: \n{}'.format(out_string))
        return

    if message.content.startswith('!games'):
        data = None
        try:
            json_data=open(member_status).read()
            data = json.loads(json_data)
        except ValueError:
            pass
        if not data:
            client.send_message(message.channel, 'I am a bit confused right now.. maybe I need more data. {}!'.format(message.author.mention()))            
        else:
            username = message.content[7:].replace('@', '').lower()
            if username in data:
                games = ', '.join(get_game_names(data[username]['games_played']))
                client.send_message(message.channel, 'I have seen {} playing: {}'.format(username, games))
            else:
                client.send_message(message.channel, 'I don\'t have any data on {} yet {}'.format(username, message.author.mention()))
        return

    # !msg joe in 5 minutes YOU ARE A DICK
    if message.content.startswith('!msg'):
        try:
            json_data=open(deliveries_file).read()
            data = json.loads(json_data)
        except ValueError:
            data = {}
        if not data:
            data = {}
        channel = message.channel
        author = message.author
        #author = message.author.name
        username = ''
        try:
            message_bits = message.content.split(" ")
            msg_datetime = datetime.datetime.now()
            msg_idx = 2
            if message_bits[2] == 'in' and message_bits[3].isdigit():
                time = int(message_bits[3])
                msg_idx = 4
                if message_bits[4].startswith('sec'):
                    msg_datetime = msg_datetime + datetime.timedelta(seconds=time)
                    msg_idx = 5
                elif message_bits[4].startswith('hour'):
                    msg_datetime = msg_datetime + datetime.timedelta(hours=time)
                    msg_idx = 5
                else: # minutes by default
                    msg_datetime = msg_datetime + datetime.timedelta(minutes=time)
                    msg_idx = 5
            elif message_bits[2] == 'on':
                try:
                    tmp_date = parse(message_bits[3])
                    msg_datetime = tmp_date
                    msg_idx = 4
                except ValueError:
                    client.send_message(channel, 'Your shitty message has been rejected {}. Next time learn how to date...MM\\DD\\YYYY'.format(message.author.mention()))
                    return            
                    
            username = message_bits[1]
            user_mention = ''
            for member in client.get_all_members():
                print("MEMBER: %s" % member)
                if username.lower() == member.name.lower():
                    user_mention = member.mention()
                    user_id = member.id
            if user_mention == '':
               client.send_message(channel, 'Your shitty message has been rejected {}. That user does not exist.'.format(message.author.name))
               return            

            msg_text = byteify(' '.join(message_bits[msg_idx:]))
            message = {'user_id': user_id, 'channel': channel.id, 'delivery_time': msg_datetime.strftime('%Y/%m/%d %H:%M:%S'), 'message': msg_text}
            print("Message: %s" % message)
            data[user_mention] = {}
            data[user_mention][author.mention()] = message
            jdata = json.dumps(data, ensure_ascii=False)
            print("Data: %s" % data)
            #test_ch = Object(channel.id)
            #client.send_message(test_ch, 'Test Message {}.'.format(author))
        except Exception as e:
           client.send_message(channel, 'Your shitty message has been rejected {}. {}'.format(author.name, e))
           return            
        open(deliveries_file, 'wb+').write(jdata.encode('utf8'))
        if msg_datetime < datetime.datetime.now():
            client.send_message(channel, '{} your message will be delivered to {} as soon as they are available.'.format(author.name, user_mention))
        else:
            client.send_message(channel, '{} your message will be delivered to {} {}.'.format(author.name, user_mention, human(msg_datetime)))            
        check_msg_queue()
        return

    if message.content.startswith('!addfortune'):
        try:
            json_data=open(fortune_file).read()
            data = json.loads(json_data)
        except ValueError:
            data = []
        if not data:
            data = []
        try:
            data.append(byteify(message.content[12:]))
            jdata = json.dumps(data, ensure_ascii=False)
        except:
            client.send_message(message.channel, 'Your shitty fortune has been rejected {}.'.format(message.author.mention()))
            return            

        open(fortune_file, 'wb+').write(jdata.encode('utf8'))
        client.send_message(message.channel, 'Your shitty fortune has been added {}.'.format(message.author.mention()))

    if message.content.startswith('!fortune'):
        data = None
        try:
            json_data=open(fortune_file).read()
            data = json.loads(json_data)
        except ValueError:
            pass
        if not data:
            client.send_message(message.channel, 'Try adding a fortune with "!addfortune <fortune>" {}!'.format(message.author.mention()))            
        else:
            client.send_message(message.channel, '{} Your fortune is... {}'.format(message.author.mention(), random.choice(data).encode('utf-8',errors='ignore')))

    if message.content.startswith('!secret'):
        client.send_message(message.channel, 'git gud {}! My source is here: http://git.savsoul.com/barry/discordbot'.format(message.author.mention()))

    if message.content.startswith('!bemyirlwaifu'):
        client.send_message(message.channel, 'http://orig13.deviantart.net/b25e/f/2014/175/3/d/no_waifu_no_laifu_by_imtheonenexttome-d7nsx3b.gif {}!'.format(message.author.mention()))


    if message.content.startswith('!hello'):
        client.send_message(message.channel, 'Hello {}!'.format(message.author.mention()))

@client.event
def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)
    print('------')

client.run()