예제 #1
0
async def _get_now_playing(lastfm, author=None):
    try:
        response = (await asyncio.get_event_loop().run_in_executor(
            None,
            lambda: requests.get(
                API_URL,
                headers={'User-Agent': config['user_agent']},
                params={
                    'method': 'user.getrecenttracks',
                    'api_key': config['lastfm']['api_key'],
                    'user': lastfm,
                    'limit': 1,
                    'format': 'json',
                },
                timeout=5,
            ),
        )).json()
    except JSONDecodeError as e:
        logger.error(f'Failed to query Last.FM API: {e}.')
        raise BotError(f'Failed to query Last.FM API.')
    if 'error' in response:
        message = (f'Failed to query Last.FM API: {response["error"]} '
                   f'{response["message"]}.')
        logger.error(message)
        raise BotError(message)
    if not response['recenttracks']['track']:
        raise BotError(f'{author} has never scrobbled before.')
    return response['recenttracks']['track'][0]
예제 #2
0
def _parse_quote_ids(message):
    try:
        quote_ids = [int(qid) for qid in message.split(' ')]
    except ValueError:
        raise BotError('Quote IDs must be integers.')

    if len(quote_ids) > 3:
        raise BotError('A maximum of three quotes may be queried at once.')
    return quote_ids
예제 #3
0
 async def wrapper(*, listener, author, **kwargs):
     username = await listener.is_authed(author)
     if not username:
         raise BotError('Identify with NickServ to use this command.')
     return await func(
         listener=listener, author=author, username=username, **kwargs
     )
예제 #4
0
 def wrapper(*, message, **kwargs):
     for regex in regexes:
         match = regex.match(message)
         if match:
             return func(args=match.groups(), **kwargs)
     else:
         raise BotError('Invalid arguments.')
예제 #5
0
def _compile_regex(regex, flags):
    try:
        if flags['nocase']:
            return re.compile(regex, flags=re.IGNORECASE)
        return re.compile(regex)
    except Exception as e:  # noqa E722
        raise BotError(f'{regex} is not a valid regex.') from e
예제 #6
0
async def call(*, bot, listener, target, author, message, private):
    """Chooses one of many provided options."""
    match = re.match(r'(\d+) *- *(\d+)', message)
    if match:
        return randint(int(match[1]), int(match[2]))
    elif ',' in message:
        return choice([c.strip() for c in message.split(',')])
    elif ' ' in message:
        return choice([c.strip() for c in message.split(' ')])
    raise BotError('No options found.')
예제 #7
0
async def call(*, bot, listener, target, author, args, private):
    """Part a channel."""
    if args:
        channel = args[0]
        asyncio.ensure_future(listener.part(channel))
        return f'Attempted to part {channel}.'
    elif target != author:
        channel = target
        asyncio.ensure_future(listener.part(channel))
    else:
        raise BotError('This command must be ran in a channel.')
예제 #8
0
def _get_lastfm_nick(username, listener):
    with database() as (conn, cursor):
        cursor.execute(
            """
            SELECT lastfm
            FROM lastfm
            WHERE user = ?  AND listener = ?
            """,
            (username, str(listener)),
        )
        row = cursor.fetchone()
        if not row:
            raise BotError('No Last.FM name set.')
        return row['lastfm']
예제 #9
0
async def call(*, bot, listener, target, author, args, private):
    """Queries the UrbanDictionary API and relays the response."""
    entry = int(args[0]) if len(args) == 2 else 1
    search = args[-1]

    future = asyncio.get_event_loop().run_in_executor(
        None,
        lambda: requests.get(
            'https://api.urbandictionary.com/v0/define',
            headers={'User-Agent': config['user_agent']},
            params={'term': search},
            timeout=15,
        ),
    )

    try:
        response = (await future).json()
    except (requests.RequestException, JSONDecodeError) as e:
        logger.error(f'Failed to query UrbanDictionary: {e}')
        raise BotError('Failed to query UrbanDictionary.')

    if not response['list']:
        raise BotError(
            f'Could not find a definition for {search.rstrip(".")}.')

    defi = (re.sub(
        r'\[(.*?)\]',
        r'\1',
        sorted(
            response['list'],
            key=lambda x: int(x['thumbs_up']) - int(x['thumbs_down']),
            reverse=True,
        )[entry]['definition'],
    ).strip().replace('\n', ' '))

    return f'{defi[:497]}...' if len(defi) >= 500 else defi
예제 #10
0
def _calculate_time_since_played(track, author=None):
    if '@attr' in track:
        return

    scrobble_time = datetime.strptime(track['date']['#text'],
                                      '%d %b %Y, %H:%M')
    diff = datetime.utcnow() - scrobble_time
    hours, seconds = divmod(diff.seconds, 3600)
    minutes = divmod(seconds, 60)[0]

    time_since = []

    if diff.days > 0:
        time_since.append(f'{diff.days} days')
    if hours > 0:
        time_since.append(f'{hours} hours')
    if minutes > 0:
        time_since.append(f'{minutes} minutes')

    if diff.days > 0 or hours > 0:
        raise BotError(f'{author} is not playing anything (last seen: '
                       f'{" ".join(time_since)} ago)')

    return f'{minutes} minutes'
예제 #11
0
def _parse_quote_ids(message):
    try:
        quote_ids = [int(qid) for qid in message.split(' ')]
    except ValueError:
        raise BotError('Quote IDs must be integers.')
    return quote_ids
예제 #12
0
 async def wrapper(*, listener, author, **kwargs):
     if not await listener.is_admin(author):
         raise BotError('Unauthorized.')
     return await func(listener=listener, author=author, **kwargs)
예제 #13
0
 def wrapper(*, listener, **kwargs):
     if any(isinstance(listener, l) for l in listeners):
         return func(listener=listener, **kwargs)
     raise BotError('This command cannot be run on this listener.')
예제 #14
0
 def wrapper(*, private, **kwargs):
     if private:
         return func(private=private, **kwargs)
     raise BotError('This command can only be run in a private message.')
예제 #15
0
 def wrapper(*, private, **kwargs):
     if not private:
         return func(private=private, **kwargs)
     raise BotError('This command can only be run in a channel.')
예제 #16
0
def confirm_database_is_updated():
    if calculate_migrations_needed():
        if not len(sys.argv) == 2 or sys.argv[1] != 'migrate':
            raise BotError(
                'The database needs to be migrated. Run `chitanda migrate`.')