Example #1
0
    def progress_quest(self, amount, limit, completion_reward):
        """ Progress the quest for `stream_id` by `amount`.
        We load data from redis in case no progress has been made yet.
        """
        streamer = StreamHelper.get_streamer()
        stream_id = StreamHelper.get_current_stream_id()

        if stream_id is False:
            return False

        redis = RedisManager.get()
        quest_progress_key = '{streamer}:{stream_id}:{username}:quest_progress'.format(
                streamer=streamer,
                stream_id=stream_id,
                username=self.username)

        if stream_id not in self.quest_progress:
            # Load the old progress, or set it to 0 if no progress was found
            self.init_quest_progress()

        if self.quest_progress[stream_id] >= limit:
            # The user has already completed this quest.
            return False

        self.quest_progress[stream_id] += amount

        if self.quest_progress[stream_id] >= limit:
            # The user just completed the quest for the first time
            self.award_tokens(completion_reward, redis=redis)
            return False

        redis.set(quest_progress_key, self.quest_progress[stream_id])
Example #2
0
    def award_tokens(self, tokens, redis=None, force=False):
        """ Returns True if tokens were awarded properly.
        Returns False if not.
        Tokens can only be rewarded once per stream ID.
        """

        streamer = StreamHelper.get_streamer()
        stream_id = StreamHelper.get_current_stream_id()

        if stream_id is False:
            return False

        if redis is None:
            redis = RedisManager.get()

        key = '{streamer}:{username}:tokens'.format(
                streamer=streamer, username=self.username)

        if force:
            res = True
            redis.hset(key, stream_id, tokens)
        else:
            res = True if redis.hsetnx(key, stream_id, tokens) == 1 else False
            if res is True:
                HandlerManager.trigger('on_user_gain_tokens', self, tokens)
        return res
Example #3
0
    def update_emotes(self):
        log.debug('Updating BTTV Emotes...')
        global_emotes = self.bttv_api.get_global_emotes()
        channel_emotes = self.bttv_api.get_channel_emotes(StreamHelper.get_streamer())

        self.global_emotes = [emote['code'] for emote in global_emotes]
        self.channel_emotes = [emote['code'] for emote in channel_emotes]

        # Store channel emotes in redis
        streamer = StreamHelper.get_streamer()
        key = '{streamer}:emotes:bttv_channel_emotes'.format(streamer=streamer)
        with RedisManager.pipeline_context() as pipeline:
            pipeline.delete(key)
            for emote in channel_emotes:
                pipeline.hset(key, emote['code'], emote['emote_hash'])

        self.all_emotes = []
        with RedisManager.pipeline_context() as pipeline:
            for emote in global_emotes + channel_emotes:
                # Store all possible emotes, with their regex in an easily
                # accessible list.
                self.all_emotes.append(self.build_emote(emote['code'], emote['emote_hash']))

                # Make sure all available emotes are available in redis
                pipeline.hset('global:emotes:bttv', emote['code'], emote['emote_hash'])
Example #4
0
    def on_stream_stop(self):
        if self.current_quest is None:
            log.info('No quest active on stream stop.')
            return False

        self.current_quest.stop_quest()
        self.current_quest = None
        self.bot.say('Stream ended, quest has been reset.')

        redis = RedisManager.get()

        # Remove any mentions of the current quest
        redis.delete(self.current_quest_key)

        last_stream_id = StreamHelper.get_last_stream_id()
        if last_stream_id is False:
            log.error('No last stream ID found.')
            # No last stream ID found. why?
            return False

        # XXX: Should we use a pipeline for any of this?
        # Go through user tokens and remove any from more than 2 streams ago
        for key in redis.keys('{streamer}:*:tokens'.format(streamer=StreamHelper.get_streamer())):
            all_tokens = redis.hgetall(key)
            for stream_id_str in all_tokens:
                try:
                    stream_id = int(stream_id_str)
                except (TypeError, ValueError):
                    log.error('Invalid stream id in tokens by {}'.format(key))
                    continue

                if last_stream_id - stream_id > 1:
                    log.info('Removing tokens for stream {}'.format(stream_id))
                    redis.hdel(key, stream_id)
Example #5
0
    def banned(self, value):
        # Set cached value
        self.values['banned'] = value

        if value is True:
            # Set redis value
            self.redis.hset('{streamer}:users:banned'.format(streamer=StreamHelper.get_streamer()), self.username, 1)
        else:
            self.redis.hdel('{streamer}:users:banned'.format(streamer=StreamHelper.get_streamer()), self.username)
Example #6
0
    def username_raw(self, value):
        # Set cached value
        self.values['username_raw'] = value

        # Set redis value
        if value != self.username:
            self.redis.hset('{streamer}:users:username_raw'.format(streamer=StreamHelper.get_streamer()), self.username, value)
        else:
            self.redis.hdel('{streamer}:users:username_raw'.format(streamer=StreamHelper.get_streamer()), self.username)
Example #7
0
    def tokens(self, value):
        # Set cached value
        self.values['tokens'] = value

        if self.save_to_redis:
            # Set redis value
            if value != 0:
                self.redis.zadd('{streamer}:users:tokens'.format(streamer=StreamHelper.get_streamer()), self.username, value)
            else:
                self.redis.zrem('{streamer}:users:tokens'.format(streamer=StreamHelper.get_streamer()), self.username)
Example #8
0
    def update_channel_emotes(self):
        _channel_emotes = self.api.get_channel_emotes(StreamHelper.get_streamer())
        self.channel_emotes = {}
        for emote in _channel_emotes:
            self.channel_emotes[emote['code']] = emote['emote_hash']

        # Store channel emotes in redis
        streamer = StreamHelper.get_streamer()
        key = '{streamer}:emotes:bttv_channel_emotes'.format(streamer=streamer)
        with RedisManager.pipeline_context() as pipeline:
            pipeline.delete(key)
            for emote_code, emote_hash in self.channel_emotes.items():
                pipeline.hset(key, emote_code, emote_hash)
Example #9
0
File: app.py Project: kzf/pajbot
def test():
    redis = RedisManager.get()
    current_quest_key = '{streamer}:current_quest'.format(streamer=StreamHelper.get_streamer())
    current_quest_id = redis.get(current_quest_key)
    current_quest = module_manager[current_quest_id]
    current_quest.load_data()
    return render_template('test.html', current_quest=current_quest)
Example #10
0
    def _last_active(self, value):
        # Set cached value
        value = value.timestamp()
        self.values['last_active'] = value

        # Set redis value
        self.redis.hset('{streamer}:users:last_active'.format(streamer=StreamHelper.get_streamer()), self.username, value)
Example #11
0
    def spend_tokens(self, tokens_to_spend, redis=None):
        if redis is None:
            redis = RedisManager.get()

        user_token_key = '{streamer}:{username}:tokens'.format(
                streamer=StreamHelper.get_streamer(), username=self.username)

        token_dict = redis.hgetall(user_token_key)

        for stream_id in token_dict:
            try:
                num_tokens = int(token_dict[stream_id])
            except (TypeError, ValueError):
                continue

            if num_tokens == 0:
                continue

            decrease_by = min(tokens_to_spend, num_tokens)
            tokens_to_spend -= decrease_by
            num_tokens -= decrease_by

            redis.hset(user_token_key, stream_id, num_tokens)

            if tokens_to_spend == 0:
                return True

        return False
