Пример #1
0
def helper(message):
    increment_usage(message.guild, 'stats')
    text = message.content

    # We need to flatten user and role mentions in order to properly query the database
    for each in message.mentions:
        text = text.replace('<@!{}>'.format(each.id), each.name)
    for each in message.channel_mentions:
        text = text.replace('<#{}>'.format(each.id), each.name)

    args = text.split()
    operator = 'cloud'
    if len(args) > 1:
        operator = args[1].lower()

    if operator == 'user' and len(args) > 2:
        setup(message.guild.id, user='******'.join(args[2:]))
        banner = word_cloud(' '.join(args[2:]), message.guild.name)
        return banner
    elif operator == 'channel' and len(args) > 2:
        setup(message.guild.id, channel=' '.join(args[2:]))
        banner = word_cloud(' '.join(args[2:]), message.guild.name)
        return banner
    else:
        setup(message.guild.id)

    return {
        'common': lambda: word_frequency(args),
        'cloud': lambda: word_cloud('the server', message.guild.name),
        'count': lambda: word_count(args, message.guild.name),
        'phrases': lambda: get_ngrams(args, message.guild.name),
        'help': lambda: get_help(message),
    }.get(operator, lambda: None)()
Пример #2
0
def get_react(message):
    """
    Get a random gif file from ./emotes or the servers folder
    :param message: <Discord.message object>
    :return: <String> Describing file location
    """
    increment_usage(message.guild, 'gif')

    nsfw = True if 'nsfw' in message.content.lower() else False
    guild = message.guild.id
    reacts = [
        '{}/emotes/{}'.format(DEFAULT_DIR, each)
        for each in listdir('./emotes')
    ]

    if isdir('{}/emotes/{}'.format(DEFAULT_DIR, guild)):
        reacts.extend([
            '{}/emotes/{}/{}'.format(DEFAULT_DIR, guild, each)
            for each in listdir('./emotes/{}'.format(guild))
        ])

    if nsfw and isdir('{}/emotes/{}/nsfw'.format(DEFAULT_DIR, guild)):
        reacts.extend([
            '{}/emotes/{}/nsfw/{}'.format(DEFAULT_DIR, guild, each)
            for each in listdir('./emotes/{}/nsfw'.format(guild))
        ])

    return random.choice(reacts)
Пример #3
0
def get_help(message):
    """
	Return the help file located in ./docs/help
	:param message: <Discord.message object>
	:return: <String> The local help file
	"""
    increment_usage(message.guild, 'help')
    return wrap(fetch_file('help', 'dict'), 1990)
Пример #4
0
async def override(message):
    """
	Admin command to manually change a user's saved location
	:param message: <Discord.message object> Describing which users to change to which locations
	:return: <String> Describing if the users' location was set or updated successfully
	"""
    increment_usage(message.guild, 'sched')
    if await is_admin(message.author, message):
        banner = Embed(title='Schedule Override',
                       description='Change a user\'s location.')
        args = message.content.split()
        # Args should translate as: 1 id, 2 name, 3 locale
        if len(args) < 4:
            banner.add_field(
                name='Invalid syntax.',
                value=
                'Formatting is: `!schedule override [TIMEZONE] @USER` you may mention any number of users.'
            )

        else:
            locale = TZ_ABBRS.get(args[2].lower(), args[2])
            success = [[], []]

            for each in message.mentions:
                user = get_user(int(each.id))

                if user:
                    with ENGINE.connect() as conn:
                        query = Users.update().where(
                            Users.c.id == each.id).values(locale=locale)
                        conn.execute(query)

                    if VERBOSE >= 2:
                        print('[+] {} UPDATED LOCALE TO {} FOR USER {}'.format(
                            message.author, locale, each.name))
                    success[0].append('Changed {} to: {}'.format(
                        each.name, locale))

                else:
                    insert_user(each.id, message.guild, each.name, locale)
                    if VERBOSE >= 2:
                        print('[+] {} SETTING {}\'s SCHEDULE TO: {}'.format(
                            message.author, each.name, locale))
                    success[1].append('Set {} to: {}'.format(
                        each.name, locale))
            banner.add_field(name='Updated schedule location.',
                             value='\n'.join(success[0]))
            banner.add_field(name='Created schedule location.',
                             value='\n'.join(success[1]))
        return banner
