예제 #1
0
    async def c_replay(self, msg: twitchirc.ChannelMessage):
        try:
            args = arg_parser.parse_args(
                main.delete_spammer_chrs(msg.text),
                {
                    'time': datetime.timedelta,
                    'channel': str,
                    arg_parser.POSITIONAL: str  # ignore
                })
        except arg_parser.ParserError as e:
            return f'@{msg.user}, Error: {e}'

        if args['time'] is ...:
            args['time'] = datetime.timedelta(seconds=30)
        if args['channel'] is ...:
            args['channel'] = msg.channel

        if args['channel'] != msg.channel:
            j_data = await self.get_user(args['channel'])
            if 'data' not in j_data:
                return f'@{msg.user}, API error (in get-users).'

            if len(j_data['data']) == 0:
                return f'@{msg.user}, failed to find user.'
            user = j_data['data'][0]['id']
        else:
            user = msg.flags['room-id']

        async with aiohttp.request(
                'get',
                'https://api.twitch.tv/helix/videos',
                params={
                    'user_id': user,
                    'sort': 'time',
                    'first': 1
                },
                headers={
                    'Authorization':
                    f'Bearer {main.twitch_auth.json_data["access_token"]}',
                    'Client-ID': main.twitch_auth.json_data["client_id"]
                }) as request:
            j_data = await request.json()
            print(j_data)
            if 'data' not in j_data:
                return f'@{msg.user}, API error (in get-videos).'

            if len(j_data['data']) == 0:
                return f'@{msg.user}, failed to find stream.'
            length = arg_parser.handle_typed_argument(
                j_data['data'][0]['duration'], datetime.timedelta)
            if args['time'] > length:
                return f'@{msg.user}, FeelsWeirdMan It is not possible to create a replay of before the stream started.'
            t: datetime.timedelta = length - args['time']
            return j_data['data'][0]['url'] + f'?t={math.floor(t.seconds / 3600):0>.0f}h' \
                                              f'{math.floor((t.seconds % 3600) / 60):0>.0f}m' \
                                              f'{math.floor((t.seconds % 3600) % 60):0>.0f}s'
예제 #2
0
async def command_debug(msg: twitchirc.ChannelMessage):
    if isinstance(msg, twitchirc.ChannelMessage):
        return f'@{msg.user}, This command is only available in whispers :)'

    argv = arg_parser.parse_args(
        main.delete_spammer_chrs(msg.text).rstrip(' '), {
            0: str,
            1: str
        })
    if argv[0] is ...:
        return f'debug what?'

    debugee_type = argv[0]
    print(repr(debugee_type), debugee_type == 'command',
          debugee_type == 'user', debugee_type == 'me', debugee_type
          in ('user', 'me'))
    if debugee_type == 'command':
        if argv[1] is ...:
            return f'debug which command?'
        cmd_name = argv[1]
        matches = list(
            filter(lambda c: c.chat_command == cmd_name, main.bot.commands))
        if not matches:
            fake_msg = twitchirc.ChannelMessage(cmd_name,
                                                msg.user,
                                                msg.channel,
                                                parent=main.bot)
            matches = list(
                filter(
                    lambda c: c.matcher_function and c.matcher_function(
                        fake_msg, c), main.bot.commands))
            if not matches:
                return f'Unknown command {cmd_name}'

        if len(matches) == 1:
            return _debug_command(matches[0])
        else:
            return f'@{msg.user}, {len(matches)} found.'
    elif debugee_type in ('user', 'me'):
        if argv[1] is ... and debugee_type != 'me':
            return f'@{msg.user}, how do I debug?'
        if debugee_type == 'me':
            argv[1] = msg.user

        users = main.User.get_by_name(argv[1])
        if users:
            return _debug_user(users[0])
        else:
            return f'@{msg.user}, couldn\'t find the target user.'
    else:
        return f'@{msg.user}, how to debug {debugee_type!r}?'