Example #12
0
    def pleblist_add_song(self, **options):
        message = options['message']
        bot = options['bot']
        source = options['source']

        if message:
            # 1. Find youtube ID in message
            msg_split = message.split(' ')
            youtube_id = find_youtube_id_in_string(msg_split[0])

            force = False

            try:
                if msg_split[1] == 'force' and source.level >= 500:
                    force = True
            except:
                pass

            if youtube_id is False:
                bot.whisper(source.username, 'Could not find a valid youtube ID in your argument.')
                return False

            # 2. Make sure the stream is live
            stream_id = StreamHelper.get_current_stream_id()
            if stream_id is None or stream_id is False:
                bot.whisper(source.username, 'You cannot request songs while the stream is offline.')
                return False

            ScheduleManager.execute_now(self.bg_pleblist_add_song, args=[stream_id, youtube_id, force], kwargs=options)
Example #13
0
    def stats():
        bot_commands_list = pajbot.web.utils.get_cached_commands()
        top_5_commands = sorted(bot_commands_list, key=lambda c: c['data']['num_uses'] if c['data'] is not None else -1, reverse=True)[:5]

        redis = RedisManager.get()

        # TODO: Make this hideable through some magic setting (NOT config.ini @_@)
        with DBManager.create_session_scope() as db_session:
            top_5_line_farmers = []
            for redis_user in redis.zrevrangebyscore(
                    '{streamer}:users:num_lines'.format(streamer=StreamHelper.get_streamer()),
                    '+inf',
                    '-inf',
                    start=0,
                    num=5,
                    withscores=True,
                    score_cast_func=int):
                user = UserManager.get_static(redis_user[0], db_session=db_session)
                user.save_to_redis = False
                user.num_lines = redis_user[1]
                top_5_line_farmers.append(user)

            return render_template('stats.html',
                    top_5_commands=top_5_commands,
                    top_5_line_farmers=top_5_line_farmers)
Example #14
0
    def incr_num_lines(self):
        # Set cached value
        self.values['num_lines'] = self.num_lines + 1

        if self.save_to_redis:
            # Set redis value
            self.redis.zincrby('{streamer}:users:num_lines'.format(streamer=StreamHelper.get_streamer()), value=self.username, amount=1.0)
Example #15
0
 def num_lines_rank(self):
     key = '{streamer}:users:num_lines'.format(streamer=StreamHelper.get_streamer())
     rank = self.redis.zrevrank(key, self.username)
     if rank is None:
         return self.redis.zcard(key)
     else:
         return rank + 1
Example #16
0
    def delete(self, **options):
        # Add a single tag to the email
        args = self.delete_parser.parse_args()

        email = args['email'].lower()
        new_tag = args['tag'].lower()
        streamer = StreamHelper.get_streamer()

        key = '{streamer}:email_tags'.format(streamer=streamer)
        redis = RedisManager.get()

        tags_str = redis.hget(key, email)

        if tags_str is None:
            tags = []
        else:
            tags = json.loads(tags_str)

        # Is the tag already active?
        if new_tag not in tags:
            return {
                    'message': 'This tag is not set on the email.'
                    }, 409

        tags.remove(new_tag)

        if len(tags) > 0:
            redis.hset(key, email, json.dumps(tags))
        else:
            redis.hdel(key, email)

        return {
                'message': 'Successfully removed the tag {} from {}'.format(new_tag, email)
                }
Example #17
0
    def post(self, **options):
        # Add a single tag to the email
        args = self.post_parser.parse_args()

        email = args['email'].lower()
        new_tag = args['tag'].lower()
        if len(new_tag) == 0:
            return {
                    'message': 'The tag must be at least 1 character long.'
                    }, 400
        streamer = StreamHelper.get_streamer()

        key = '{streamer}:email_tags'.format(streamer=streamer)
        redis = RedisManager.get()

        tags_str = redis.hget(key, email)

        if tags_str is None:
            tags = []
        else:
            tags = json.loads(tags_str)

        # Is the tag already active?
        if new_tag in tags:
            return {
                    'message': 'This tag is already set on the email.'
                    }, 409

        tags.append(new_tag)

        redis.hset(key, email, json.dumps(tags))

        return {
                'message': 'Successfully added the tag {} to {}'.format(new_tag, email)
                }
Example #18
0
    def get_emote_epmrecord(self, emote_code):
        redis = RedisManager.get()
        streamer = StreamHelper.get_streamer()

        emote_count = redis.zscore('{streamer}:emotes:epmrecord'.format(streamer=streamer), emote_code)
        if emote_count:
            return int(emote_count)
        return None
Example #19
0
 def __init__(self):
     from pajbot.apiwrappers import BTTVApi
     self.bttv_api = BTTVApi()
     self.global_emotes = []
     streamer = StreamHelper.get_streamer()
     redis = RedisManager.get()
     self.channel_emotes = redis.lrange('{streamer}:emotes:bttv_channel_emotes'.format(streamer=streamer), 0, -1)
     self.all_emotes = []
Example #20
0
def donations(widget_id, **options):
    redis = RedisManager.get()
    widget = redis.hget(
            '{streamer}:clr:donations'.format(streamer=StreamHelper.get_streamer()),
            widget_id)
    if widget is None:
        abort(404)

    widget = json.loads(widget)

    # Assign indices to all styles and conditions
    i = 0
    log.info(widget['styles'])
    for style in widget['styles']:
        style['index'] = i
        i += 1
    log.info(widget['styles'])
    i = 0
    j = 0
    for condition in widget['conditions']:
        condition['index'] = i
        i += 1
        for style in condition['styles']:
            style['index'] = j
            j += 1
    log.info(widget)

    operator_order = {
            '==': 100,
            '>=': 50,
            '<=': 50,
            }

    widget['conditions'].sort(key=lambda c: (operator_order[c['operator']], c['amount']))

    tts_authentication = ''
    if 'extra' in config:
        tts_authentication = config['extra'].get('tts_authentication', '')

    redis = RedisManager.get()
    twitch_emotes = redis.hgetall('global:emotes:twitch')
    bttv_emotes = redis.hgetall('global:emotes:bttv')
    emotes = []
    for emote in twitch_emotes:
        emotes.append({
            'code': emote,
            'emote_id': twitch_emotes[emote],
            })
    for emote in bttv_emotes:
        emotes.append({
            'code': emote,
            'emote_hash': bttv_emotes[emote],
            })
    emotes.sort(key=lambda emote: len(emote['code']), reverse=True)
    return render_template('clr/donations.html',
            widget=widget,
            emotes=emotes,
            tts_authentication=tts_authentication)
Example #21
0
 def queue_up_redis_calls(self, pipeline):
     streamer = StreamHelper.get_streamer()
     # Queue up calls to the pipeline
     for key in UserRedis.SS_KEYS:
         pipeline.zscore('{streamer}:users:{key}'.format(streamer=streamer, key=key), self.username)
     for key in UserRedis.HASH_KEYS:
         pipeline.hget('{streamer}:users:{key}'.format(streamer=streamer, key=key), self.username)
     for key in UserRedis.BOOL_KEYS:
         pipeline.hget('{streamer}:users:{key}'.format(streamer=streamer, key=key), self.username)