Пример #5
0
async def get_todays_word(message):
    """
	Pull the word of the day from www.wordsmith.org
	:param message: <Discord.message object> 
	:return: <str> Banner
	"""
    increment_usage(message.guild, 'wotd')

    async with aiohttp.ClientSession() as session:
        async with session.get(URL_WOTD) as resp:
            if resp.status == 200:
                text = await resp.read()
            else:
                if VERBOSE >= 2:
                    print("[!] Status {}".format(resp.status))

    soup = BeautifulSoup(text, "html.parser")
    text = soup.get_text()
    text = text.split('with Anu Garg')
    text = text[1].split('A THOUGHT FOR TODAY')
    text = text[0].strip()
    text = text.split('\n')

    fields = {
        'header': '',
    }
    for idx, line in enumerate(text):
        if line:
            if line in URL_KEYWORDS.keys():
                fields[line] = ''
                key = line
            elif idx == 0:
                fields['header'] = '{}\n{}'.format(fields['header'], line)
            else:
                fields[key] = '{}\n{}'.format(fields[key], line)

    banner = Embed(title="Word of the Day", description=fields['header'])
    fields.pop('header')
    for key, val in fields.items():
        banner.add_field(name=key, value=val)
    banner.set_footer(text=URL_WOTD)
    return banner
Пример #6
0
async def get_help(result):
    increment_usage(result["message"].guild, 'help')
    help_ = fetch_file('help', 'general')
    if not await is_admin(result["message"].author, result["message"]):
        help_ = help_.split('For Admins:')[0]

    banner = Embed(title='General Help', description=help_)
    banner.add_field(name='Help support this bot!',
                     value='All donations go to development and server costs.',
                     inline=False)
    banner.add_field(name='PayPal', value=help_general['paypal'])
    # banner.add_field(name='Patreon', value=help_general['patreon'])
    banner.add_field(name='More Information',
                     value='This bot is open source, find it at: {}'.format(
                         help_general['github']))
    banner.add_field(name='Invite the bot to your server.',
                     value=help_general['invite'],
                     inline=False)

    result["embed"] = banner
    return result
Пример #7
0
async def fetch_react(message):
    """
    Save a gif a user added with !gif add
    :param message: <Discord.message object>
    :return: <String> Notify of gif being added or not
    """
    increment_usage(message.guild, 'gif')
    url = str(message.attachments[0].url)
    extension = str(url.split('.')[-1].lower())

    if extension != 'gif':
        return 'File must be a gif'

    file_name = str(url.split('/')[-1])
    nsfw = True if 'nsfw' in message.content.lower() else False

    if nsfw:
        Path('{}/emotes/{}/nsfw'.format(DEFAULT_DIR,
                                        message.guild.id)).mkdir(parents=True,
                                                                 exist_ok=True)
        file_path = '{}/emotes/{}/nsfw/{}'.format(DEFAULT_DIR,
                                                  message.guild.id, file_name)
    else:
        Path('{}/emotes/{}'.format(DEFAULT_DIR,
                                   message.guild.id)).mkdir(parents=True,
                                                            exist_ok=True)
        file_path = '{}/emotes/{}/{}'.format(DEFAULT_DIR, message.guild.id,
                                             file_name)

    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            if resp.status == 200:
                f = await aiofiles.open(file_path, mode='wb')
                await f.write(await resp.read())
                await f.close()
                if VERBOSE >= 2:
                    print("[+] Saved: {}".format(file_path))
                return 'Added a new gif to !gif'