예제 #3
0
    async def c_nuke_url(self, msg: twitchirc.ChannelMessage):
        try:
            args = arg_parser.parse_args(main.delete_spammer_chrs(msg.text), {
                'dry-run': bool,
                'url': str,
                'perma': bool,
                'force': bool,
                'timeout': datetime.timedelta,
                'hastebin': bool
            },
                                         defaults={
                                             'dry-run': False,
                                             'perma': False,
                                             'hastebin': False,
                                             'timeout':...,
                                             'force': False
                                         })
        except arg_parser.ParserError as e:
            return f'@{msg.user}, error: {e.message}'
        if args['url'] is ... or (args['timeout'] is ...
                                  and not args['perma']):
            print(args)
            return f'@{msg.user}, url, timeout (or perma) are required parameters'

        url = args['url']
        if url.startswith(plugin_hastebin.hastebin_addr):
            url = url.replace(plugin_hastebin.hastebin_addr,
                              plugin_hastebin.hastebin_addr + 'raw/')
        async with aiohttp.request('get', url) as req:
            if req.status != 200:
                return f'@{msg.user}, failed to download user list :('
            if req.content_type == 'text/plain':
                users, reasons = self.parse_user_list(
                    (await req.text('utf-8')).replace('\r\n', '\n').replace(
                        '$(newline)', '\n'))

                while '' in users:
                    users.remove('')

                return await self.nuke(
                    args,
                    msg,
                    users,
                    force_nuke=args['force'],
                    disable_hastebinning=not args['hastebin'],
                    reasons=reasons)
            else:
                return f'Refusing to use data, bad content type: {req.content_type}, expected text/plain'
예제 #4
0
    async def c_unnuke(self, msg: twitchirc.ChannelMessage):
        try:
            args = arg_parser.parse_args(main.delete_spammer_chrs(msg.text), {
                'dry-run': bool,
                'url': str,
                'perma': bool,
                'force': bool,
                'hastebin': bool
            },
                                         defaults={
                                             'dry-run': False,
                                             'perma': False,
                                             'force': False,
                                             'hastebin': False
                                         })
        except arg_parser.ParserError as e:
            return f'@{msg.user}, error: {e.message}'
        if args['url'] is ...:
            return f'@{msg.user}, url is a required parameter'
        if args['perma'] is ...:
            args['perma'] = False

        url = args['url']
        if url.startswith(plugin_hastebin.hastebin_addr):
            url = url.replace(plugin_hastebin.hastebin_addr,
                              plugin_hastebin.hastebin_addr + 'raw/')
        async with aiohttp.request('get', url) as req:
            if req.status != 200:
                return f'@{msg.user}, failed to download user list :('
            if req.content_type == 'text/plain':
                users, _ = self.parse_user_list(
                    (await req.text('utf-8')).replace('\r\n', '\n').replace(
                        '$(newline)', '\n'))

                while '' in users:
                    users.remove('')

                return await self.unnuke(
                    args,
                    msg,
                    users,
                    disable_hastebinning=(not args['hastebin']))
예제 #5
0
    async def c_nuke_url(self, msg: twitchirc.ChannelMessage):
        try:
            args = arg_parser.parse_args(
                main.delete_spammer_chrs(msg.text), {
                    'dry-run': bool,
                    'url': str,
                    'perma': bool,
                    'force': bool,
                    'timeout': datetime.timedelta
                })
        except arg_parser.ParserError as e:
            return f'@{msg.user}, error: {e.message}'
        arg_parser.check_required_keys(
            args, ('url', 'timeout', 'search', 'perma', 'dry-run'))
        if args['url'] is ... or (args['timeout'] is ... and
                                  not args['perma']) or args['search'] is ...:
            return f'@{msg.user}, url, timeout and search are required parameters'
        if args['perma'] is ...:
            args['perma'] = False

        url = args['url']
        if url.startswith(plugin_hastebin.hastebin_addr):
            url = url.replace(plugin_hastebin.hastebin_addr,
                              plugin_hastebin.hastebin_addr + 'raw/')
        async with aiohttp.request('get', url) as req:
            if req.status != 200:
                return f'@{msg.user}, failed to download user list :('
            if req.content_type == 'text/plain':
                users = (await
                         req.text('utf-8')).replace('\r\n', '\n').replace(
                             '$(newline)', '\n').split('\n')

                while '' in users:
                    users.remove('')

                return await self.nuke(args,
                                       msg,
                                       users,
                                       force_nuke=args['force'])
예제 #6
0
    async def c_nuke(self, msg: twitchirc.ChannelMessage):
        try:
            args = arg_parser.parse_args(
                main.delete_spammer_chrs(msg.text), {
                    'regex': str,
                    'perma': bool,
                    'timeout': datetime.timedelta,
                    'search': datetime.timedelta,
                    'dry-run': bool,
                    'force': bool,
                    'hastebin': bool
                })
        except arg_parser.ParserError as e:
            return f'@{msg.user}, error: {e.message}'
        arg_parser.check_required_keys(
            args, ('regex', 'timeout', 'search', 'perma', 'dry-run', 'force'))
        if args['regex'] is ... or args['timeout'] is ... or args[
                'search'] is ...:
            return f'@{msg.user}, regex, timeout and search are required parameters'
        if args['perma'] is ...:
            args['perma'] = False

        try:
            r = regex.compile(args['regex'])
        except Exception as e:
            return f'@{msg.user}, error while compiling regex: {e}'

        results = plugin_chat_cache.find_messages(
            msg.channel,
            expr=r,
            min_timestamp=time.time() - args['search'].total_seconds())
        if not results:
            return f'@{msg.user}, found no messages matching the regex.'
        else:
            return await self.nuke_from_messages(
                args, msg, results, disable_hastebinning=not args['hastebin'])