Example #22
0
    def init_quest_progress(self, redis=None):
        """ Initialize quest progress for the current stream. """
        streamer = StreamHelper.get_streamer()
        stream_id = StreamHelper.get_current_stream_id()
        if redis is None:
            redis = RedisManager.get()

        quest_progress_key = '{streamer}:{stream_id}:{username}:quest_progress'.format(
                streamer=streamer,
                stream_id=stream_id,
                username=self.username)

        old_progress = 0
        try:
            old_progress = int(redis.get(quest_progress_key))
        except (TypeError, ValueError):
            pass
        self.quest_progress[stream_id] = old_progress
Example #23
0
 def __init__(self):
     super().__init__()
     # XXX: This key should probably be generic and always set in the BaseQuest
     self.points_required_key = "{streamer}:current_quest_points_required".format(
         streamer=StreamHelper.get_streamer()
     )
     # The points_required variable is randomized at the start of the quest.
     # It will be a value between settings['min_value'] and settings['max_value']
     self.points_required = None
     self.progress = {}
Example #24
0
    def get_quest_progress(self):
        stream_id = StreamHelper.get_current_stream_id()

        if stream_id is False:
            return False

        if stream_id not in self.quest_progress:
            self.init_quest_progress()

        return self.quest_progress[stream_id]
Example #25
0
File: app.py Project: kzf/pajbot
def index():
    custom_content = custom_web_content.get('home', '')
    try:
        custom_content = Markup(markdown.markdown(custom_content))
    except:
        log.exception('Unhandled exception in def index')

    redis = RedisManager.get()
    streamer = StreamHelper.get_streamer()

    keys = ('online', 'viewers', 'game')
    stream_data_keys = ['{streamer}:{key}'.format(streamer=streamer, key=key) for key in keys]
    stream_data_list = redis.hmget('stream_data', stream_data_keys)
    stream_data = {keys[x]: stream_data_list[x] for x in range(0, len(keys))}

    keys = StreamHelper.social_keys
    streamer_info_keys = ['{streamer}:{key}'.format(streamer=streamer, key=key) for key in keys.keys()]
    log.info(streamer_info_keys)
    streamer_info_list = redis.hmget('streamer_info', streamer_info_keys)
    streamer_info = collections.OrderedDict()
    for key in keys:
        value = streamer_info_list.pop(0)
        if value:
            streamer_info[key] = {
                    'value': keys[key]['format'].format(value),
                    'title': keys[key]['title'],
                    'format': keys[key]['format'],
                    }

    current_quest_key = '{streamer}:current_quest'.format(streamer=StreamHelper.get_streamer())
    current_quest_id = redis.get(current_quest_key)
    if current_quest_id is not None:
        current_quest = module_manager[current_quest_id]
        if current_quest:
            current_quest.load_data()
    else:
        current_quest = None

    return render_template('index.html',
            custom_content=custom_content,
            current_quest=current_quest,
            stream_data=stream_data,
            streamer_info=streamer_info)
Example #26
0
    def load_cached_channel_emotes(self):
        streamer = StreamHelper.get_streamer()

        # Try to get the list of global emotes from redis
        try:
            _channel_emotes = RedisManager.get().hgetall('{streamer}:emotes:bttv_channel_emotes'.format(streamer=streamer))
        except:
            _channel_emotes = {}

        for code in _channel_emotes:
            emote_hash = _channel_emotes[code]
            self.channel_emotes[code] = emote_hash
Example #27
0
File: api.py Project: coral/pajbot
        def post(self, widget_id, **options):
            args = self.post_parser.parse_args()

            # special case for boolean values
            args['tts'] = args['tts'] == 'true'

            streamer = StreamHelper.get_streamer()
            key = '{streamer}:clr:donations'.format(streamer=streamer)
            redis = RedisManager.get()
            redis.hset(key, widget_id, json.dumps(args))

            return {
                    'message': 'GOT EM'
                    }, 200
Example #28
0
    def on_user_sub(self, user):
        if self.settings['multi_raffle_on_sub'] is False:
            return

        MAX_REWARD = 10000

        points = StreamHelper.get_viewers() * 5
        if points == 0:
            points = 100
        length = 30

        points = min(points, MAX_REWARD)

        self.multi_start_raffle(points, length)
Example #29
0
    def clr_donations_edit(widget_id, **options):
        redis = RedisManager.get()
        widget = redis.hget(
                '{streamer}:clr:donations'.format(streamer=StreamHelper.get_streamer()),
                widget_id)
        new = False
        if widget is None:
            widget = {}
            new = True
        else:
            widget = json.loads(widget)

        return render_template('admin/clr/donations/edit.html',
                widget_id=widget_id,
                widget_data=json.dumps(widget),
                new=new)
Example #30
0
    def get_tokens(self, redis=None):
        streamer = StreamHelper.get_streamer()
        if redis is None:
            redis = RedisManager.get()

        tokens = redis.hgetall('{streamer}:{username}:tokens'.format(
            streamer=streamer, username=self.username))

        num_tokens = 0
        for token_value in tokens.values():
            try:
                num_tokens += int(token_value)
            except (TypeError, ValueError):
                log.warn('Invalid value for tokens, user {}'.format(self.username))

        return num_tokens
Example #31
0
    def top_emotes(self, bot, **rest):
        redis = RedisManager.get()
        streamer = StreamHelper.get_streamer()
        num_emotes = self.settings["num_top_emotes"]

        top_emotes = {
            emote: emote_count
            for emote, emote_count in sorted(
                redis.zscan_iter(f"{streamer}:emotes:count"),
                key=lambda e_ecount_pair: e_ecount_pair[1],
                reverse=True)[:num_emotes]
        }
        if top_emotes:
            top_list_str = ", ".join(
                f"{emote} ({emote_count:,.0f})"
                for emote, emote_count in top_emotes.items())
            bot.say(f"Top {num_emotes} emotes: {top_list_str}")
        else:
            bot.say("No emote data available")
Example #32
0
    def on_stream_stop(self):
        if self.current_quest is None:
            log.info('No quest active on stream stop.')
            return False

        self.current_quest.stop_quest()
        self.current_quest = None
        self.bot.say('Stream ended, quest has been reset.')

        redis = RedisManager.get()

        # Remove any mentions of the current quest
        redis.delete(self.current_quest_key)

        last_stream_id = StreamHelper.get_last_stream_id()
        if last_stream_id is False:
            log.error('No last stream ID found.')
            # No last stream ID found. why?
            return False
Example #33
0
 def admin_streamer(**options):
     redis = RedisManager.get()
     streamer = StreamHelper.get_streamer()
     keys = StreamHelper.social_keys
     streamer_info_keys = [
         "{streamer}:{key}".format(streamer=streamer, key=key)
         for key in keys.keys()
     ]
     log.info(streamer_info_keys)
     streamer_info_list = redis.hmget("streamer_info", streamer_info_keys)
     streamer_info = collections.OrderedDict()
     for key in keys:
         value = streamer_info_list.pop(0)
         streamer_info[key] = {
             "value": value,
             "title": keys[key]["title"],
             "format": keys[key]["format"]
         }
     return render_template("admin/streamer.html",
                            streamer_info=streamer_info)