Пример #8
0
async def get_help(message):
    """
	Get the command help file from ./docs/help
	:param message: <Discord.message object>
	:return: <String> Containing help for the user's available options or list of locations
	"""
    increment_usage(message.guild, 'help')
    args = message.content.split()
    banner = Embed(title='Schedule')

    if len(args) < 3:
        # Get general help
        raw = fetch_file('help', 'schedule')
        if not await is_admin(message.author, message):
            raw = raw.split('For Admins:')[0]
        banner.add_field(name='Help', value=raw)
    else:
        # Get list of cities or continents
        raw = fetch_file('locales', args[2].lower())
        banner.add_field(name='Locales in {}'.format((args[2].lower())),
                         value=raw)

    return banner
Пример #9
0
def get_help(message):
    """
    Get the command help file from ./docs/help
    :param message: <Discord.message object>
    :return: <String> Containing help for the user's available options or list of locations
    """
    increment_usage(message.guild, 'help')
    custom = ''
    try:
        guild_commands = custom_commands[message.guild.id]
        banner = Embed(title='Custom Command Help',
                       description=fetch_file('help', 'custom'))
        for name, value in guild_commands.items():
            custom = '{}`{}`: {}\n'.format(custom, name, value)
        available = Embed(
            title='Custom commands available in this server are:',
            description=custom)
        # banner.add_field(name='Custom commands available in this server are:', value=custom)
        return None, [banner, available]
    except Exception as e:
        if VERBOSE >= 0:
            print('[!] Exception in get help custom {}'.format(e))
        pass
Пример #10
0
def set_schedule(message):
    """
	User command to set their locale
	:param message: <Discord.message object> Describing where to set location to
	:return: <String> Describing new location for user
	"""
    increment_usage(message.guild, 'sched')
    args = message.content.split()
    config = load_config(message.guild.id)
    banner = Embed(title='Schedule')

    if config:
        server_locale = config[2]
    else:
        server_locale = 'Asia/Tokyo'

    # if no location provided default to server locale
    # if server has no locale default to Tokyo
    # if there is no server locale the schedule will not be displayed
    # however this allows users to still get their locations set
    locale = server_locale if len(args) < 3 else TZ_ABBRS.get(
        args[2].lower(), args[2])
    user = get_user(message.author.id)
    old_locale = user[2]
    if user:
        with ENGINE.connect() as conn:
            query = Users.update().where(
                Users.c.id == message.author.id, ).values(locale=locale)
            conn.execute(query)
        banner.add_field(name='Updated your schedule location.',
                         value='From: {}\nTo: {}'.format(old_locale, locale))
    else:
        insert_user(message.author.id, message.guild, message.author.name,
                    locale)
        banner.add_field(name='Set your schedule location.',
                         value='To: {}'.format(locale))
    return banner
Пример #11
0
async def helper(message):
    """
	Main entry point from main.py, handles majority of argument parsing
	:param message: <Discord.message object>
	:return: <lambda function> Internal function dispatch
	"""

    text = message.content
    for each in message.mentions:
        text = text.replace('<@!{}>'.format(each.id), each.name)
    args = text.split()

    # Lore
    if args[0] == '!lore':
        increment_usage(message.guild, 'lore')
        if len(args) > 1:
            if args[1] == 'add' and await is_admin(message.author, message):
                return insert_quote(message, Lore)
            elif args[1] == 'delete' and await is_admin(
                    message.author, message):
                return delete_quote(message.guild.id, args[2])
            elif args[1] == 'help' and await is_admin(message.author, message):
                return get_help(message)
            else:
                return get_quote(message, Lore, ' '.join(args[1:]), True)
        else:
            return get_quote(message, Lore, None, True)

    # Quote with options
    elif len(args) > 1:
        increment_usage(message.guild, 'quote')
        if args[1] == 'help':
            return get_help(message)
        elif args[1] == 'delete' and await is_admin(message.author, message):
            return delete_quote(message.guild.id, args[2])
        elif args[1] == 'log' and await is_admin(message.author, message):
            return get_quote_log(message.guild.id)
        else:
            return get_quote(message, Quotes, ' '.join(args[1:]), True)

    # Any random quote
    else:
        increment_usage(message.guild, 'quote')
        return get_quote(message, Quotes, None, True)
Пример #12
0
def get_help(message):
    increment_usage(message.guild, 'help')
    banner = Embed(title='Stats Help', description=fetch_file('help', 'stats'))
    return None, banner