예제 #7
0
async def command_whois(msg: util_bot.StandardizedMessage):
    if not bots or bots_invalidates <= time.time():
        await _load_bots()

    try:
        args = arg_parser.parse_args(util_bot.delete_spammer_chrs(msg.text), {
            'id': int,
            'name': str,
            'channels': str,

            'verbose': bool,

            1: str
        }, defaults={
            'id': None,
            'name': None,

            'channels': '',

            'verbose': False,

            1: None
        })
    except arg_parser.ParserError as err:
        return f'@{msg.user}, {err.message}'
    print(args)

    if args['name'] and args[1]:
        return f'@{msg.user}, Name argument provided twice.'
    if args[1]:
        args['name'] = args[1]

    if args['id'] is not None:
        name = args['id']
        id_ = True
    elif args['name'] is not None:
        name = args['name']
        id_ = False

        if name.startswith('#'):
            id_ = True
            name = name.lstrip('#')

    else:
        return (f'@{msg.user} {msg.text.split(" ")[0]} (name:TWITCH_USERNAME|id:TWITCH_ID) [+verbose] OR '
                f'{msg.text.split(" ")[0]} TWITCH_USERNAME [+verbose]')
    params = {}
    if id_:
        params['id'] = name.lower()
    else:
        params['login'] = name.lower()

    async with aiohttp.request('get', f'https://api.ivr.fi/v2/twitch/user',
                               params=params,
                               headers={
                                   'User-Agent': util_bot.constants.USER_AGENT
                               }) as request:
        print(request)
        if request.status == 400:
            return f'@{msg.user} Bad username.'
        if request.status == 404:
            return f'@{msg.user} No such user found.'
        users: typing.List[IVRUser] = await request.json(
            loads=lambda *largs, **kwargs: json.loads(*largs, **kwargs, object_hook=_object_hook)
        )
        if len(users) == 0:
            return f'@{msg.user} No such user found.'
        data: IVRUser = users[0]

        roles = ''
        if data.roles.affiliate:
            roles += 'affiliate, '
        if data.roles.partner:
            roles += 'partner, '
        # rip site admin flag
        if any(i.set_id == 'admin' for i in data.badges):
            roles += 'site admin (badge), '
        # if data.roles.get('isSiteAdmin', False):
        #     roles += 'site admin, '
        if data.roles.staff:
            roles += 'staff, '

        if roles == '':
            roles = 'none'

        roles = (roles[::-1].replace(', '[::-1], '', 1))[::-1]
        # replace last ", " with "".

        if data.display_name.casefold() != data.login.casefold():
            login = f'({data.login})'
        else:
            login = ''
        print(data)

        created_at_str = ''
        for i in data.created_at:
            if i == '.':
                break
            created_at_str += i
        created_at_str = created_at_str.rstrip('Z')

        created_on = datetime.datetime.strptime(created_at_str, '%Y-%m-%dT%H:%M:%S')
        logo_warning = ''
        if data.logo.startswith('https://static-cdn.jtvnw.net/user-default-pictures'):
            logo_warning = 'avatar: DEFAULT, '

        bot_notes = ''
        bot = _find_bot(data.login)
        if bot is not None:
            if args['verbose']:
                last_active = f', Last active: {bot["lastSeen"][:-4]}' if bot['lastSeen'] is not None else ''
            else:
                last_active = ''

            bot_notes = (f'Prefix: {bot["prefix"] if bot["prefix"] is not None else "<blank>"}, '
                         f'Description: {bot["description"] if bot["description"] is not None else "<blank>"}, '
                         f'Language: {bot["language"] if bot["language"] is not None else "<unknown>"}'
                         f'{last_active}')

        user = f'user {data.display_name}{login}'
        if ' ' in data.display_name:
            user = f'user {data.display_name!r}{login}'
        info = [
            user,
            logo_warning,
            f'chat color: {data.chat_color if data.chat_color else "never set"}',
            f'account created at {created_on}',
            f'roles: {roles}',
            f'id: {data.id}',
            f'bio: {data.bio}' if data.bio is not None else 'empty bio',
            bot_notes,
        ]
        special_warnings = getattr(data, 'special_warning', '')
        if special_warnings:
            info.append(special_warnings)
        if args['verbose']:
            info.append(f'badges: {", ".join(b.set_id + "/" + b.version for b in data.badges)}')

        info_text = ''
        long_text = ''
        for elem in info:
            info_text += f'{elem.strip(",. ")}, ' if elem else ''
            long_text += f' - {elem.strip(",. ")}\n' if elem else ''

        ret_val = (f'@{msg.user}, {"BANNED " if data.banned else ""}{"bot " if data.verified_bot else ""}'
                   + info_text.rstrip('., '))
        if len(ret_val) > 500:
            url = plugin_hastebin.hastebin_addr + await plugin_hastebin.upload(
                long_text
            )
            return f'@{msg.user}, Command output was too long, here\'s a hastebin: {url}'
        else:
            return ret_val