Example #34
0
 def admin_streamer(**options):
     redis = RedisManager.get()
     streamer = StreamHelper.get_streamer()
     keys = StreamHelper.social_keys
     streamer_info_keys = [
         '{streamer}:{key}'.format(streamer=streamer, key=key)
         for key in keys.keys()
     ]
     log.info(streamer_info_keys)
     streamer_info_list = redis.hmget('streamer_info', streamer_info_keys)
     streamer_info = collections.OrderedDict()
     for key in keys:
         value = streamer_info_list.pop(0)
         streamer_info[key] = {
             'value': value,
             'title': keys[key]['title'],
             'format': keys[key]['format'],
         }
     return render_template('admin/streamer.html',
                            streamer_info=streamer_info)
Example #35
0
 def print_emotes(self, source, manager):
     if self.settings[
             f"custom_{manager.friendly_name.lower()}_response"] != "":
         custom_message = self.settings[
             f"custom_{manager.friendly_name.lower()}_response"]
         self.bot.say(
             custom_message.format(streamer=StreamHelper.get_streamer(),
                                   source=source))
     else:
         emotes = manager.channel_emotes
         messages = split_into_chunks_with_prefix(
             [{
                 "prefix": f"{manager.friendly_name} emotes:",
                 "parts": [e.code for e in emotes]
             }],
             default=
             f"No {manager.friendly_name} Emotes active in this chat :(",
         )
         for message in messages:
             self.bot.say(message)
Example #36
0
def get_top_emotes() -> List[Dict[str, str]]:
    redis = RedisManager.get()
    streamer = StreamHelper.get_streamer()

    top_emotes_list: List[Dict[str, str]] = []
    top_emotes = {
        emote: emote_count
        for emote, emote_count in sorted(
            redis.zscan_iter(f"{streamer}:emotes:count"),
            key=lambda e_ecount_pair: e_ecount_pair[1],
            reverse=True)[:100]
    }

    if top_emotes:
        top_emotes_list.extend({
            "emote_name": emote,
            "emote_count": str(int(emote_count))
        } for emote, emote_count in top_emotes.items())

    return top_emotes_list
Example #37
0
    def home():
        custom_content = ""

        redis = RedisManager.get()
        streamer = StreamHelper.get_streamer()

        keys = ("online", "viewers", "game")
        stream_data_keys = [f"{streamer}:{key}" for key in keys]
        stream_data_list = redis.hmget("stream_data", stream_data_keys)
        stream_data = {keys[x]: stream_data_list[x] for x in range(0, len(keys))}

        keys = StreamHelper.social_keys
        streamer_info_keys = [f"{streamer}:{key}" for key in keys.keys()]
        log.info(streamer_info_keys)
        streamer_info_list = redis.hmget("streamer_info", streamer_info_keys)
        streamer_info = collections.OrderedDict()
        for key in keys:
            value = streamer_info_list.pop(0)
            if value:
                streamer_info[key] = {
                    "value": keys[key]["format"].format(value),
                    "title": keys[key]["title"],
                    "format": keys[key]["format"],
                }

        current_quest_key = f"{StreamHelper.get_streamer()}:current_quest"
        current_quest_id = redis.get(current_quest_key)
        if current_quest_id is not None:
            current_quest = app.module_manager[current_quest_id]
            if current_quest:
                current_quest.load_data()
        else:
            current_quest = None

        return render_template(
            "home.html",
            custom_content=custom_content,
            current_quest=current_quest,
            stream_data=stream_data,
            streamer_info=streamer_info,
        )
Example #38
0
    def finish_quest(self, redis, user):
        if not self.quest_module:
            log.error("Quest module not initialized")
            return

        stream_id = StreamHelper.get_current_stream_id()

        # Load user's finished quest status
        val = redis.hget(self.quest_finished_key, user.id)
        if val:
            quests_finished = json.loads(val)
        else:
            quests_finished = []

        if stream_id in quests_finished:
            # User has already completed this quest
            return

        reward_type = self.quest_module.settings["reward_type"]
        reward_amount = self.quest_module.settings["reward_amount"]

        if reward_type == "tokens" and user.tokens > self.quest_module.settings["max_tokens"]:
            message = (
                "You finished todays quest, but you have more than the max tokens allowed already. Spend some tokens!"
            )
            self.bot.whisper(user, message)
            return

        # Mark the current stream ID has finished
        quests_finished.append(stream_id)
        redis.hset(self.quest_finished_key, user.id, json.dumps(quests_finished, separators=(",", ":")))

        # Award the user appropriately
        if reward_type == "tokens":
            user.tokens += reward_amount
        else:
            user.points += reward_amount

        # Notify the user that they've finished today's quest
        message = f"You finished todays quest! You have been awarded with {reward_amount} {reward_type}."
        self.bot.whisper(user, message)
Example #39
0
    def __init__(self):
        from pajbot.apiwrappers import BTTVApi
        self.api = BTTVApi()
        self.global_emotes = []
        streamer = StreamHelper.get_streamer()
        _global_emotes = RedisManager.get().hgetall('global:emotes:bttv')
        try:
            _channel_emotes = RedisManager.get().hgetall(
                '{streamer}:emotes:bttv_channel_emotes'.format(
                    streamer=streamer))
        except:
            _channel_emotes = {}

        self.channel_emotes = list(_channel_emotes.keys())

        _all_emotes = _global_emotes.copy()
        _all_emotes.update(_channel_emotes)

        self.all_emotes = []
        for emote_code, emote_hash in _all_emotes.items():
            self.all_emotes.append(self.build_emote(emote_code, emote_hash))
Example #40
0
def get_cached_commands():
    CACHE_TIME = 30  # seconds

    redis = RedisManager.get()
    commands_key = '{streamer}:cache:commands'.format(streamer=StreamHelper.get_streamer())
    commands = redis.get(commands_key)
    if commands is None:
        log.debug('Updating commands...')
        bot_commands = pajbot.managers.command.CommandManager(
                socket_manager=None,
                module_manager=ModuleManager(None).load(),
                bot=None).load(load_examples=True)
        bot_commands_list = bot_commands.parse_for_web()

        bot_commands_list.sort(key=lambda x: (x.id or -1, x.main_alias))
        bot_commands_list = [c.jsonify() for c in bot_commands_list]
        redis.setex(commands_key, json.dumps(bot_commands_list, separators=(',', ':')), CACHE_TIME)
    else:
        bot_commands_list = json.loads(commands)

    return bot_commands_list
Example #41
0
    def pleblist_add_song(self, **options):
        message = options['message']
        bot = options['bot']
        source = options['source']

        if message:
            # 1. Find youtube ID in message
            msg_split = message.split(' ')
            youtube_id = find_youtube_id_in_string(msg_split[0])

            if youtube_id is False:
                bot.whisper(source.username, 'Could not find a valid youtube ID in your argument.')
                return False

            # 2. Make sure the stream is live
            stream_id = StreamHelper.get_current_stream_id()
            if stream_id is None or stream_id is False:
                bot.whisper(source.username, 'You cannot request songs while the stream is offline.')
                return False

            ScheduleManager.execute_now(self.bg_pleblist_add_song, args=[stream_id, youtube_id], kwargs=options)