Пример #13
0
async def dispatch(message):
    # Preprocessing
    if message.author.bot:
        return None
    increment_usage(message.guild, 'raw_messages')
    await tlog.log_message(message)
    args = message.content.split()
    result = {"message": message, "rawText": None, "embed": None, "file": None}
    if VERBOSE >= 2:
        print('[-] {} by {} in {} - {}'.format(args[0][1:],
                                               message.author.name,
                                               message.channel.name,
                                               message.guild.name))

    # Guild level custom commands
    custom = tcustom.get_command(message)
    if custom:
        if VERBOSE >= 2:
            print('[-] {} by {} in {} - {}'.format('arg: {}'.format(args[0]),
                                                   message.author.name,
                                                   message.channel.name,
                                                   message.guild.name))
        result["rawText"] = custom[0]
        result["embed"] = custom[1]
        return result

    # Correct minor typos
    spell = Speller('cmd')
    operator = spell(args[0][1:])
    if args[0][0] != '$':
        return None
    if VERBOSE >= 2:
        print('[-] {} by {} in {} - {}'.format(operator, message.author.name,
                                               message.channel.name,
                                               message.guild.name))

    # Quotes
    if operator in {'quote', 'lore', 'q', 'l'}:
        result = get_quote(result)

    # Wolfram Alpha
    elif operator in {'w', 'wolf', 'wolfram'}:
        result = await get_wolfram(result)

    # Word of the Day
    elif operator in {'word', 'wotd'}:
        result["embed"] = await tword.get_todays_word(message)

    # Wiktionary
    elif operator in {'dict', 'dictionary', 'wiki', 'wiktionary'}:
        result["embed"] = tword.wiki(message)

    # Config
    elif operator == 'config':
        result["file"] = await config_helper(message)
        if result["file"] and type(result["file"]) is not DiscordFile:
            result["file"] = DiscordFile(result["file"])
        await message.author.send(file=result["file"])
        return None

    # Log
    elif operator == 'log' and await is_admin_test(message.author, message):
        banner = tlog.get_log(message)
        result["file"] = banner[1]
        if result["file"] and type(result["file"]) is not DiscordFile:
            result["file"] = DiscordFile(result["file"])
        await message.author.send(content=banner[0], file=result["file"])
        return None

    # Schedule
    elif operator in {'schedule', 'sched', 's'}:
        result["embed"] = tsched.helper(message)
    elif operator in {'next'}:
        result["embed"] = tsched.helper(message, 'next')

    # Yandex
    elif operator in {'yandex', 'image', 'tineye', 'reverse'}:
        result["rawText"] = tword.yandex(message)

    # Doip
    elif operator == 'doip' and int(message.guild.id) == 453859595262361611:
        increment_usage(message.guild, 'doip')
        result["rawText"] = tquote.get_quote(message, tquote.Quotes,
                                             "LaDoIphin", True)
        result["file"] = '{}/docs/doip.jpg'.format(DEFAULT_DIR)

    # GIF
    elif operator in {'gif', 'react', 'meme'}:
        return await get_gif(result)

    # Stats
    elif operator == 'stats':
        result["file"], result["embed"] = tstat.helper(message)

    # Magic Eightball
    elif operator in {'8ball', '88ball', 'ball', '8', 'eightball', 'eight'}:
        increment_usage(message.guild, 'eight')
        result["rawText"] = choice(EIGHTBALL)

    # General Help
    elif operator == 'help':
        result = await get_help(result)

    if result["file"] and type(result["file"]) is not DiscordFile:
        result["file"] = DiscordFile(result["file"])
    return result
