Example #1
0
 def run_enter(self, message: base.Message) -> Optional[str]:
     if self.data.exists('_ended'):
         if self.error_cooldown.fire():
             raise base.UserError(f"Sorry @{message.user}, it's too late to enter! NotLikeThis")
         else:
             return None
     if self.data.exists(message.user.name):
         raise base.UserError(f"@{message.user} Don't worry, you're already entered.")
     self.data.set(message.user.name, cast(twitch.TwitchUser, message.user).display_name)
     return f"@{message.user} You've entered the giveaway, good luck!"
Example #2
0
 def run_aliascom(self, message: base.Message, name: str, target: str):
     name = normalize(name)
     target = normalize(target)
     if self.data.exists(name):
         raise base.UserError(f'!{name} already exists.')
     if hasattr(self, 'run_' + name):
         raise base.UserError(f"Can't use !{name} for a command.")
     lookup = self._lookup(target)
     if not lookup:
         raise base.UserError(f"!{target} isn't a custom command.")
     target, _ = lookup
     self.data.set(name, {'alias': target})
     if self.discord:
         msg = f'**{message.user}** created **!{name}** as an alias to **!{target}**.'
         self.discord.embed(EMBED_COLOR, msg)
     return f'Added !{name} as an alias to !{target}.'
Example #3
0
    def finish_authorization(self, code: str) -> None:
        try:
            access_token, refresh_token = self._fetch({
                'grant_type':
                'authorization_code',
                'code':
                code,
                'redirect_uri':
                secret.TWITCH_REDIRECT_URI,
            })
        except base.ServerError:
            logger.exception("Couldn't exchange code for token")
            raise

        response = requests.get('https://api.twitch.tv/helix/users',
                                headers={
                                    'Client-ID': secret.TWITCH_CLIENT_ID,
                                    'Authorization': f'Bearer {access_token}'
                                })
        if response.status_code != 200:
            logger.error(
                "Couldn't fetch user info with new bearer token: %d %s",
                response.status_code, response.text)
            raise base.ServerError(f'{response.status_code} {response.text}')
        body = response.json()
        login = body['data'][0]['login']
        if login != self.streamer_username.lower():
            display_name = body['data'][0]['display_name']
            raise base.UserError(
                f"You're logged into Twitch as {display_name}. Please log in "
                f"as {self.streamer_username} to authorize the bot.")

        self.data.set('access_token', access_token)
        self.data.set('refresh_token', refresh_token)
        self.auth_finished.set()
Example #4
0
 def run_roulette(self, message: base.Message, points: int) -> str:
     starting_points = int(self.data.get(message.user.name, default='0'))
     if starting_points < points:
         if not starting_points:
             raise base.UserError("You don't have any points!")
         elif starting_points == 1:
             raise base.UserError('You only have 1 point.')
         raise base.UserError(f'You only have {starting_points} points.')
     if random.randint(0, 1):
         new_points = starting_points + points
         self.data.set(message.user.name, str(new_points))
         return f'{message.user} won {points} points and now has {new_points} points!'
     else:
         new_points = starting_points - points
         self.data.set(message.user.name, str(new_points))
         return f'{message.user} lost {points} points and now has {new_points} points.'
Example #5
0
 def run_resetcount(self, name: str, count: Optional[int]) -> str:
     if count is None:
         count = 0
     name = normalize(name)
     lookup = self._lookup(name)
     if not lookup:
         raise base.UserError(f"!{name} doesn't exist")
     name, _ = lookup
     self.data.set_subkey(name, 'count', str(count))
     return f'Reset !{name} counter to {count}.'
Example #6
0
 def run_addcom(self, message: base.Message, name: str, text: str) -> str:
     name = normalize(name)
     if self.data.exists(name):
         raise base.UserError(f'!{name} already exists.')
     if hasattr(self, 'run_' + name):
         raise base.UserError(f"Can't use !{name} for a command.")
     self.data.set(
         name, {
             'response':
             text,
             'count':
             '0',
             'cooldowns':
             repr(
                 cooldown.GlobalAndUserCooldowns(
                     datetime.timedelta(seconds=5), None)),
         })
     if self.discord:
         msg = f'**{message.user}** created the command **!{name}**:\n\n{text}'
         self.discord.embed(EMBED_COLOR, msg)
     return f'Added !{name}.'