Example #42
0
        def get(self, **options):
            args = self.get_parser.parse_args()

            email = args['email'].lower()
            streamer = StreamHelper.get_streamer()

            key = '{streamer}:email_tags'.format(streamer=streamer)
            redis = RedisManager.get()

            tags_str = redis.hget(key, email)

            payload = {}

            if tags_str is None:
                tags = []
            else:
                tags = json.loads(tags_str)

            payload['tags'] = tags

            return payload
Example #43
0
    def stats():
        bot_commands_list = pajbot.web.utils.get_cached_commands()
        top_5_commands = sorted(
            bot_commands_list, key=lambda c: c["data"]["num_uses"] if c["data"] is not None else -1, reverse=True
        )[:5]

        redis = RedisManager.get()

        # TODO: Make this hideable through some magic setting (NOT config.ini @_@)
        with DBManager.create_session_scope() as db_session:
            top_5_line_farmers = []
            for redis_user in redis.zrevrangebyscore(
                "{streamer}:users:num_lines".format(streamer=StreamHelper.get_streamer()),
                "+inf",
                "-inf",
                start=0,
                num=5,
                withscores=True,
                score_cast_func=int,
            ):
                user = UserManager.get_static(redis_user[0], db_session=db_session)
                user.save_to_redis = False
                top_5_line_farmers.append(user)

            data = {
                "top_5_duel_winners": db_session.query(UserDuelStats).order_by(UserDuelStats.duels_won.desc())[:5],
                "top_5_duel_points_won": db_session.query(UserDuelStats).order_by(UserDuelStats.profit.desc())[:5],
                "top_5_duel_points_lost": db_session.query(UserDuelStats).order_by(UserDuelStats.profit.asc())[:5],
                "top_5_duel_losers": db_session.query(UserDuelStats).order_by(UserDuelStats.duels_lost.desc())[:5],
                "top_5_duel_winrate": db_session.query(UserDuelStats)
                .filter(UserDuelStats.duels_won >= 5)
                .order_by(UserDuelStats.winrate.desc())[:5],
                "bottom_5_winrate": db_session.query(UserDuelStats)
                .filter(UserDuelStats.duels_lost >= 5)
                .order_by(UserDuelStats.winrate.asc())[:5],
                "top_5_commands": top_5_commands,
                "top_5_line_farmers": top_5_line_farmers,
            }

            return render_template("stats.html", **data)
Example #44
0
    def finish_quest(self, redis, user):
        stream_id = StreamHelper.get_current_stream_id()

        # Load user's finished quest status
        val = redis.hget(self.quest_finished_key, user.username)
        if val:
            quests_finished = json.loads(val)
        else:
            quests_finished = []

        if stream_id in quests_finished:
            # User has already completed this quest
            return

        # Mark the current stream ID has finished
        quests_finished.append(stream_id)
        redis.hset(self.quest_finished_key, user.username,
                   json.dumps(quests_finished, separators=(',', ':')))

        # Award the user appropriately
        reward_type = self.quest_module.settings['reward_type']
        reward_amount = self.quest_module.settings['reward_amount']
        if reward_type == 'tokens':
            user.tokens += reward_amount
        else:
            user.points += reward_amount

        # Make sure the user doesn't have more tokens than allowed
        if user.tokens > self.quest_module.settings['max_tokens']:
            user.tokens = self.quest_module.settings['max_tokens']

        # Notify the user that they've finished today's quest
        message = 'You finished todays quest! You have been awarded with {} {}.'.format(
            reward_amount, reward_type)
        pajbot.managers.handler.HandlerManager.trigger('send_whisper',
                                                       user.username, message)

        # XXX: this can safely be removed once points are moved to redis
        user.save()
Example #45
0
    def print_twitch_emotes(self, **rest):
        manager = self.bot.emote_manager.twitch_emote_manager
        messages = split_into_chunks_with_prefix(
            [
                {
                    "prefix": "Subscriber emotes:",
                    "parts": [e.code for e in manager.tier_one_emotes]
                },
                {
                    "prefix": "T2:",
                    "parts": [e.code for e in manager.tier_two_emotes]
                },
                {
                    "prefix": "T3:",
                    "parts": [e.code for e in manager.tier_three_emotes]
                },
            ],
            default="Looks like {} has no subscriber emotes! :(".format(
                StreamHelper.get_streamer()),
        )

        for message in messages:
            self.bot.say(message)
Example #46
0
File: clip.py Project: zneix/pajbot
 def load_commands(self, **options):
     self.commands["clip"] = Command.raw_command(
         self.clip,
         sub_only=self.settings["subscribers_only"],
         delay_all=self.settings["global_cd"],
         delay_user=self.settings["user_cd"],
         level=self.settings["level"],
         command="clip",
         examples=[
             CommandExample(
                 None,
                 "Make a new clip while the stream is online",
                 chat="user:!clip\n"
                 "bot: " + self.settings["online_response"].format(
                     source="pajlada",
                     streamer=StreamHelper.get_streamer(),
                     clip=
                     "https://clips.twitch.tv/ExpensiveWonderfulClamArsonNoSexy",
                 ),
                 description="",
             ).parse()
         ],
     )
Example #47
0
    def print_twitch_cmd(self):
        if self.settings["custom_sub_response"] != "":
            bot_response = "bot: " + self.settings[
                "custom_sub_response"].format(
                    source="pajlada", streamer=StreamHelper.get_streamer())
        else:
            bot_response = (
                "bot: Subscriber emotes: forsenE forsenC forsenK forsenW Tier 2: forsenSnus Tier 3: forsen2499"
            )

        return Command.raw_command(
            self.print_twitch_emotes,
            level=self.settings["level"],
            delay_all=self.settings["global_cd"],
            delay_user=self.settings["user_cd"],
            examples=[
                CommandExample(
                    None,
                    f"Show all active sub emotes for {StreamHelper.get_streamer()}.",
                    chat="user: !subemotes\n" + bot_response,
                ).parse()
            ],
        )
Example #48
0
    def social_set(social_key: str, **options) -> ResponseReturnValue:
        try:
            json_data = request.get_json()
            if not json_data:
                return {"error": "Missing json body"}, 400
            data: SocialSet = SocialSetSchema().load(json_data)
        except ValidationError as err:
            return {"error": f"Did not match schema: {json.dumps(err.messages)}"}, 400

        streamer = StreamHelper.get_streamer()

        if social_key not in StreamHelper.valid_social_keys:
            return {"error": "invalid social key"}, 400

        # TODO key by streamer ID?
        key = f"{streamer}:{social_key}"
        redis = RedisManager.get()

        if len(data.value) == 0:
            redis.hdel("streamer_info", key)
        else:
            redis.hset("streamer_info", key, data.value)

        return {"message": "success!"}, 200