Пример #14
0
def get_command(message):
    """
    Return a custom command to be sent to Discord.
    :param message: <Discord.message> Raw message object
    :return: <str> Banner
    """
    embed_image = None
    links = ''
    custom = '.'
    args = message.content.split()
    config = tsched.load_config(message.guild.id)
    quotes = False

    if VERBOSE >= 2:
        print("Config: ")
        print(config)

    try:
        if args[0] == '$custom' or args[0:2] == ['$help', 'custom']:
            if VERBOSE >= 1:
                print('[-] custom - help by {} in {} - {}'.format(
                    message.author.name, message.channel.name,
                    message.guild.name))
            return get_help(message)
    except Exception as e:
        if VERBOSE >= 2:
            print("Exception: ")
            print(e)

    if config:
        server_locale = config[2]
        url = config[6]
        timestamp = pendulum.now(tz=server_locale).to_datetime_string()
    else:
        url = ' '
        timestamp = pendulum.now(tz='America/New_York').to_datetime_string()
        server_locale = 'America/New_York'

    try:
        # all custom commands for the guild
        guild_commands = custom_commands[message.guild.id]
        if VERBOSE >= 2:
            print("Guild Commands: ")
            print(guild_commands)
        # the value to be returned to the user, in raw formatting
        custom = guild_commands[args[0]]
        if VERBOSE >= 2:
            print("Custom: ")
            print(custom)

        # Check for image links or general links
        if VERBOSE >= 2:
            print("Checking for links...")
        for each in custom.split():
            if each.find('http') != -1:
                if each.split('.')[-1] in extSet['image']:
                    embed_image = each
                else:
                    links = '{}\n{}'.format(links, each)
        # Setting up for nested loops
        prev = deepcopy(custom)
        count = 0

        # for nested commands, not the most efficient solution but it works
        # if you can improve it please issue a code merge request
        while True:
            if VERBOSE >= 2:
                print("Formatting command, loop {}...".format(count))
            # Discord's character limit is 2000
            # count is chosen arbitrarily, move up or down for recursion limit
            if len(custom) + len(prev) > 1999 or count > 50:
                break
            else:
                for key in guild_commands:
                    custom = custom.replace('<{}>'.format(key),
                                            guild_commands[key])
                    # TODO user mentions for <QUOTE>
                custom = custom.replace('\\n', '\n')
                custom = custom.replace('\\r', '<\n>')
                custom = custom.replace('<URL>', url)
                custom = custom.replace(
                    '<NOW>', '{} in {}'.format(timestamp, server_locale))
                custom = custom.replace(
                    '<TIME>', '{} in {}'.format(timestamp, server_locale))
                custom = custom.replace('<LOCALE>', server_locale)
                custom = custom.replace('<LOCATION>', server_locale)
                custom = custom.replace('<AUTHOR>', message.author.name)
                custom = custom.replace('<GUILD>', message.guild.name)
                while '<SCHED>' in custom:
                    custom = custom.replace('<SCHED>',
                                            tsched.get_schedule(message, True))
                #if '<QUOTE>' in custom:
                #    custom = custom.replace('<QUOTE>', tquote.get_quote(message, tquote.Quotes, raw=True))
                #    quotes = True
                custom = custom.replace(
                    '<LORE>', tquote.get_quote(message, tquote.Lore, raw=True))
                if custom == prev:
                    break
                else:
                    count += 1
                    prev = deepcopy(custom)

    except Exception as e:
        if VERBOSE >= 2:
            print('[!] Exception in tcustom {}'.format(e))
            pass
    finally:
        # Cleanup from quote with user
        if quotes:
            custom = custom.replace('>', '')
        if custom == '.':
            return None
        else:
            increment_usage(message.guild, 'custom')
            if VERBOSE >= 1:
                print('[-] custom - {} by {} in {} - {}'.format(
                    args[0], message.author.name, message.channel.name,
                    message.guild.name))
            banner = Embed(title=args[0], description=custom)
            if embed_image:
                banner.set_image(url=embed_image)

            if links == '':
                links = None
            return links, banner