Example #7
0
 def run(
     self, event: impbot.connections.twitch_eventsub.PointsRewardRedemption
 ) -> Optional[str]:
     if datetime.now() > END_TIME:
         if self.error_cooldown.fire():
             raise base.UserError(
                 f"Sorry @{event.user}, it's too late to enter! NotLikeThis"
             )
         else:
             return None
     entries = int(self.data.get(event.user.name, default='0'))
     if entries == MAX_ENTRIES:
         raise base.UserError(
             f'Sorry @{event.user}, you already have the max {MAX_ENTRIES} entries.'
         )
     entries += 1
     self.data.set(event.user.name, str(entries))
     if entries == MAX_ENTRIES:
         return (
             f"@{event.user} You've entered {entries} times now -- that's the maximum, "
             "good luck!")
     else:
         return None
Example #8
0
    def run_followage(self, message: base.Message, who: Optional[str]):
        if not who:
            who = message.user.name
        if who.startswith('@'):
            who = who[1:]
        try:
            from_id = self.twitch_util.get_channel_id(who)
        except KeyError:
            raise base.UserError(f"@{message.user} {who} isn't a Twitch user.")
        to_id = self.twitch_util.get_channel_id(self.streamer_username)
        body = self.twitch_util.helix_get('users/follows', {
            'from_id': from_id,
            'to_id': to_id
        })
        if not body['data']:
            if who.lower() == message.user.name.lower():
                return f"@{message.user} You aren't following {self.streamer_username}."
            else:
                return f"{who} isn't following {self.streamer_username}."

        data = body['data'][0]
        if who.lower() == message.user.name.lower():
            name_has = f"@{message.user} You've"
        else:
            name_has = f'{data["from_name"]} has'

        since_str = data['followed_at']
        since = date.fromisoformat(since_str[:len('YYYY-MM-DD')])
        if (date.today() - since) < timedelta(days=365):
            since_str = since.strftime('%B %d').replace(' 0', ' ')
        else:
            since_str = since.strftime('%B %d, %Y').replace(' 0', ' ')

        if since == date.today():
            duration = 'today'
        elif since == date.today() - timedelta(days=1):
            duration = 'yesterday'
        elif since < date.today():
            days = (date.today() - since).days
            duration = f'{days:,} days ago'
        else:
            duration = 'the future??'

        return (
            f'{name_has} been following {self.streamer_username} since {since_str} ({duration}).'
        )
Example #9
0
    def run(self, message: base.Message) -> Optional[str]:
        # If CommandHandler's check() passes, this is a built-in like !addcom, so let
        # CommandHandler's run() dispatch to it.
        if super().check(message):
            # As it happens, all the builtins are for mods only, so we'll do that check here.
            # TODO: Real per-command ACLs.
            if not (message.user.moderator or message.user.admin):
                raise base.UserError("You can't do that.")
            return super().run(message)
        # Otherwise, it's a custom command so we do our own thing.

        # self.lookup is guaranteed non-None by check().
        name, comm = cast(Tuple[str, CommandDict], self.lookup)
        if 'cooldowns' in comm:
            cooldowns = eval(comm['cooldowns'])
            if not cooldowns.fire(message.user):
                return None
            self.data.set_subkey(name, 'cooldowns', repr(cooldowns))
        count = int(comm['count']) + 1
        self.data.set_subkey(name, 'count', str(count))
        return comm['response'].replace('(count)', f'{count:,}')
Example #10
0
 def run_delcom(self, message: base.Message, name: str) -> str:
     name = normalize(name)
     try:
         comm = self.data.get_dict(name)
     except KeyError:
         raise base.UserError(f"!{name} doesn't exist.")
     self.data.unset(name)
     if 'alias' in comm:
         target = comm['alias']
         if self.discord:
             self.discord.embed(
                 EMBED_COLOR,
                 f'**{message.user}** deleted the command **!{name}** (alias to **!{target}**).'
             )
         return f'Deleted !{name}. (It was an alias to !{target}.)'
     else:
         if self.discord:
             msg = f'**{message.user}** deleted the command **!{name}**.'
             fields = {'Old response': comm['response']}
             if '(count)' in comm['response']:
                 fields['Count'] = comm['count']
             self.discord.embed(EMBED_COLOR, msg, fields)
         return f'Deleted !{name}.'
Example #11
0
 def game_id(self, game_name: str) -> str:
     body = self.helix_get('games', {'name': game_name})
     if not body['data']:
         raise base.UserError(f'No such game "{game_name}"')
     return body['data'][0]['id']