Example #49
0
        def post(self, **options):
            # Add a single tag to the email
            args = self.post_parser.parse_args()

            email = args['email'].lower()
            new_tag = args['tag'].lower()
            if len(new_tag) == 0:
                return {
                    'message': 'The tag must be at least 1 character long.'
                }, 400
            streamer = StreamHelper.get_streamer()

            key = '{streamer}:email_tags'.format(streamer=streamer)
            redis = RedisManager.get()

            tags_str = redis.hget(key, email)

            if tags_str is None:
                tags = []
            else:
                tags = json.loads(tags_str)

            # Is the tag already active?
            if new_tag in tags:
                return {
                    'message': 'This tag is already set on the email.'
                }, 409

            tags.append(new_tag)

            redis.hset(key, email, json.dumps(tags))

            return {
                'message':
                'Successfully added the tag {} to {}'.format(new_tag, email)
            }
Example #50
0
    def print_cmd(self, manager, examples):
        def do_print(source, **rest):
            self.print_emotes(source, manager)

        if self.settings[f"custom_{manager.friendly_name.lower()}_response"] != "":
            bot_response = "bot: " + self.settings[f"custom_{manager.friendly_name.lower()}_response"].format(
                source="pajlada", streamer=StreamHelper.get_streamer_display()
            )
        else:
            bot_response = f"bot: {manager.friendly_name} emotes: {examples}"

        return Command.raw_command(
            do_print,
            level=self.settings["level"],
            delay_all=self.settings["global_cd"],
            delay_user=self.settings["user_cd"],
            examples=[
                CommandExample(
                    None,
                    f"Show all active {manager.friendly_name} emotes for this channel.",
                    chat=f"user: !{manager.friendly_name.lower()}emotes\n" + bot_response,
                ).parse()
            ],
        )
Example #51
0
 def save_epm_record(self, code, count):
     streamer = StreamHelper.get_streamer()
     self.redis_zadd_if_higher(keys=[
         "{streamer}:emotes:epmrecord".format(streamer=streamer), count
     ],
                               args=[code])
Example #52
0
    def __init__(self, config, args):
        self.config = config
        self.args = args

        ScheduleManager.init()

        DBManager.init(self.config["main"]["db"])

        # redis
        redis_options = {}
        if "redis" in config:
            redis_options = dict(config.items("redis"))
        RedisManager.init(**redis_options)
        utils.wait_for_redis_data_loaded(RedisManager.get())

        self.nickname = config["main"].get("nickname", "pajbot")

        if config["main"].getboolean("verified", False):
            self.tmi_rate_limits = TMIRateLimits.VERIFIED
        elif config["main"].getboolean("known", False):
            self.tmi_rate_limits = TMIRateLimits.KNOWN
        else:
            self.tmi_rate_limits = TMIRateLimits.BASE

        self.whisper_output_mode = WhisperOutputMode.from_config_value(
            config["main"].get("whisper_output_mode", "normal")
        )

        # phrases
        self.phrases = {
            "welcome": ["{nickname} {version} running! HeyGuys"],
            "quit": ["{nickname} {version} shutting down... BibleThump"],
        }
        if "phrases" in config:
            phrases = config["phrases"]
            if "welcome" in phrases:
                self.phrases["welcome"] = phrases["welcome"].splitlines()
            if "quit" in phrases:
                self.phrases["quit"] = phrases["quit"].splitlines()
        # Remembers whether the "welcome" phrases have already been said. We don't want to send the
        # welcome messages to chat again on a reconnect.
        self.welcome_messages_sent = False

        # streamer
        if "streamer" in config["main"]:
            self.streamer = config["main"]["streamer"]
            self.channel = "#" + self.streamer
        elif "target" in config["main"]:
            self.channel = config["main"]["target"]
            self.streamer = self.channel[1:]

        self.bot_domain = self.config["web"]["domain"]
        self.streamer_display = self.config["web"]["streamer_name"]

        log.debug("Loaded config")

        # do this earlier since schema upgrade can depend on the helix api
        self.api_client_credentials = ClientCredentials(
            self.config["twitchapi"]["client_id"],
            self.config["twitchapi"]["client_secret"],
            self.config["twitchapi"]["redirect_uri"],
        )

        self.twitch_id_api = TwitchIDAPI(self.api_client_credentials)
        self.twitch_tmi_api = TwitchTMIAPI()
        self.app_token_manager = AppAccessTokenManager(self.twitch_id_api, RedisManager.get())
        self.twitch_helix_api = TwitchHelixAPI(RedisManager.get(), self.app_token_manager)
        self.twitch_v5_api = TwitchKrakenV5API(self.api_client_credentials, RedisManager.get())

        self.bot_user_id = self.twitch_helix_api.get_user_id(self.nickname)
        if self.bot_user_id is None:
            raise ValueError("The bot login name you entered under [main] does not exist on twitch.")

        self.streamer_user_id = self.twitch_helix_api.get_user_id(self.streamer)
        if self.streamer_user_id is None:
            raise ValueError("The streamer login name you entered under [main] does not exist on twitch.")

        self.streamer_access_token_manager = UserAccessTokenManager(
            api=self.twitch_id_api, redis=RedisManager.get(), username=self.streamer, user_id=self.streamer_user_id
        )

        StreamHelper.init_streamer(self.streamer, self.streamer_user_id, self.streamer_display)

        # SQL migrations
        with DBManager.create_dbapi_connection_scope() as sql_conn:
            sql_migratable = DatabaseMigratable(sql_conn)
            sql_migration = Migration(sql_migratable, pajbot.migration_revisions.db, self)
            sql_migration.run()

        # Redis migrations
        redis_migratable = RedisMigratable(redis_options=redis_options, namespace=self.streamer)
        redis_migration = Migration(redis_migratable, pajbot.migration_revisions.redis, self)
        redis_migration.run()

        # Thread pool executor for async actions
        self.action_queue = ActionQueue()

        # refresh points_rank and num_lines_rank regularly
        UserRanksRefreshManager.start(self.action_queue)

        self.reactor = irc.client.Reactor()
        # SafeDefaultScheduler makes the bot not exit on exception in the main thread
        # e.g. on actions via bot.execute_now, etc.
        self.reactor.scheduler_class = SafeDefaultScheduler
        self.reactor.scheduler = SafeDefaultScheduler()

        self.start_time = utils.now()
        ActionParser.bot = self

        HandlerManager.init_handlers()

        self.socket_manager = SocketManager(self.streamer, self.execute_now)
        self.stream_manager = StreamManager(self)
        StreamHelper.init_stream_manager(self.stream_manager)

        self.decks = DeckManager()
        self.banphrase_manager = BanphraseManager(self).load()
        self.timer_manager = TimerManager(self).load()
        self.kvi = KVIManager()

        # bot access token
        if "password" in self.config["main"]:
            log.warning(
                "DEPRECATED - Using bot password/oauth token from file. "
                "You should authenticate in web gui using route /bot_login "
                "and remove password from config file"
            )

            access_token = self.config["main"]["password"]

            if access_token.startswith("oauth:"):
                access_token = access_token[6:]

            self.bot_token_manager = UserAccessTokenManager(
                api=None,
                redis=None,
                username=self.nickname,
                user_id=self.bot_user_id,
                token=UserAccessToken.from_implicit_auth_flow_token(access_token),
            )
        else:
            self.bot_token_manager = UserAccessTokenManager(
                api=self.twitch_id_api, redis=RedisManager.get(), username=self.nickname, user_id=self.bot_user_id
            )

        self.emote_manager = EmoteManager(self.twitch_v5_api, self.action_queue)
        self.epm_manager = EpmManager()
        self.ecount_manager = EcountManager()
        if "twitter" in self.config and self.config["twitter"].get("streaming_type", "twitter") == "tweet-provider":
            self.twitter_manager = PBTwitterManager(self)
        else:
            self.twitter_manager = TwitterManager(self)
        self.module_manager = ModuleManager(self.socket_manager, bot=self).load()
        self.commands = CommandManager(
            socket_manager=self.socket_manager, module_manager=self.module_manager, bot=self
        ).load()
        self.websocket_manager = WebSocketManager(self)

        HandlerManager.trigger("on_managers_loaded")

        # Commitable managers
        self.commitable = {"commands": self.commands, "banphrases": self.banphrase_manager}

        self.execute_every(60, self.commit_all)
        self.execute_every(1, self.do_tick)

        # promote the admin to level 2000
        self.admin = self.config["main"].get("admin", None)
        if self.admin is None:
            log.warning("No admin user specified. See the [main] section in the example config for its usage.")
        else:
            with DBManager.create_session_scope() as db_session:
                admin_user = User.find_or_create_from_login(db_session, self.twitch_helix_api, self.admin)
                if admin_user is None:
                    log.warning(
                        "The login name you entered for the admin user does not exist on twitch. "
                        "No admin user has been created."
                    )
                else:
                    admin_user.level = 2000

        # silent mode
        self.silent = (
            "flags" in config and "silent" in config["flags"] and config["flags"]["silent"] == "1"
        ) or args.silent
        if self.silent:
            log.info("Silent mode enabled")

        # dev mode
        self.dev = "flags" in config and "dev" in config["flags"] and config["flags"]["dev"] == "1"
        if self.dev:
            self.version_long = utils.extend_version_if_possible(VERSION)
        else:
            self.version_long = VERSION

        self.irc = IRCManager(self)

        relay_host = self.config["main"].get("relay_host", None)
        relay_password = self.config["main"].get("relay_password", None)
        if relay_host is not None or relay_password is not None:
            log.warning(
                "DEPRECATED - Relaybroker support is no longer implemented. relay_host and relay_password are ignored"
            )

        self.data = {
            "broadcaster": self.streamer,
            "version": self.version_long,
            "version_brief": VERSION,
            "bot_name": self.nickname,
            "bot_domain": self.bot_domain,
            "streamer_display": self.streamer_display,
        }

        self.data_cb = {
            "status_length": self.c_status_length,
            "stream_status": self.c_stream_status,
            "bot_uptime": self.c_uptime,
            "current_time": self.c_current_time,
            "molly_age_in_years": self.c_molly_age_in_years,
        }

        self.user_agent = f"pajbot1/{VERSION} ({self.nickname})"