Пример #15
0
def wiki(message):
    """
	Get the www.wiktionary.org entry for a word or phrase
	:param message: <Discord.message object> 
	:return: <str> Banner or None
	"""
    increment_usage(message.guild, 'dict')
    args = message.content.split()
    if len(args) == 1 or args[1] == 'help':
        banner = Embed(title="Wiktionary Help")
        banner.add_field(name='About', value=help_dict['main'])
        banner.add_field(name='Aliased Command Names',
                         value=help_dict['alternative'])
        return banner
    else:
        try:
            word = message.content.split(' ', maxsplit=1)[1]
            result = parser.fetch(word.strip())[0]
            etymology = result['etymology']
            definitions = result['definitions'][0]
            pronunciations = result['pronunciations']

            banner = Embed(title="Wiktionary", description=word)

            if definitions['partOfSpeech']:
                banner.add_field(name="Parts of Speech",
                                 value=definitions['partOfSpeech'],
                                 inline=False)

            if etymology:
                banner.add_field(name="Etymology",
                                 value=etymology,
                                 inline=False)

            if definitions['text']:
                defs = ''
                for each in definitions['text']:
                    defs += '{} \n'.format(each)
                banner.add_field(name="Definitions", value=defs, inline=False)

            if definitions['relatedWords']:
                defs = ''
                for each in definitions['relatedWords']:
                    for sub in each['words']:
                        defs += '{}, '.format(sub)
                    defs += '\n'
                banner.add_field(name="Related Words",
                                 value=defs,
                                 inline=False)

            if definitions['examples']:
                defs = ''
                for each in definitions['examples']:
                    defs += '{} \n'.format(each)
                banner.add_field(name="Examples", value=defs, inline=False)

            if pronunciations['text'] or pronunciations['audio']:
                defs_text = ''
                defs_audio = ''
                for each in pronunciations['text']:
                    defs_text += '{} \n'.format(each)

                for each in pronunciations['audio']:
                    defs_audio += 'https:{} \n'.format(each)
                banner.add_field(name="Pronunciation, IPA",
                                 value=defs_text,
                                 inline=False)
                banner.add_field(name="Pronunciation, Audio Sample",
                                 value=defs_audio,
                                 inline=False)

                return banner
        except Exception as e:
            if VERBOSE >= 0:
                print('[!] Exception in wiki: {}'.format(e))
            return None
Пример #16
0
async def wolfram(message):
    """
	Return an image based response from the Wolfram Alpha API
	:param message: <Discord.message object> 
	:return: <str> Banner or None
	"""
    increment_usage(message.guild, 'wolf')

    args = message.content.split()
    banner = Embed(title="Wolfram Alpha")
    try:
        if len(args) > 1:
            if args[1].lower() in {'simple', 'txt', 'text', 'textual'}:
                query_st = quote_plus(' '.join(args[2:]))
                query = URL_WOLF_TXT.format(WOLFRAM, query_st)

                async with aiohttp.ClientSession() as session:
                    async with session.get(query) as resp:
                        if resp.status == 200:
                            text = await resp.read()
                        elif resp.status == 501:
                            return 'Wolfram cannot interpret your request.'
                        else:
                            return [
                                '[!] Wolfram Server Status {}'.format(
                                    resp.status), None
                            ]

                text = text.decode('UTF-8')
                banner.add_field(name=' '.join(args[2:]), value=text)
                return banner

            elif args[1].lower() in {
                    'complex', 'graphic', 'graphical', 'image', 'img', 'gif'
            }:
                query_st = quote_plus(' '.join(args[2:]))
                query = URL_WOLF_IMG.format(WOLFRAM, query_st)
                file_path = '{}/log/wolf/{}.gif'.format(
                    DEFAULT_DIR, message.id)

                async with aiohttp.ClientSession() as session:
                    async with session.get(query) as resp:
                        if resp.status == 200:
                            f = await aiofiles.open(file_path, mode='wb')
                            await f.write(await resp.read())
                            await f.close()
                            return [None, file_path]
                        elif resp.status == 501:
                            return [
                                'Wolfram cannot interpret your request.', None
                            ]
                        else:
                            return [
                                '[!] Wolfram Server Status {}'.format(
                                    resp.status), None
                            ]

        banner = Embed(title='Wolfram Help',
                       description=fetch_file('help', 'wolfram'))
        return banner
    except Exception as e:
        if VERBOSE >= 0:
            print('[!] Wolfram failed to process command on: {}'.format(
                message.content))
            print('[!] {}'.format(e))
        return None