예제 #8
0
    def command_manage_blacklists(self, msg: twitchirc.ChannelMessage):
        argv = main.delete_spammer_chrs(msg.text).rstrip(' ').split(' ', 1)
        if len(argv) == 1:
            return f'@{msg.user}, {plugin_help.all_help[plugin_help.SECTION_COMMANDS]["plonk"]}'
        text = argv[1]
        try:
            kw = arg_parser.parse_args(text, {
                'scope': str,
                'user': str,
                'command': str,
                'expires': datetime.timedelta
            },
                                       defaults={
                                           'scope': None,
                                           'user': None,
                                           'command': None,
                                           'expires': None
                                       })
        except arg_parser.ParserError as e:
            return e.message

        if kw['command'] is None:
            return f'@{msg.user}, No `command:...` provided.'
        if kw['user'] is None:
            return f'@{msg.user}, No `user:...` provided.'

        kw['user'] = kw['user'].lower()
        if kw['user'] == 'everyone':
            kw['user'] = True

        kw['scope'] = kw['scope'].lower().strip('#')
        if kw['scope'] != 'global':
            sc = []
            for ch in kw['scope'].split(','):
                ch = ch.lstrip('#').lower()
                if ch not in main.bot.channels_connected:
                    return f'@{msg.user}, Invalid `scope`: {kw["scope"]!r}, no such channel.'
                sc.append(ch)
            kw['scope'] = sc
        if kw['command'].lower() == 'all':
            kw['command'] = True
        else:
            cmd = None
            for i in main.bot.commands:
                i: main.Command
                if i.chat_command.lower(
                ) == kw['command'] or kw['command'] in i.aliases:
                    cmd = i.chat_command
            if cmd is None:
                return f'@{msg.user}, Invalid `command`: {kw["command"]!r}. No such command exists.'
            else:
                kw['command'] = cmd
            del cmd

        if kw['expires']:
            kw['expires'] = datetime.datetime.now() + kw['expires']

        with main.session_scope() as session:
            if kw['scope'] == 'global':
                targets = main.User.get_by_name(
                    kw['user'], session) if kw['user'] is not True else None

                if targets is None or len(targets) == 1:
                    obj = BlacklistEntry(
                        target=targets[0] if targets is not None else targets,
                        command=kw['command']
                        if kw['command'] is not True else None,
                        channel=None,
                        expires_on=kw['expires'],
                        is_active=True)
                    blacklists.append(obj)
                    session.add(obj)
                elif len(targets) == 0:
                    return f'@{msg.user} Failed to find user: {kw["user"]}'
                else:
                    return f'@{msg.user} Found multiple users possible with name {kw["user"]}'
            else:
                for ch in kw['scope']:
                    targets = main.User.get_by_name(
                        kw['user'],
                        session) if kw['user'] is not True else None
                    channels = main.User.get_by_name(ch, session)
                    if len(channels) == 1:
                        if targets is None or len(targets) == 1:
                            obj = BlacklistEntry(
                                target=targets[0]
                                if targets is not None else targets,
                                command=kw['command']
                                if kw['command'] is not True else None,
                                channel=channels[0],
                                expires_on=kw['expires'],
                                is_active=True)
                            blacklists.append(obj)
                            session.add(obj)
                        elif len(targets) == 0:
                            return f'@{msg.user} Failed to find user: {kw["user"]}'
                        else:
                            return f'@{msg.user} Found multiple users possible with name {kw["user"]}'
                    elif len(channels) == 0:
                        return f'@{msg.user} Failed to find channel: {ch}'
                    elif len(channels) > 1:
                        return f'@{msg.user} Found multiple channels possible with name {ch}'
        return f'@{msg.user}, Added blacklist for command {kw["command"]} with scope {kw["scope"]} for {kw["user"]}'