Example #53
0
    def __init__(self, config, args=None):
        # Load various configuration variables from the given config object
        # The config object that should be passed through should
        # come from pajbot.utils.load_config
        self.load_config(config)

        # Update the database scheme if necessary using alembic
        # In case of errors, i.e. if the database is out of sync or the alembic
        # binary can't be called, we will shut down the bot.
        pajbot.utils.alembic_upgrade()

        # Actions in this queue are run in a separate thread.
        # This means actions should NOT access any database-related stuff.
        self.action_queue = ActionQueue()
        self.action_queue.start()

        self.reactor = irc.client.Reactor(self.on_connect)
        self.start_time = datetime.datetime.now()
        ActionParser.bot = self

        HandlerManager.init_handlers()

        self.socket_manager = SocketManager(self)
        self.stream_manager = StreamManager(self)

        StreamHelper.init_bot(self, self.stream_manager)
        ScheduleManager.init()

        self.users = UserManager()
        self.decks = DeckManager()
        self.module_manager = ModuleManager(self.socket_manager, bot=self).load()
        self.commands = CommandManager(
                socket_manager=self.socket_manager,
                module_manager=self.module_manager,
                bot=self).load()
        self.filters = FilterManager().reload()
        self.banphrase_manager = BanphraseManager(self).load()
        self.timer_manager = TimerManager(self).load()
        self.kvi = KVIManager()
        self.emotes = EmoteManager(self)
        self.twitter_manager = TwitterManager(self)

        HandlerManager.trigger('on_managers_loaded')

        # Reloadable managers
        self.reloadable = {
                'filters': self.filters,
                }

        # Commitable managers
        self.commitable = {
                'commands': self.commands,
                'filters': self.filters,
                'banphrases': self.banphrase_manager,
                }

        self.execute_every(10 * 60, self.commit_all)
        self.execute_every(1, self.do_tick)

        try:
            self.admin = self.config['main']['admin']
        except KeyError:
            log.warning('No admin user specified. See the [main] section in config.example.ini for its usage.')
        if self.admin:
            with self.users.get_user_context(self.admin) as user: pass
                # user.level = 2000

        self.parse_version()

        relay_host = self.config['main'].get('relay_host', None)
        relay_password = self.config['main'].get('relay_password', None)
        if relay_host is None or relay_password is None:
            self.irc = MultiIRCManager(self)
        else:
            self.irc = SingleIRCManager(self)

        self.reactor.add_global_handler('all_events', self.irc._dispatcher, -10)

        twitch_client_id = None
        twitch_oauth = None
        if 'twitchapi' in self.config:
            twitch_client_id = self.config['twitchapi'].get('client_id', None)
            twitch_oauth = self.config['twitchapi'].get('oauth', None)

        # A client ID is required for the bot to work properly now, give an error for now
        if twitch_client_id is None:
            log.error('MISSING CLIENT ID, SET "client_id" VALUE UNDER [twitchapi] SECTION IN CONFIG FILE')

        self.twitchapi = TwitchAPI(twitch_client_id, twitch_oauth)

        self.data = {}
        self.data_cb = {}
        self.url_regex = re.compile(self.url_regex_str, re.IGNORECASE)

        self.data['broadcaster'] = self.streamer
        self.data['version'] = self.version
        self.data['version_brief'] = self.version_brief
        self.data['bot_name'] = self.nickname
        self.data_cb['status_length'] = self.c_status_length
        self.data_cb['stream_status'] = self.c_stream_status
        self.data_cb['bot_uptime'] = self.c_uptime
        self.data_cb['current_time'] = self.c_current_time

        self.silent = True if args.silent else self.silent

        if self.silent:
            log.info('Silent mode enabled')

        """
        For actions that need to access the main thread,
        we can use the mainthread_queue.
        """
        self.mainthread_queue = ActionQueue()
        self.execute_every(1, self.mainthread_queue.parse_action)

        self.websocket_manager = WebSocketManager(self)

        try:
            if self.config['twitchapi']['update_subscribers'] == '1':
                self.execute_every(30 * 60,
                                   self.action_queue.add,
                                   (self.update_subscribers_stage1, ))
        except:
            pass

        # XXX: TEMPORARY UGLY CODE
        HandlerManager.add_handler('on_user_gain_tokens', self.on_user_gain_tokens)
        HandlerManager.add_handler('send_whisper', self.whisper)
Example #54
0
 def __init__(self):
     super().__init__()
     # XXX: This key should probably be generic and always set in the BaseQuest
     self.points_required_key = '{streamer}:current_quest_points_required'.format(streamer=StreamHelper.get_streamer())
     # The points_required variable is randomized at the start of the quest.
     # It will be a value between settings['min_value'] and settings['max_value']
     self.points_required = None
     self.progress = {}
Example #55
0
    def _set_last_seen(self, value):
        # Set cached value
        self.values["last_seen"] = value

        self.redis.hset("{streamer}:users:last_seen".format(streamer=StreamHelper.get_streamer()), self.username, value)
Example #56
0
 def channel_emote_redis_key(self):
     streamer = StreamHelper.get_streamer()
     return "{}:emotes:{}_channel_emotes".format(streamer, self.redis_name)
Example #57
0
 def get_emote_epm_record(emote_code):
     redis = RedisManager.get()
     streamer = StreamHelper.get_streamer()
     return redis.zscore(
         "{streamer}:emotes:epmrecord".format(streamer=streamer),
         emote_code)
Example #58
0
def init(args):
    import subprocess
    import sys

    from flask import request
    from flask import session

    import pajbot.utils
    import pajbot.web.common
    import pajbot.web.routes
    from pajbot.managers.db import DBManager
    from pajbot.managers.redis import RedisManager
    from pajbot.models.module import ModuleManager
    from pajbot.models.sock import SocketClientManager
    from pajbot.streamhelper import StreamHelper
    from pajbot.utils import load_config
    from pajbot.web.models import errors
    from pajbot.web.utils import download_logo
    from pajbot.web.utils import download_sub_badge

    config = load_config(args.config)

    api_client_credentials = ClientCredentials(
        config["twitchapi"]["client_id"],
        config["twitchapi"]["client_secret"],
        config["twitchapi"].get(
            "redirect_uri",
            f"https://{config['web']['domain']}/login/authorized"),
    )

    redis_options = {}
    if "redis" in config:
        redis_options = dict(config["redis"])

    RedisManager.init(redis_options)

    twitch_id_api = TwitchIDAPI(api_client_credentials)
    app_token_manager = AppAccessTokenManager(twitch_id_api,
                                              RedisManager.get())
    twitch_helix_api = TwitchHelixAPI(RedisManager.get(), app_token_manager)
    twitch_badges_api = TwitchBadgesAPI(RedisManager.get())

    app.api_client_credentials = api_client_credentials
    app.twitch_id_api = twitch_id_api
    app.twitch_helix_api = twitch_helix_api

    if "web" not in config:
        log.error("Missing [web] section in config.ini")
        sys.exit(1)

    app.streamer = cfg.load_streamer(config, twitch_helix_api)

    app.streamer_display = app.streamer.name
    if "streamer_name" in config["web"]:
        app.streamer_display = config["web"]["streamer_name"]

    app.bot_user = cfg.load_bot(config, twitch_helix_api)

    StreamHelper.init_streamer(app.streamer.login, app.streamer.id,
                               app.streamer.name)

    try:
        download_logo(twitch_helix_api, app.streamer)
    except:
        log.exception("Error downloading the streamers profile picture")

    subscriber_badge_version = config["web"].get("subscriber_badge_version",
                                                 "0")

    # Specifying a value of -1 in the config will disable sub badge downloading. Useful if you want to keep a custom version of a sub badge for a streamer
    if subscriber_badge_version != "-1":
        try:
            download_sub_badge(twitch_badges_api, app.streamer,
                               subscriber_badge_version)
        except:
            log.exception("Error downloading the streamers subscriber badge")

    SocketClientManager.init(app.streamer.login)

    app.bot_modules = config["web"].get("modules", "").split()
    app.bot_commands_list = []
    app.bot_config = config

    # https://flask.palletsprojects.com/en/1.1.x/quickstart/#sessions
    # https://flask.palletsprojects.com/en/1.1.x/api/#sessions
    # https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.secret_key
    app.secret_key = _load_secret_key(app.bot_user.id, app.streamer.id)
    app.bot_dev = "flags" in config and "dev" in config["flags"] and config[
        "flags"]["dev"] == "1"

    DBManager.init(config["main"]["db"])

    app.module_manager = ModuleManager(None).load()

    pajbot.web.routes.admin.init(app)
    pajbot.web.routes.api.init(app)
    pajbot.web.routes.base.init(app)

    # Make a CSRF exemption for the /api/v1/banphrases/test endpoint
    csrf.exempt("pajbot.web.routes.api.banphrases.apibanphrasetest")

    pajbot.web.common.filters.init(app)
    pajbot.web.common.assets.init(app)
    pajbot.web.common.menu.init(app)

    app.register_blueprint(pajbot.web.routes.clr.page)

    errors.init(app, config)
    pajbot.web.routes.clr.config = config

    version = VERSION
    last_commit = None

    if app.bot_dev:
        version = extend_version_if_possible(VERSION)

        try:
            last_commit = subprocess.check_output(
                ["git", "log", "-1", "--format=%cd"]).decode("utf8").strip()
        except:
            log.exception(
                "Failed to get last_commit, will not show last commit")

    default_variables = {
        "version": version,
        "last_commit": last_commit,
        "bot": {
            "name": app.bot_user.login
        },
        "site": {
            "domain":
            config["web"]["domain"],
            "deck_tab_images":
            cfg.get_boolean(config["web"], "deck_tab_images", False),
            "websocket": {
                "host":
                config["websocket"].get(
                    "host", f"wss://{config['web']['domain']}/clrsocket")
            },
        },
        "streamer": {
            "name": app.streamer_display,
            "full_name": app.streamer.login,
            "id": app.streamer.id
        },
        "modules": app.bot_modules,
        "request": request,
        "session": session,
        "google_analytics": config["web"].get("google_analytics", None),
    }

    @app.context_processor
    def current_time():
        current_time = {}
        current_time["current_time"] = pajbot.utils.now()
        return current_time

    @app.context_processor
    def inject_default_variables():
        return default_variables
Example #59
0
 def __init__(self):
     self.streamer = StreamHelper.get_streamer()
     UserDict.__init__(self)
Revision ID: 5f746af0a82d
Revises: 186928676dbc
Create Date: 2019-06-04 19:07:25.109751

"""

from pajbot.managers.redis import RedisManager
from pajbot.streamhelper import StreamHelper

# revision identifiers, used by Alembic.
revision = '5f746af0a82d'
down_revision = '186928676dbc'
branch_labels = None
depends_on = None

streamer = StreamHelper.get_streamer()


def upgrade():
    with RedisManager.pipeline_context() as redis:
        redis.delete(
            '{streamer}:emotes:ffz_channel_emotes'.format(streamer=streamer))
        redis.delete(
            '{streamer}:emotes:bttv_channel_emotes'.format(streamer=streamer))
        redis.delete('global:emotes:ffz_global')
        redis.delete('global:emotes:bttv_global')


def downgrade():
    with RedisManager.pipeline_context() as redis:
        redis.delete('{streamer}:emotes:twitch_channel_emotes'.format(