Esempio n. 1
0
    def create_stream(self, status):
        log.info('Attempting to create a stream!')
        with DBManager.create_session_scope(expire_on_commit=False) as db_session:
            stream_chunk = db_session.query(StreamChunk).filter_by(broadcast_id=status['broadcast_id']).one_or_none()
            new_stream = False
            if stream_chunk is not None:
                stream = stream_chunk.stream
            else:
                log.info('checking if there is an active stream already')
                stream = db_session.query(Stream).filter_by(ended=False).order_by(Stream.stream_start.desc()).first()
                new_stream = stream is None

                if new_stream:
                    log.info('No active stream, create new!')
                    stream = Stream(status['created_at'],
                            title=status['title'])
                    db_session.add(stream)
                    db_session.commit()
                    log.info('Successfully added stream!')
                stream_chunk = StreamChunk(stream, status['broadcast_id'], status['created_at'])
                db_session.add(stream_chunk)
                db_session.commit()
                stream.stream_chunks.append(stream_chunk)
                log.info('Created stream chunk')

            self.current_stream = stream
            self.current_stream_chunk = stream_chunk
            db_session.expunge_all()

            if new_stream:
                HandlerManager.trigger('on_stream_start', stop_on_false=False)

            log.info('Successfully created a stream')
Esempio n. 2
0
    def on_usernotice(self, source, message, tags):
        if 'msg-id' not in tags or 'msg-param-months' not in tags:
            return

        if tags['msg-id'] == 'resub':
            num_months = int(tags['msg-param-months'])
            self.on_resub(source, num_months)
            HandlerManager.trigger('on_user_resub', source, num_months)
Esempio n. 3
0
 def on_message(self, source, message, emotes, whisper, urls, event):
     if whisper is False and source.username in self.valid_usernames:
         # Did twitchnotify tell us about a new sub?
         m = self.new_sub_regex.search(message)
         if m:
             username = m.group(1)
             with UserManager.get().get_user_context(username) as user:
                 self.on_new_sub(user)
                 HandlerManager.trigger('on_user_sub', user)
Esempio n. 4
0
    def on_usernotice(self, source, message, tags):
        if 'msg-id' not in tags or 'msg-param-months' not in tags:
            return

        if tags['msg-id'] == 'resub':
            # TODO: Should we check room id with streamer ID here? Maybe that's for pajbot2 instead
            num_months = int(tags['msg-param-months'])
            self.on_resub(source, num_months)
            HandlerManager.trigger('on_user_resub', source, num_months)
Esempio n. 5
0
File: bot.py Progetto: jardg/pajbot
    def commit_all(self):
        log.info('Commiting all...')
        for key, manager in self.commitable.items():
            log.info('Commiting {0}'.format(key))
            manager.commit()
            log.info('Done with {0}'.format(key))
        log.info('ok!')

        HandlerManager.trigger('on_commit', stop_on_false=False)
Esempio n. 6
0
    def base_paid_timeout(self, bot, source, message, _time, _cost):
        if message is None or len(message) == 0:
            return False

        target = message.split(' ')[0]
        if len(target) < 2:
            return False

        with bot.users.find_context(target) as victim:
            if victim is None:
                bot.whisper(source.username, 'This user does not exist FailFish')
                return False

            if victim.last_active is None or (datetime.datetime.now() - victim._last_active).total_seconds() > 10 * 60:
                bot.whisper(source.username, 'This user has not been active in chat within the last 10 minutes.')
                return False

            """
            if victim == source:
                bot.whisper(source.username, 'You can\'t timeout yourself FailFish')
                return False
                """

            if victim.moderator is True:
                bot.whisper(source.username, 'This person has mod privileges, timeouting this person is not worth it.')
                return False

            if victim.level >= self.settings['bypass_level']:
                bot.whisper(source.username, 'This person\'s user level is too high, you can\'t timeout this person.')
                return False

            now = datetime.datetime.now()
            if victim.timed_out is True and victim.timeout_end > now:
                victim.timeout_end += datetime.timedelta(seconds=_time)
                bot.whisper(victim.username, '{victim.username}, you were timed out for an additional {time} seconds by {source.username}'.format(
                    victim=victim,
                    source=source,
                    time=_time))
                bot.whisper(source.username, 'You just used {0} points to time out {1} for an additional {2} seconds.'.format(_cost, victim.username, _time))
                num_seconds = int((victim.timeout_end - now).total_seconds())
                bot._timeout(victim.username, num_seconds, reason='Timed out by {}'.format(source.username_raw))
            # songs = session.query(PleblistSong, func.count(PleblistSong.song_info).label('total')).group_by(PleblistSong.youtube_id).order_by('total DESC')
            else:
                bot.whisper(source.username, 'You just used {0} points to time out {1} for {2} seconds.'.format(_cost, victim.username, _time))
                bot.whisper(victim.username, '{0} just timed you out for {1} seconds. /w {2} !$unbanme to unban yourself for points forsenMoney'.format(source.username, _time, bot.nickname))
                bot._timeout(victim.username, _time, reason='Timed out by {}'.format(source.username_raw))
                victim.timed_out = True
                victim.timeout_start = now
                victim.timeout_end = now + datetime.timedelta(seconds=_time)

            if self.settings['show_on_clr']:
                payload = {'user': source.username, 'victim': victim.username}
                bot.websocket_manager.emit('timeout', payload)

            HandlerManager.trigger('on_paid_timeout',
                    source, victim, _cost,
                    stop_on_false=False)
Esempio n. 7
0
    def parse_message(self, msg_raw, source, event, tags={}, whisper=False):
        msg_lower = msg_raw.lower()

        emote_tag = None

        for tag in tags:
            if tag['key'] == 'subscriber' and event.target == self.channel:
                source.subscriber = tag['value'] == '1'
            elif tag['key'] == 'emotes' and tag['value']:
                emote_tag = tag['value']
            elif tag['key'] == 'display-name' and tag['value']:
                source.username_raw = tag['value']
            elif tag['key'] == 'user-type':
                source.moderator = tag['value'] == 'mod' or source.username == self.streamer

        # source.num_lines += 1

        if source is None:
            log.error('No valid user passed to parse_message')
            return False

        if source.banned:
            self.ban(source.username)
            return False

        # If a user types when timed out, we assume he's been unbanned for a good reason and remove his flag.
        if source.timed_out is True:
            source.timed_out = False

        # Parse emotes in the message
        message_emotes = self.emotes.parse_message_twitch_emotes(source, msg_raw, emote_tag, whisper)

        urls = self.find_unique_urls(msg_raw)

        log.debug('{2}{0}: {1}'.format(source.username, msg_raw, '<w>' if whisper else ''))

        res = HandlerManager.trigger('on_message',
                source, msg_raw, message_emotes, whisper, urls, event,
                stop_on_false=True)
        if res is False:
            return False

        source.last_seen = datetime.datetime.now()
        source.last_active = datetime.datetime.now()

        if source.ignored:
            return False

        if msg_lower[:1] == '!':
            msg_lower_parts = msg_lower.split(' ')
            trigger = msg_lower_parts[0][1:]
            msg_raw_parts = msg_raw.split(' ')
            remaining_message = ' '.join(msg_raw_parts[1:]) if len(msg_raw_parts) > 1 else None
            if trigger in self.commands:
                command = self.commands[trigger]
                extra_args = {
                        'emotes': message_emotes,
                        'trigger': trigger,
                        }
                command.run(self, source, remaining_message, event=event, args=extra_args, whisper=whisper)
Esempio n. 8
0
File: bot.py Progetto: jardg/pajbot
    def on_usernotice(self, chatconn, event):
        # We use .lower() in case twitch ever starts sending non-lowercased usernames
        tags = {}
        for d in event.tags:
            tags[d['key']] = d['value']

        if 'login' not in tags:
            return

        username = tags['login']

        with self.users.get_user_context(username) as source:
            msg = ''
            if len(event.arguments) > 0:
                msg = event.arguments[0]
            HandlerManager.trigger('on_usernotice',
                    source, msg, tags)
Esempio n. 9
0
    def go_offline(self):
        with DBManager.create_session_scope(expire_on_commit=False) as db_session:
            self.current_stream.ended = True
            self.current_stream.stream_end = self.first_offline
            self.current_stream_chunk.chunk_end = self.first_offline

            db_session.add(self.current_stream)
            db_session.add(self.current_stream_chunk)

            db_session.commit()

            db_session.expunge_all()

        self.last_stream = self.current_stream
        self.current_stream = None
        self.current_stream_chunk = None

        HandlerManager.trigger('on_stream_stop', stop_on_false=False)
Esempio n. 10
0
    def end_raffle(self):
        if not self.raffle_running:
            return False

        self.raffle_running = False

        if len(self.raffle_users) == 0:
            self.bot.me('Wow, no one joined the raffle DansGame')
            return False

        winner = random.choice(self.raffle_users)

        self.raffle_users = []

        if self.settings['show_on_clr']:
            self.bot.websocket_manager.emit('notification', {'message': '{} won {} points in the raffle!'.format(winner.username_raw, self.raffle_points)})
            self.bot.me('The raffle has finished! {0} won {1} points! PogChamp'.format(winner.username_raw, self.raffle_points))

        winner.points += self.raffle_points

        winner.save()

        HandlerManager.trigger('on_raffle_win', winner, self.raffle_points)
Esempio n. 11
0
    def create_stream(self, status):
        log.info("Attempting to create a stream!")
        with DBManager.create_session_scope(
                expire_on_commit=False) as db_session:
            stream_chunk = db_session.query(StreamChunk).filter_by(
                broadcast_id=status["broadcast_id"]).one_or_none()
            new_stream = False
            if stream_chunk is not None:
                stream = stream_chunk.stream
            else:
                log.info("checking if there is an active stream already")
                stream = db_session.query(Stream).filter_by(
                    ended=False).order_by(Stream.stream_start.desc()).first()
                new_stream = stream is None

                if new_stream:
                    log.info("No active stream, create new!")
                    stream = Stream(status["created_at"],
                                    title=status["title"])
                    db_session.add(stream)
                    db_session.commit()
                    log.info("Successfully added stream!")
                stream_chunk = StreamChunk(stream, status["broadcast_id"],
                                           status["created_at"])
                db_session.add(stream_chunk)
                db_session.commit()
                stream.stream_chunks.append(stream_chunk)
                log.info("Created stream chunk")

            self.current_stream = stream
            self.current_stream_chunk = stream_chunk
            db_session.expunge_all()

            if new_stream:
                HandlerManager.trigger("on_stream_start", stop_on_false=False)

            log.info("Successfully created a stream")
Esempio n. 12
0
    def on_usernotice(self, chatconn, event):
        tags = {
            tag["key"]: tag["value"] if tag["value"] is not None else ""
            for tag in event.tags
        }

        id = tags["user-id"]
        login = tags["login"]
        name = tags["display-name"]

        with DBManager.create_session_scope(
                expire_on_commit=False) as db_session:
            source = User.from_basics(db_session, UserBasics(id, login, name))
            if event.arguments and len(event.arguments) > 0:
                msg = event.arguments[0]
            else:
                msg = None  # e.g. user didn't type an extra message to share with the streamer
            HandlerManager.trigger("on_usernotice",
                                   source=source,
                                   message=msg,
                                   tags=tags)

            if msg is not None:
                self.parse_message(msg, source, event, tags)
Esempio n. 13
0
    def on_pubmsg(self, chatconn, event):
        if event.source.user == self.nickname:
            return False

        username = event.source.user.lower()

        # We use .lower() in case twitch ever starts sending non-lowercased usernames
        with self.users.get_user_context(username) as source:
            res = HandlerManager.trigger('on_pubmsg',
                    source, event.arguments[0],
                    stop_on_false=True)
            if res is False:
                return False

            self.parse_message(event.arguments[0], source, event, tags=event.tags)
Esempio n. 14
0
    def on_usernotice(self, source, message, tags):
        if 'msg-id' not in tags:
            return

        if tags['msg-id'] == 'resub':
            if 'msg-param-months' not in tags:
                log.debug('subalert msg-id is resub, but missing msg-param-months: {}'.format(tags))
                return
            if 'msg-param-sub-plan' not in tags:
                log.debug('subalert msg-id is resub, but missing msg-param-sub-plan: {}'.format(tags))
                return

            # log.debug('msg-id resub tags: {}'.format(tags))

            # TODO: Should we check room id with streamer ID here? Maybe that's for pajbot2 instead
            num_months = int(tags['msg-param-months'])
            self.on_resub(source, num_months, tags['msg-param-sub-plan'])
            HandlerManager.trigger('on_user_resub', source, num_months)
        elif tags['msg-id'] == 'subgift':
            if 'msg-param-months' not in tags:
                log.debug('subalert msg-id is subgift, but missing msg-param-months: {}'.format(tags))
                return
            if 'display-name' not in tags:
                log.debug('subalert msg-id is subgift, but missing display-name: {}'.format(tags))
                return

            num_months = int(tags['msg-param-months'])

            with self.bot.users.get_user_context(tags['msg-param-recipient-user-name']) as receiver:
                if num_months > 1:
                    # Resub
                    self.on_resub(receiver, num_months, tags['msg-param-sub-plan'], tags['display-name'])
                    HandlerManager.trigger('on_user_resub', receiver, num_months)
                else:
                    # New sub
                    self.on_new_sub(receiver, tags['msg-param-sub-plan'], tags['display-name'])
                    HandlerManager.trigger('on_user_sub', receiver)
        elif tags['msg-id'] == 'sub':
            if 'msg-param-sub-plan' not in tags:
                log.debug('subalert msg-id is sub, but missing msg-param-sub-plan: {}'.format(tags))
                return

            self.on_new_sub(source, tags['msg-param-sub-plan'])
            HandlerManager.trigger('on_user_sub', source)
        else:
            log.debug('Unhandled msg-id: {}'.format(tags['msg-id']))
Esempio n. 15
0
    def on_pubmsg(self, chatconn, event):
        tags = {tag["key"]: tag["value"] if tag["value"] is not None else "" for tag in event.tags}

        id = tags["user-id"]
        login = event.source.user
        name = tags["display-name"]

        if event.source.user == self.nickname:
            return False

        if self.streamer == "forsen":
            if "zonothene" in login:
                self._ban(login)
                return True

            raw_m = event.arguments[0].lower()
            if raw_m.startswith("!lastseen forsen"):
                if len(raw_m) > len("!lastseen forsen2"):
                    if raw_m[16] == " ":
                        return True
                else:
                    return True

            if raw_m.startswith("!lastseen @forsen"):
                if len(raw_m) > len("!lastseen @forsen2"):
                    if raw_m[17] == " ":
                        return True
                else:
                    return True

        if self.streamer == "nymn":
            if "hades_k" in login:
                self.timeout_login(login, 3600, reason="Bad username")
                return True

            if "hades_b" in login:
                self.timeout_login(login, 3600, reason="Bad username")
                return True

        with DBManager.create_session_scope(expire_on_commit=False) as db_session:
            source = User.from_basics(db_session, UserBasics(id, login, name))

            with new_message_processing_scope(self):
                res = HandlerManager.trigger("on_pubmsg", source=source, message=event.arguments[0], tags=tags)
                if res is False:
                    return False

                self.parse_message(event.arguments[0], source, event, tags=tags)
Esempio n. 16
0
    def on_pubmsg(self, chatconn, event):
        tags = {
            tag["key"]: tag["value"] if tag["value"] is not None else ""
            for tag in event.tags
        }

        id = tags["user-id"]
        login = event.source.user
        name = tags["display-name"]

        if event.source.user == self.nickname:
            return False

        with DBManager.create_session_scope(
                expire_on_commit=False) as db_session:
            source = User.from_basics(db_session, UserBasics(id, login, name))
            res = HandlerManager.trigger("on_pubmsg",
                                         source=source,
                                         message=event.arguments[0])
            if res is False:
                return False

            self.parse_message(event.arguments[0], source, event, tags=tags)
Esempio n. 17
0
 def onMessage(self, payload, isBinary):
     if isBinary:
         log.info(f"Binary message received: {len(payload)} bytes")
     else:
         log.info(
             f"Text message received: {payload.decode('utf8')}")
         if not self.websocket_origin:
             parsedPayload = json.loads(payload)
             if parsedPayload["event"] == "open_bets":
                 HandlerManager.trigger("on_open_bets")
             elif parsedPayload["event"] == "lock_bets":
                 HandlerManager.trigger("on_lock_bets")
             elif parsedPayload["event"] == "end_bets":
                 HandlerManager.trigger(
                     "on_end_bets",
                     winning_team=parsedPayload["data"]
                     ["winning_team"],
                     player_team=parsedPayload["data"]
                     ["player_team"],
                 )
             else:
                 for client in WebSocketServer.clients:
                     client.sendMessage(payload, False)
Esempio n. 18
0
    def roulette(self, **options):
        if self.settings['only_roulette_after_sub']:
            if self.last_sub is None:
                return False
            if datetime.datetime.now() - self.last_sub > datetime.timedelta(
                    seconds=self.settings['after_sub_roulette_time']):
                return False

        message = options['message']
        user = options['source']
        bot = options['bot']

        if message is None:
            bot.whisper(
                user.username,
                'I didn\'t recognize your bet! Usage: !roulette 150 to bet 150 points'
            )
            return False

        msg_split = message.split(' ')
        try:
            bet = pajbot.utils.parse_points_amount(user, msg_split[0])
        except pajbot.exc.InvalidPointAmount as e:
            bot.whisper(user.username, str(e))
            return False

        if not user.can_afford(bet):
            bot.whisper(
                user.username,
                'You don\'t have enough points to do a roulette for {} points :('
                .format(bet))
            return False

        if bet < self.settings['min_roulette_amount']:
            bot.whisper(
                user.username, 'You have to bet at least {} point! :('.format(
                    self.settings['min_roulette_amount']))
            return False

        # Calculating the result
        result = self.rigged_random_result()
        points = bet if result else -bet
        user.points += points

        with DBManager.create_session_scope() as db_session:
            r = Roulette(user.id, points)
            db_session.add(r)

        arguments = {
            'bet': bet,
            'user': user.username_raw,
            'points': user.points_available()
        }

        if points > 0:
            out_message = self.get_phrase('message_won', **arguments)
        else:
            out_message = self.get_phrase('message_lost', **arguments)

        if self.settings['options_output'] == '1. Show results in chat':
            bot.me(out_message)
        if self.settings['options_output'] == '2. Show results in whispers':
            bot.whisper(user.username, out_message)
        if self.settings[
                'options_output'] == '3. Show results in chat if it\'s over X points else it will be whispered.':
            if abs(points) >= self.settings['min_show_points']:
                bot.me(out_message)
            else:
                bot.whisper(user.username, out_message)

        HandlerManager.trigger('on_roulette_finish', user, points)
Esempio n. 19
0
    def on_usernotice(self, source, message, tags):
        if 'msg-id' not in tags:
            return

        if tags['msg-id'] == 'resub':
            num_months = -1
            substreak_count = 0
            if 'msg-param-months' in tags:
                num_months = int(tags['msg-param-months'])
            if 'msg-param-cumulative-months' in tags:
                num_months = int(tags['msg-param-cumulative-months'])
            if 'msg-param-streak-months' in tags:
                substreak_count = int(tags['msg-param-streak-months'])
            if 'msg-param-should-share-streak' in tags:
                should_share = bool(tags['msg-param-should-share-streak'])
                if not should_share:
                    substreak_count = 0

            if 'msg-param-sub-plan' not in tags:
                log.debug('subalert msg-id is resub, but missing msg-param-sub-plan: {}'.format(tags))
                return

            # log.debug('msg-id resub tags: {}'.format(tags))

            # TODO: Should we check room id with streamer ID here? Maybe that's for pajbot2 instead
            self.on_resub(source, num_months, tags['msg-param-sub-plan'], None, substreak_count)
            HandlerManager.trigger('on_user_resub', source, num_months)
        elif tags['msg-id'] == 'subgift':
            num_months = 0
            substreak_count = 0
            if 'msg-param-months' in tags:
                num_months = int(tags['msg-param-months'])
            if 'msg-param-cumulative-months' in tags:
                num_months = int(tags['msg-param-cumulative-months'])
            if 'msg-param-streak-months' in tags:
                substreak_count = int(tags['msg-param-streak-months'])
            if 'msg-param-should-share-streak' in tags:
                should_share = bool(tags['msg-param-should-share-streak'])
                if not should_share:
                    substreak_count = 0

            if 'display-name' not in tags:
                log.debug('subalert msg-id is subgift, but missing display-name: {}'.format(tags))
                return

            with self.bot.users.get_user_context(tags['msg-param-recipient-user-name']) as receiver:
                if num_months > 1:
                    # Resub
                    self.on_resub(receiver, num_months, tags['msg-param-sub-plan'], tags['display-name'], substreak_count)
                    HandlerManager.trigger('on_user_resub', receiver, num_months)
                else:
                    # New sub
                    self.on_new_sub(receiver, tags['msg-param-sub-plan'], tags['display-name'])
                    HandlerManager.trigger('on_user_sub', receiver)
        elif tags['msg-id'] == 'sub':
            if 'msg-param-sub-plan' not in tags:
                log.debug('subalert msg-id is sub, but missing msg-param-sub-plan: {}'.format(tags))
                return

            self.on_new_sub(source, tags['msg-param-sub-plan'])
            HandlerManager.trigger('on_user_sub', source)
        else:
            log.debug('Unhandled msg-id: {} - tags: {}'.format(tags['msg-id'], tags))
Esempio n. 20
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)
        log.debug("Loaded config")

        # streamer is additionally initialized here so streamer can be accessed by the DB migrations
        # before StreamHelper.init_bot() is called later (which depends on an upgraded DB because
        # StreamManager accesses the DB)
        StreamHelper.init_streamer(self.streamer)

        # Update the database (and partially redis) 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()
        log.debug("ran db 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 = pajbot.utils.now()
        ActionParser.bot = self

        HandlerManager.init_handlers()

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

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

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

        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.emote_manager = EmoteManager(twitch_client_id)
        self.epm_manager = EpmManager()
        self.ecount_manager = EcountManager()
        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()

        HandlerManager.trigger("on_managers_loaded")

        # Reloadable managers
        self.reloadable = {}

        # Commitable managers
        self.commitable = {
            "commands": self.commands,
            "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:
                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)

        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
Esempio n. 21
0
    def accept_duel(self, bot, source, **rest):
        """
        Accepts any active duel requests you've received.

        How to use: !accept
        """

        if source.id not in self.duel_targets:
            bot.whisper(source,
                        "You are not being challenged to a duel by anyone.")
            return

        with DBManager.create_session_scope() as db_session:
            requestor = User.find_by_id(db_session,
                                        self.duel_targets[source.id])
            duel_price = self.duel_request_price[self.duel_targets[source.id]]
            if not source.can_afford(duel_price) or not requestor.can_afford(
                    duel_price):
                bot.whisper(
                    source,
                    f"Your duel request with {requestor} was cancelled due to one of you not having enough points.",
                )
                bot.whisper(
                    requestor,
                    f"Your duel request with {source} was cancelled due to one of you not having enough points.",
                )

                del self.duel_requests[requestor.id]
                del self.duel_request_price[requestor.id]
                del self.duel_begin_time[requestor.id]
                del self.duel_targets[source.id]

                return False

            source.points -= duel_price
            requestor.points -= duel_price
            participants = [source, requestor]
            winner = random.choice(participants)
            participants.remove(winner)
            loser = participants.pop()

            winner.points += duel_price * 2

            # Persist duel statistics
            winner.duel_stats.won(duel_price)
            loser.duel_stats.lost(duel_price)
            arguments = {
                "winner": winner.name,
                "loser": loser.name,
                "total_pot": duel_price,
                "extra_points": duel_price,
            }

            if duel_price > 0:
                message = self.get_phrase("message_won_points", **arguments)
                if duel_price >= 500 and self.settings["show_on_clr"]:
                    bot.websocket_manager.emit(
                        "notification",
                        {"message": f"{winner} won the duel vs {loser}"})
            else:
                message = self.get_phrase("message_won", **arguments)
            bot.say(message)

            del self.duel_requests[requestor.id]
            del self.duel_request_price[requestor.id]
            del self.duel_begin_time[requestor.id]
            del self.duel_targets[source.id]

            HandlerManager.trigger("on_duel_complete",
                                   winner=winner,
                                   loser=loser,
                                   points_won=duel_price,
                                   points_bet=duel_price)
Esempio n. 22
0
    def pull(self, bot, source, message, **rest):
        if message is None:
            bot.whisper(
                source,
                "I didn't recognize your bet! Usage: !slotmachine 150 to bet 150 points"
            )
            return False

        low_tier_emotes = self.settings["low_tier_emotes"].split()
        high_tier_emotes = self.settings["high_tier_emotes"].split()

        if len(low_tier_emotes) == 0 or len(high_tier_emotes) == 0:
            return False

        msg_split = message.split(" ")
        try:
            bet = pajbot.utils.parse_points_amount(source, msg_split[0])
        except pajbot.exc.InvalidPointAmount as e:
            bot.whisper(source, str(e))
            return False

        if not source.can_afford(bet):
            bot.whisper(
                source,
                f"You don't have enough points to do a slot machine pull for {bet} points :("
            )
            return False

        if bet < self.settings["min_bet"]:
            bot.whisper(
                source,
                f"You have to bet at least {self.settings['min_bet']} point! :("
            )
            return False

        # how much of the users point they're expected to get back (basically how much the house yoinks)
        expected_return = 1.0

        ltsw = self.settings["ltsw"] / 100.0
        htsw = self.settings["htsw"] / 100.0
        ltbw = self.settings["ltbw"] / 100.0
        htbw = self.settings["htbw"] / 100.0

        bet_return, randomized_emotes = pull_lol(low_tier_emotes,
                                                 high_tier_emotes, bet,
                                                 expected_return, ltsw, htsw,
                                                 ltbw, htbw)

        # Calculating the result
        if bet_return <= 0.0:
            points = -bet
        else:
            points = bet * bet_return

        source.points += points

        arguments = {
            "bet": bet,
            "result": points,
            "user": source.name,
            "points": source.points,
            "win": points > 0,
            "emotes": " ".join(randomized_emotes),
        }

        if points > 0:
            out_message = self.get_phrase("message_won", **arguments)
        else:
            out_message = self.get_phrase("message_lost", **arguments)

        if self.settings["options_output"] == "4. Combine output in chat":
            if bot.is_online:
                self.add_message(bot, arguments)
            else:
                bot.me(out_message)
        if self.settings["options_output"] == "1. Show results in chat":
            bot.me(out_message)
        if self.settings["options_output"] == "2. Show results in whispers":
            bot.whisper(source, out_message)
        if (self.settings["options_output"] ==
                "3. Show results in chat if it's over X points else it will be whispered."
            ):
            if abs(points) >= self.settings["min_show_points"]:
                bot.me(out_message)
            else:
                bot.whisper(source, out_message)

        HandlerManager.trigger("on_slot_machine_finish",
                               user=source,
                               points=points)
Esempio n. 23
0
    def poll_trackobot_stage2(self, game_data):
        latest_game = game_data['history'][0]

        if latest_game['id'] != self.last_game_id:
            # A new game has been detected
            # Reset all variables
            winners = []
            losers = []
            total_winning_points = 0
            total_losing_points = 0
            points_bet = {
                    'win': 0,
                    'loss': 0,
                    }
            bet_game_id = None

            # Mark down the last game's results
            with DBManager.create_session_scope() as db_session:
                bet_game = HSBetGame(latest_game['id'], latest_game['result'])
                db_session.add(bet_game)
                db_session.flush()
                bet_game_id = bet_game.id

                db_bets = {}

                for username in self.bets:
                    bet_for_win, points = self.bets[username]
                    """
                    self.bot.me('{} bet {} points on the last game to end up as a {}'.format(
                        username,
                        points,
                        'win' if bet_for_win else 'loss'))
                        """

                    user = self.bot.users.find(username, db_session=db_session)
                    if user is None:
                        continue

                    correct_bet = (latest_game['result'] == 'win' and bet_for_win is True) or (latest_game['result'] == 'loss' and bet_for_win is False)
                    points_bet['win' if bet_for_win else 'loss'] += points
                    db_bets[username] = HSBetBet(bet_game_id, user.id, 'win' if bet_for_win else 'loss', points, 0)
                    if correct_bet:
                        winners.append((user, points))
                        total_winning_points += points
                        user.remove_debt(points)
                    else:
                        losers.append((user, points))
                        total_losing_points += points
                        user.pay_debt(points)
                        db_bets[username].profit = -points
                        self.bot.whisper(user.username, 'You bet {} points on the wrong outcome, so you lost it all. :('.format(
                            points))

                for obj in losers:
                    user, points = obj
                    user.save()
                    log.debug('{} lost {} points!'.format(user, points))

                for obj in winners:
                    points_reward = 0

                    user, points = obj

                    if points == 0:
                        # If you didn't bet any points, you don't get a part of the cut.
                        HandlerManager.trigger('on_user_win_hs_bet', user, points_reward)
                        continue

                    pot_cut = points / total_winning_points
                    points_reward = int(pot_cut * total_losing_points)
                    db_bets[user.username].profit = points_reward
                    user.points += points_reward
                    user.save()
                    HandlerManager.trigger('on_user_win_hs_bet', user, points_reward)
                    self.bot.whisper(user.username, 'You bet {} points on the right outcome, that rewards you with a profit of {} points! (Your bet was {:.2f}% of the total pool)'.format(
                        points, points_reward, pot_cut * 100))
                    """
                    self.bot.me('{} bet {} points, and made a profit of {} points by correctly betting on the HS game!'.format(
                        user.username_raw, points, points_reward))
                        """

                for username in db_bets:
                    bet = db_bets[username]
                    db_session.add(bet)

            self.bot.me('A new game has begun! Vote with !hsbet win/lose POINTS')
            self.bets = {}
            self.last_game_id = latest_game['id']
            self.last_game_start = datetime.datetime.now() + datetime.timedelta(seconds=self.settings['time_until_bet_closes'])
            payload = {
                    'time_left': self.settings['time_until_bet_closes'],
                    'win': 0,
                    'loss': 0,
                    }
            self.bot.websocket_manager.emit('hsbet_new_game', data=payload)

            # stats about the game
            ratio = 0.0
            try:
                ratio = (total_losing_points / total_winning_points) * 100.0
            except:
                pass
            self.bot.me('The game ended as a {result}. {points_bet[win]} points bet on win, {points_bet[loss]} points bet on loss. Winners can expect a {ratio:.2f}% return on their bet points.'.format(ratio=ratio, result=latest_game['result'], points_bet=points_bet))

            redis = RedisManager.get()
            redis.set('{streamer}:last_hsbet_game_id'.format(streamer=StreamHelper.get_streamer()), self.last_game_id)
            redis.set('{streamer}:last_hsbet_game_start'.format(streamer=StreamHelper.get_streamer()), self.last_game_start.timestamp())
Esempio n. 24
0
 def do_tick():
     HandlerManager.trigger("on_tick")
Esempio n. 25
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})"
Esempio n. 26
0
    def multi_end_raffle(self):
        if not self.raffle_running:
            return False

        self.raffle_running = False

        if len(self.raffle_users) == 0:
            self.bot.me('Wow, no one joined the raffle DansGame')
            return False

        # Shuffle the list of participants
        random.shuffle(self.raffle_users)

        num_participants = len(self.raffle_users)

        abs_points = abs(self.raffle_points)

        max_winners = min(num_participants, 200)
        min_point_award = 100
        negative = self.raffle_points < 0

        # Decide how we should pick the winners
        log.info('Num participants: {}'.format(num_participants))
        for winner_percentage in [x * 0.01 for x in range(1, 26)]:
            log.info('Winner percentage: {}'.format(winner_percentage))
            num_winners = math.ceil(num_participants * winner_percentage)
            points_per_user = math.ceil(abs_points / num_winners)
            log.info('nw: {}, ppu: {}'.format(num_winners, points_per_user))

            if num_winners > max_winners:
                num_winners = max_winners
                points_per_user = math.ceil(abs_points / num_winners)
                break
            elif points_per_user < min_point_award:
                num_winners = max(
                    1,
                    min(math.floor(abs_points / min_point_award),
                        num_participants))
                points_per_user = math.ceil(abs_points / num_winners)
                break

        log.info('k done. got {} winners'.format(num_winners))
        winners = self.raffle_users[:num_winners]
        self.raffle_users = []

        if negative:
            points_per_user *= -1

        self.bot.me(
            'The multi-raffle has finished! {0} users won {1} points each! PogChamp'
            .format(len(winners), points_per_user))

        winners_arr = []
        for winner in winners:
            winner.points += points_per_user
            winners_arr.append(winner)

            winners_str = generate_winner_list(winners_arr)
            if len(winners_str) > 300:
                self.bot.me('{} won {} points each!'.format(
                    winners_str, points_per_user))
                winners_arr = []

            winner.save()

        if len(winners_arr) > 0:
            winners_str = generate_winner_list(winners_arr)
            self.bot.me('{} won {} points each!'.format(
                winners_str, points_per_user))

        HandlerManager.trigger('on_multiraffle_win', winners, points_per_user)
Esempio n. 27
0
    def parse_message(self, msg_raw, source, event, tags={}, whisper=False):
        msg_lower = msg_raw.lower()

        emote_tag = None

        for tag in tags:
            if tag['key'] == 'subscriber' and event.target == self.channel:
                source.subscriber = tag['value'] == '1'
            elif tag['key'] == 'emotes' and tag['value']:
                emote_tag = tag['value']
            elif tag['key'] == 'display-name' and tag['value']:
                source.username_raw = tag['value']
            elif tag['key'] == 'user-type':
                source.moderator = tag['value'] == 'mod' or source.username == self.streamer

        # source.num_lines += 1

        if source is None:
            log.error('No valid user passed to parse_message')
            return False

        if source.banned:
            self.ban(source.username)
            return False

        # If a user types when timed out, we assume he's been unbanned for a good reason and remove his flag.
        if source.timed_out is True:
            source.timed_out = False

        # Parse emotes in the message
        message_emotes = self.emotes.parse_message_twitch_emotes(source, msg_raw, emote_tag, whisper)

        urls = self.find_unique_urls(msg_raw)

        if whisper:
            self.whisper('datguy1', '{} said: {}'.format(source.username, msg_raw))
        # log.debug('{2}{0}: {1}'.format(source.username, msg_raw, '<w>' if whisper else ''))

        res = HandlerManager.trigger('on_message',
                source, msg_raw, message_emotes, whisper, urls, event,
                stop_on_false=True)
        if res is False:
            return False

        source.last_seen = datetime.datetime.now()
        source.last_active = datetime.datetime.now()

        if source.ignored:
            return False

        if msg_lower[:1] == '!':
            msg_lower_parts = msg_lower.split(' ')
            trigger = msg_lower_parts[0][1:]
            msg_raw_parts = msg_raw.split(' ')
            remaining_message = ' '.join(msg_raw_parts[1:]) if len(msg_raw_parts) > 1 else None
            if trigger in self.commands:
                command = self.commands[trigger]
                extra_args = {
                        'emotes': message_emotes,
                        'trigger': trigger,
                        }
                command.run(self, source, remaining_message, event=event, args=extra_args, whisper=whisper)
Esempio n. 28
0
    def base_paid_timeout(self, bot, source, message, _time, _cost):
        if message is None or len(message) == 0:
            return False

        target = message.split(" ")[0]
        if len(target) < 2:
            return False

        with DBManager.create_session_scope() as db_session:
            victim = User.find_by_user_input(db_session, target)

            if victim is None:
                bot.whisper(source, "This user does not exist FailFish")
                return False

            if victim == source:
                # bot.whisper(source.username, 'You can\'t timeout yourself FailFish')
                source.points += 2
                return True

            if victim.last_active is None or (
                    utils.now() -
                    victim.last_active) > datetime.timedelta(minutes=10):
                bot.whisper(
                    source,
                    "This user has not been active in chat within the last 10 minutes."
                )
                return False

            if victim.moderator is True:
                bot.whisper(
                    source,
                    "This person has mod privileges, timeouting this person is not worth it."
                )
                return False

            if victim.level >= self.settings["bypass_level"]:
                bot.whisper(
                    source,
                    "This person's user level is too high, you can't timeout this person."
                )
                return False

            if not victim.subscriber and source.subscriber:
                _cost = int(_cost * 0.8)

            if not source.can_afford(_cost):
                bot.whisper(
                    source.username,
                    "You need {} more points to be able to timeout {}".format(
                        source.points - _cost, victim.username_raw),
                )
                return False

            if source.username != "datguy1":
                source.points -= _cost

            now = utils.now()
            if victim.timeout_end is not None and victim.timeout_end > now:
                victim.timeout_end += datetime.timedelta(seconds=_time)
                bot.whisper(
                    victim,
                    f"{victim}, you were timed out for an additional {_time} seconds by {source}"
                )
                bot.whisper(
                    source,
                    f"You just used {_cost} points to time out {victim} for an additional {_time} seconds."
                )
                num_seconds = int((victim.timeout_end - now).total_seconds())
                bot.timeout(victim,
                            num_seconds,
                            reason=f"Timed out by {source}")
            else:
                bot.whisper(
                    source,
                    f"You just used {_cost} points to time out {victim} for {_time} seconds."
                )
                bot.whisper(
                    victim,
                    f"{source} just timed you out for {_time} seconds.")
                bot.timeout(victim,
                            _time,
                            reason=f"Timed out by {source} for {_cost} points")
                bot.say(
                    f"{source} timed out {victim} with !timeout for {_cost} points!"
                )

                victim.timeout_end = now + datetime.timedelta(seconds=_time)

            if self.settings["show_on_clr"]:
                payload = {"user": source.name, "victim": victim.name}
                bot.websocket_manager.emit("timeout", payload)

            HandlerManager.trigger("on_paid_timeout",
                                   source=source,
                                   victim=victim,
                                   cost=_cost,
                                   stop_on_false=False)
Esempio n. 29
0
    def on_pubmsg(self, chatconn, event):
        if event.source.user == self.nickname:
            return False

        username = event.source.user.lower()

        if self.streamer == 'forsen':
            if 'zonothene' in username:
                self._ban(username)
                return True

            raw_m = event.arguments[0].lower()
            if raw_m.startswith('!lastseen forsen'):
                if len(raw_m) > len('!lastseen forsen2'):
                    if raw_m[16] == ' ':
                        return True
                else:
                    return True

            if raw_m.startswith('!lastseen @forsen'):
                if len(raw_m) > len('!lastseen @forsen2'):
                    if raw_m[17] == ' ':
                        return True
                else:
                    return True

        if self.streamer == 'nymn':
            if 'hades_k' in username:
                self._timeout(username, 3600)
                return True

            if 'hades_b' in username:
                self._timeout(username, 3600)
                return True

            raw_m = event.arguments[0]
            m = ''.join(sorted(set(raw_m), key=raw_m.index))
            m = ''.join(ch for ch in m if ch.isalnum())
            if 'niqers' in m:
                self.timeout(username, 600)
                return True

            if 'niqe3rs' in m:
                self.timeout(username, 600)
                return True

            if 'niq3ers' in m:
                self.timeout(username, 600)
                return True

            if 'niqurs' in m:
                self.timeout(username, 600)
                return True

            if 'nigurs' in m:
                self.timeout(username, 600)
                return True

            if 'nige3rs' in m:
                self.timeout(username, 600)
                return True

            if 'nig3ers' in m:
                self.timeout(username, 600)
                return True

            if 'nig3ers' in m:
                self.timeout(username, 600)
                return True

            if 'nigger' in m:
                self.timeout(username, 600)
                return True

        # We use .lower() in case twitch ever starts sending non-lowercased usernames
        with self.users.get_user_context(username) as source:
            res = HandlerManager.trigger('on_pubmsg',
                    source, event.arguments[0],
                    stop_on_false=True)
            if res is False:
                return False

            self.parse_message(event.arguments[0], source, event, tags=event.tags)
Esempio n. 30
0
    def poll_trackobot_stage2(self, trackobot_game):
        if not self.detect_trackobot_game_change(trackobot_game):
            return

        with DBManager.create_session_scope() as db_session:
            current_game = self.get_current_game(db_session,
                                                 with_bets=True,
                                                 with_users=True)

            current_game.trackobot_id = trackobot_game.id
            current_game.outcome = trackobot_game.outcome

            points_by_outcome = current_game.get_points_by_outcome(db_session)
            total_points_in_pot = sum(points_by_outcome.values())

            for bet in current_game.bets:
                correct_bet = bet.outcome == current_game.outcome

                if not correct_bet:
                    # lost the bet
                    bet.profit = -bet.points
                    self.bot.whisper(
                        bet.user,
                        f"You bet {bet.points} points on the wrong outcome, so you lost it all. :("
                    )
                else:
                    # won the bet
                    investment_ratio = bet.points / points_by_outcome[
                        bet.outcome]
                    # pot_cut includes the user's initial investment
                    pot_cut = int(investment_ratio * total_points_in_pot)
                    # profit is just how much they won
                    bet.profit = pot_cut - bet.points
                    bet.user.points = User.points + pot_cut
                    self.bot.whisper(
                        bet.user,
                        f"You bet {bet.points} points on the right outcome, that leaves you with a profit of {bet.profit} points! (Your bet was {investment_ratio * 100:.2f}% of the total pot)",
                    )
                    HandlerManager.trigger("on_user_win_hs_bet",
                                           user=bet.user,
                                           points_won=bet.profit)

            winning_points = sum(
                points for outcome, points in points_by_outcome.items()
                if outcome == current_game.outcome)
            losing_points = sum(
                points for outcome, points in points_by_outcome.items()
                if outcome != current_game.outcome)
            end_message = f"The game ended as a {trackobot_game.outcome.name}. {points_by_outcome[HSGameOutcome.win]} points bet on win, {points_by_outcome[HSGameOutcome.loss]} points bet on loss."

            # don't want to divide by 0
            if winning_points != 0:
                ratio = losing_points / winning_points * 100
                end_message += f" Winners can expect a {ratio:.2f}% return on their bet points."
            else:
                end_message += " Nobody won any points. KKona"

            self.bot.me(end_message)

            # so we can create a new game
            db_session.flush()

            self.bot.me(
                "A new game has begun! Vote with !hsbet win/lose POINTS")
            current_game = self.get_current_game(db_session)
            time_limit = self.settings["time_until_bet_closes"]
            current_game.bet_deadline = utils.now() + datetime.timedelta(
                seconds=time_limit)

            bets_statistics = current_game.get_bets_by_outcome(db_session)

            payload = {
                "time_left": time_limit,
                **{key.name: value
                   for key, value in bets_statistics.items()}
            }
            self.bot.websocket_manager.emit("hsbet_new_game", data=payload)
Esempio n. 31
0
File: bot.py Progetto: jardg/pajbot
    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:
                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)
Esempio n. 32
0
    def multi_end_raffle(self):
        if not self.raffle_running:
            return False

        self.raffle_running = False

        if len(self.raffle_users) == 0:
            self.bot.me('Wow, no one joined the raffle DansGame')
            return False

        # Shuffle the list of participants
        random.shuffle(self.raffle_users)

        num_participants = len(self.raffle_users)

        abs_points = abs(self.raffle_points)

        max_winners = min(num_participants, 200)
        min_point_award = 100
        negative = self.raffle_points < 0

        # Decide how we should pick the winners
        log.info('Num participants: {}'.format(num_participants))
        for winner_percentage in [x * 0.01 for x in range(1, 26)]:
            log.info('Winner percentage: {}'.format(winner_percentage))
            num_winners = math.ceil(num_participants * winner_percentage)
            points_per_user = math.ceil(abs_points / num_winners)
            log.info('nw: {}, ppu: {}'.format(num_winners, points_per_user))

            if num_winners > max_winners:
                num_winners = max_winners
                points_per_user = math.ceil(abs_points / num_winners)
                break
            elif points_per_user < min_point_award:
                num_winners = max(1, min(math.floor(abs_points / min_point_award), num_participants))
                points_per_user = math.ceil(abs_points / num_winners)
                break

        log.info('k done. got {} winners'.format(num_winners))
        winners = self.raffle_users[:num_winners]
        self.raffle_users = []

        if negative:
            points_per_user *= -1

        self.bot.me('The multi-raffle has finished! {0} users won {1} points each! PogChamp'.format(len(winners), points_per_user))

        winners_arr = []
        for winner in winners:
            winner.points += points_per_user
            winners_arr.append(winner)

            winners_str = generate_winner_list(winners_arr)
            if len(winners_str) > 300:
                self.bot.me('{} won {} points each!'.format(winners_str, points_per_user))
                winners_arr = []

            winner.save()

        if len(winners_arr) > 0:
            winners_str = generate_winner_list(winners_arr)
            self.bot.me('{} won {} points each!'.format(winners_str, points_per_user))

        HandlerManager.trigger('on_multiraffle_win', winners, points_per_user)
Esempio n. 33
0
    def roulette(self, **options):
        if self.settings['only_roulette_after_sub']:
            if self.last_sub is None:
                return False
            if datetime.datetime.now() - self.last_sub > datetime.timedelta(seconds=self.settings['after_sub_roulette_time']):
                return False

        message = options['message']
        user = options['source']
        bot = options['bot']

        if message is None:
            bot.whisper(user.username, 'I didn\'t recognize your bet! Usage: !roulette 150 to bet 150 points')
            return False

        msg_split = message.split(' ')
        try:
            bet = pajbot.utils.parse_points_amount(user, msg_split[0])
        except pajbot.exc.InvalidPointAmount as e:
            bot.whisper(user.username, str(e))
            return False

        if not user.can_afford(bet):
            bot.whisper(user.username, 'You don\'t have enough points to do a roulette for {} points :('.format(bet))
            return False

        if bet < self.settings['min_roulette_amount']:
            bot.whisper(user.username, 'You have to bet at least {} point! :('.format(self.settings['min_roulette_amount']))
            return False

        # Calculating the result
        result = self.rigged_random_result()
        points = bet if result else -bet
        user.points += points

        with DBManager.create_session_scope() as db_session:
            r = Roulette(user.id, points)
            db_session.add(r)

        arguments = {
            'bet': bet,
            'user': user.username_raw,
            'points': user.points_available(),
            'win': points > 0,
        }

        if points > 0:
            out_message = self.get_phrase('message_won', **arguments)
        else:
            out_message = self.get_phrase('message_lost', **arguments)

        if self.settings['options_output'] == '4. Combine output in chat':
            self.add_message(bot, arguments)
        if self.settings['options_output'] == '1. Show results in chat':
            bot.me(out_message)
        if self.settings['options_output'] == '2. Show results in whispers':
            bot.whisper(user.username, out_message)
        if self.settings['options_output'] == '3. Show results in chat if it\'s over X points else it will be whispered.':
            if abs(points) >= self.settings['min_show_points']:
                bot.me(out_message)
            else:
                bot.whisper(user.username, out_message)

        HandlerManager.trigger('on_roulette_finish', user, points)
Esempio n. 34
0
File: bot.py Progetto: jardg/pajbot
 def do_tick(self):
     HandlerManager.trigger('on_tick')
Esempio n. 35
0
    def base_paid_timeout(self, bot, source, message, _time, _cost):
        if message is None or len(message) == 0:
            return False

        target = message.split(" ")[0]
        if len(target) < 2:
            return False

        with DBManager.create_session_scope() as db_session:
            victim = User.find_by_user_input(db_session, target)

            if victim is None:
                bot.whisper(source, "This user does not exist FailFish")
                return False

            if victim.last_active is None or (
                    utils.now() -
                    victim.last_active) > datetime.timedelta(minutes=10):
                bot.whisper(
                    source,
                    "This user has not been active in chat within the last 10 minutes."
                )
                return False

            if victim.moderator is True:
                bot.whisper(
                    source,
                    "This person has mod privileges, timeouting this person is not worth it."
                )
                return False

            if victim.level >= self.settings["bypass_level"]:
                bot.whisper(
                    source,
                    "This person's user level is too high, you can't timeout this person."
                )
                return False

            now = utils.now()
            if victim.timeout_end is not None and victim.timeout_end > now:
                victim.timeout_end += datetime.timedelta(seconds=_time)
                bot.whisper(
                    victim,
                    f"{victim}, you were timed out for an additional {_time} seconds by {source}"
                )
                bot.whisper(
                    source,
                    f"You just used {_cost} points to time out {victim} for an additional {_time} seconds."
                )
                num_seconds = int((victim.timeout_end - now).total_seconds())
                bot.timeout(victim,
                            num_seconds,
                            reason=f"Timed out by {source}")
            else:
                bot.whisper(
                    source,
                    f"You just used {_cost} points to time out {victim} for {_time} seconds."
                )
                bot.whisper(
                    victim,
                    f"{source} just timed you out for {_time} seconds. /w {bot.nickname} !$unbanme to unban yourself for points forsenMoney",
                )
                bot.timeout(victim, _time, reason=f"Timed out by {source}")
                victim.timeout_end = now + datetime.timedelta(seconds=_time)

            if self.settings["show_on_clr"]:
                payload = {"user": source.name, "victim": victim.name}
                bot.websocket_manager.emit("timeout", payload)

            HandlerManager.trigger("on_paid_timeout",
                                   source=source,
                                   victim=victim,
                                   cost=_cost,
                                   stop_on_false=False)
Esempio n. 36
0
    def parse_message(self, message, source, event, tags={}, whisper=False):
        msg_lower = message.lower()

        emote_tag = tags["emotes"]
        msg_id = tags.get("id", None)  # None on whispers!

        if not whisper and event.target == self.channel:
            # Moderator or broadcaster, both count
            source.moderator = tags[
                "mod"] == "1" or source.id == self.streamer_user_id
            source.subscriber = tags["subscriber"] == "1"

        if not whisper and source.banned:
            self.ban(source)
            return False

        # Parse emotes in the message
        emote_instances, emote_counts = self.emote_manager.parse_all_emotes(
            message, emote_tag)

        now = utils.now()
        source.last_seen = now
        source.last_active = now

        if not whisper:
            # increment epm and ecount
            self.epm_manager.handle_emotes(emote_counts)
            self.ecount_manager.handle_emotes(emote_counts)

        urls = self.find_unique_urls(message)

        res = HandlerManager.trigger(
            "on_message",
            source=source,
            message=message,
            emote_instances=emote_instances,
            emote_counts=emote_counts,
            whisper=whisper,
            urls=urls,
            msg_id=msg_id,
            event=event,
        )
        if res is False:
            return False

        if source.ignored:
            return False

        if whisper:
            self.whisper_login("datguy1",
                               "{} said: {}".format(source, message))

        if msg_lower[:1] == "!":
            msg_lower_parts = msg_lower.split(" ")
            trigger = msg_lower_parts[0][1:]
            msg_raw_parts = message.split(" ")
            remaining_message = " ".join(
                msg_raw_parts[1:]) if len(msg_raw_parts) > 1 else None
            if trigger in self.commands:
                command = self.commands[trigger]
                extra_args = {
                    "emote_instances": emote_instances,
                    "emote_counts": emote_counts,
                    "trigger": trigger,
                    "msg_id": msg_id,
                }
                command.run(self,
                            source,
                            remaining_message,
                            event=event,
                            args=extra_args,
                            whisper=whisper)
Esempio n. 37
0
    def roulette(self, bot, source, message, **rest):
        if self.settings["stream_status"] == "Online" and not bot.is_online:
            return

        if self.settings["stream_status"] == "Offline" and bot.is_online:
            return

        if self.settings["only_roulette_after_sub"]:
            if self.last_sub is None:
                return False
            if utils.now() - self.last_sub > datetime.timedelta(
                    seconds=self.settings["after_sub_roulette_time"]):
                return False

        if message is None:
            bot.whisper(
                source,
                "I didn't recognize your bet! Usage: !" +
                self.settings["command_name"] + " 150 to bet 150 points",
            )
            return False

        msg_split = message.split(" ")
        try:
            bet = utils.parse_points_amount(source, msg_split[0])
        except pajbot.exc.InvalidPointAmount as e:
            bot.whisper(source, str(e))
            return False

        if not source.can_afford(bet):
            bot.whisper(
                source,
                f"You don't have enough points to do a roulette for {bet} points :("
            )
            return False

        if bet < self.settings["min_roulette_amount"]:
            bot.whisper(
                source,
                f"You have to bet at least {self.settings['min_roulette_amount']} point! :("
            )
            return False

        # Calculating the result
        result = self.rigged_random_result()
        points = bet if result else -bet
        source.points += points

        with DBManager.create_session_scope() as db_session:
            r = Roulette(source.id, points)
            db_session.add(r)

        arguments = {
            "bet": bet,
            "user": source.name,
            "points": source.points,
            "win": points > 0
        }

        if points > 0:
            out_message = self.get_phrase("message_won", **arguments)
        else:
            out_message = self.get_phrase("message_lost", **arguments)

        if self.settings["options_output"] == "4. Combine output in chat":
            if bot.is_online:
                self.add_message(bot, arguments)
            else:
                bot.me(out_message)
        if self.settings["options_output"] == "1. Show results in chat":
            bot.me(out_message)
        if self.settings["options_output"] == "2. Show results in whispers":
            bot.whisper(source, out_message)
        if (self.settings["options_output"] ==
                "3. Show results in chat if it's over X points else it will be whispered."
            ):
            if abs(points) >= self.settings["min_show_points"]:
                bot.me(out_message)
            else:
                bot.whisper(source, out_message)

        HandlerManager.trigger("on_roulette_finish",
                               user=source,
                               points=points)
Esempio n. 38
0
    def __init__(self, config, args):
        self.config = config
        self.args = args

        self.last_ping = utils.now()
        self.last_pong = utils.now()

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

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

        # Pepega SE points sync
        pajbot.models.user.Config.se_sync_token = config["main"].get(
            "se_sync_token", None)
        pajbot.models.user.Config.se_channel = config["main"].get(
            "se_channel", None)

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

        if config["main"].getboolean("verified", False):
            TMI.promote_to_verified()

        # phrases
        self.phrases = {
            "welcome": ["{nickname} {version} running!"],
            "quit": ["{nickname} {version} shutting down..."]
        }
        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()

        TimeManager.init_timezone(self.timezone)

        # 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:]
        StreamHelper.init_streamer(self.streamer)

        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.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.twitch_legacy_api = TwitchLegacyAPI(self.api_client_credentials,
                                                 RedisManager.get())
        self.twitch_tmi_api = TwitchTMIAPI()

        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."
            )

        # SQL migrations
        sql_conn = DBManager.engine.connect().connection
        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()

        # 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 = utils.now()
        ActionParser.bot = self

        HandlerManager.init_handlers()

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

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

        self.users = UserManager()
        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.twitch_legacy_api,
                                          self.action_queue)
        self.epm_manager = EpmManager()
        self.ecount_manager = EcountManager()
        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(10 * 60, self.commit_all)
        self.execute_every(1, self.do_tick)

        # promote the admin to level 2000
        admin = None
        try:
            admin = self.config["main"]["admin"]
        except KeyError:
            log.warning(
                "No admin user specified. See the [main] section in the example config for its usage."
            )
        if admin is not None:
            with self.users.get_user_context(admin) as user:
                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 = 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.reactor.add_global_handler("all_events", self.irc._dispatcher,
                                        -10)

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

        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,
        }
Esempio n. 39
0
    def on_usernotice(self, source, tags, **rest):
        if "msg-id" not in tags:
            return

        if tags["msg-id"] == "resub":
            num_months = -1
            substreak_count = 0
            if "msg-param-months" in tags:
                num_months = int(tags["msg-param-months"])
            if "msg-param-cumulative-months" in tags:
                num_months = int(tags["msg-param-cumulative-months"])
            if "msg-param-streak-months" in tags:
                substreak_count = int(tags["msg-param-streak-months"])
            if "msg-param-should-share-streak" in tags:
                should_share = bool(tags["msg-param-should-share-streak"])
                if not should_share:
                    substreak_count = 0

            if "msg-param-sub-plan" not in tags:
                log.debug("subalert msg-id is resub, but missing msg-param-sub-plan: {}".format(tags))
                return

            # log.debug('msg-id resub tags: {}'.format(tags))

            # TODO: Should we check room id with streamer ID here? Maybe that's for pajbot2 instead
            self.on_resub(source, num_months, tags["msg-param-sub-plan"], None, substreak_count)
            HandlerManager.trigger("on_user_resub", user=source, num_months=num_months)
        elif tags["msg-id"] == "subgift":
            num_months = 0
            substreak_count = 0
            if "msg-param-months" in tags:
                num_months = int(tags["msg-param-months"])
            if "msg-param-cumulative-months" in tags:
                num_months = int(tags["msg-param-cumulative-months"])
            if "msg-param-streak-months" in tags:
                substreak_count = int(tags["msg-param-streak-months"])
            if "msg-param-should-share-streak" in tags:
                should_share = bool(tags["msg-param-should-share-streak"])
                if not should_share:
                    substreak_count = 0

            if "display-name" not in tags:
                log.debug("subalert msg-id is subgift, but missing display-name: {}".format(tags))
                return

            with self.bot.users.get_user_context(tags["msg-param-recipient-user-name"]) as receiver:
                if num_months > 1:
                    # Resub
                    self.on_resub(
                        receiver, num_months, tags["msg-param-sub-plan"], tags["display-name"], substreak_count
                    )
                    HandlerManager.trigger("on_user_resub", user=receiver, num_months=num_months)
                else:
                    # New sub
                    self.on_new_sub(receiver, tags["msg-param-sub-plan"], tags["display-name"])
                    HandlerManager.trigger("on_user_sub", user=receiver)
        elif tags["msg-id"] == "sub":
            if "msg-param-sub-plan" not in tags:
                log.debug("subalert msg-id is sub, but missing msg-param-sub-plan: {}".format(tags))
                return

            self.on_new_sub(source, tags["msg-param-sub-plan"])
            HandlerManager.trigger("on_user_sub", user=source)
        else:
            log.debug("Unhandled msg-id: {} - tags: {}".format(tags["msg-id"], tags))
Esempio n. 40
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)
Esempio n. 41
0
    def parse_message(self, message, source, event, tags={}, whisper=False):
        msg_lower = message.lower()

        emote_tag = None
        msg_id = None

        for tag in tags:
            if tag["key"] == "subscriber" and event.target == self.channel:
                source.subscriber = tag["value"] == "1"
            elif tag["key"] == "emotes":
                emote_tag = tag["value"]
            elif tag["key"] == "display-name" and tag["value"]:
                source.username_raw = tag["value"]
            elif tag["key"] == "user-type":
                source.moderator = tag[
                    "value"] == "mod" or source.username == self.streamer
            elif tag["key"] == "id":
                msg_id = tag["value"]

        # source.num_lines += 1

        if source is None:
            log.error("No valid user passed to parse_message")
            return False

        if source.banned:
            self.ban(source.username)
            return False

        # If a user types when timed out, we assume he's been unbanned for a good reason and remove his flag.
        if source.timed_out is True:
            source.timed_out = False

        # Parse emotes in the message
        emote_instances, emote_counts = self.emote_manager.parse_all_emotes(
            message, emote_tag)

        if not whisper:
            # increment epm and ecount
            self.epm_manager.handle_emotes(emote_counts)
            self.ecount_manager.handle_emotes(emote_counts)

        urls = self.find_unique_urls(message)

        res = HandlerManager.trigger(
            "on_message",
            source=source,
            message=message,
            emote_instances=emote_instances,
            emote_counts=emote_counts,
            whisper=whisper,
            urls=urls,
            msg_id=msg_id,
            event=event,
        )
        if res is False:
            return False

        source.last_seen = utils.now()
        source.last_active = utils.now()

        if source.ignored:
            return False

        if whisper:
            self.whisper("datguy1",
                         "{} said: {}".format(source.username_raw, message))

        if msg_lower[:1] == "!":
            msg_lower_parts = msg_lower.split(" ")
            trigger = msg_lower_parts[0][1:]
            msg_raw_parts = message.split(" ")
            remaining_message = " ".join(
                msg_raw_parts[1:]) if len(msg_raw_parts) > 1 else None
            if trigger in self.commands:
                command = self.commands[trigger]
                extra_args = {
                    "emote_instances": emote_instances,
                    "emote_counts": emote_counts,
                    "trigger": trigger,
                    "msg_id": msg_id,
                }
                command.run(self,
                            source,
                            remaining_message,
                            event=event,
                            args=extra_args,
                            whisper=whisper)
Esempio n. 42
0
 def do_tick(self):
     HandlerManager.trigger('on_tick')
Esempio n. 43
0
    def multi_end_raffle(self):
        if not self.raffle_running:
            return False

        self.raffle_running = False

        if len(self.raffle_users) == 0:
            self.bot.me("Wow, no one joined the raffle DansGame")
            return False

        # Shuffle the list of participants
        random.shuffle(self.raffle_users)

        num_participants = len(self.raffle_users)

        abs_points = abs(self.raffle_points)

        max_winners = min(num_participants, 200)
        min_point_award = 100
        negative = self.raffle_points < 0

        # Decide how we should pick the winners
        log.info("Num participants: {}".format(num_participants))

        for winner_percentage in [x * 0.01 for x in range(1, 10)]:
            log.info("Winner percentage: {}".format(winner_percentage))
            num_winners = math.ceil(num_participants * winner_percentage)
            points_per_user = math.ceil(abs_points / num_winners)
            log.info("nw: {}, ppu: {}".format(num_winners, points_per_user))

            if num_winners > max_winners:
                num_winners = max_winners
                points_per_user = math.ceil(abs_points / num_winners)
                break
            elif points_per_user < min_point_award:
                num_winners = max(
                    1,
                    min(math.floor(abs_points / min_point_award),
                        num_participants))
                points_per_user = math.ceil(abs_points / num_winners)
                break

        log.info("k done. got {} winners".format(num_winners))
        winners = self.raffle_users[:num_winners]

        for winner in winners:
            if not winner.subscriber and random.randint(1, 10) > 5:
                winners.remove(winner)
                continue

        if not winners:
            winners = random.choice(self.raffle_users)

        self.raffle_users = []

        points_per_user = math.ceil(abs_points / len(winners))

        if negative:
            self.bot.me(
                "The multi-raffle has finished! {0} users lost {1} points each! OMEGALUL"
                .format(len(winners), points_per_user * -1))
        else:
            self.bot.me(
                "The multi-raffle has finished! {0} users won {1} points each! PogChamp"
                .format(len(winners), points_per_user))

        winners_arr = []
        for winner in winners:
            if negative:
                winner.points = winner.points - points_per_user
            else:
                winner.points = winner.points + points_per_user
            winners_arr.append(winner)

            winners_str = generate_winner_list(winners_arr)
            if len(winners_str) > 300:
                self.bot.me("{} {} {} points each!".format(
                    winners_str, "lost" if negative else "won",
                    points_per_user))
                winners_arr = []

            winner.save()

        if len(winners_arr) > 0:
            winners_str = generate_winner_list(winners_arr)
            self.bot.me("{} {} {} points each!".format(
                winners_str, "lost" if negative else "won", points_per_user))

        HandlerManager.trigger("on_multiraffle_win",
                               winners=winners,
                               points_per_user=points_per_user *
                               -1 if negative else points_per_user)
Esempio n. 44
0
    def parse_message(self, message, source, event, tags={}, whisper=False):
        msg_lower = message.lower()

        emote_tag = tags["emotes"]
        msg_id = tags.get("id", None)  # None on whispers!
        badges_string = tags.get("badges", "")
        badges = dict((badge.split("/") for badge in badges_string.split(",") if badge != ""))

        if not whisper and event.target == self.channel:
            # Moderator or broadcaster, both count
            source.moderator = tags["mod"] == "1" or source.id == self.streamer_user_id
            # Having the founder badge means that the subscriber tag is set to 0. Therefore it's more stable to just check badges
            source.subscriber = "founder" in badges or "subscriber" in badges
            # once they are a founder they are always be a founder, regardless if they are a sub or not.
            if not source.founder:
                source.founder = "founder" in badges
            source.vip = "vip" in badges

        if not whisper and source.banned:
            self.ban(
                source,
                reason=f"User is on the {self.nickname} banlist. Contact a moderator level 1000 or higher for unban.",
            )
            return False

        # Parse emotes in the message
        emote_instances, emote_counts = self.emote_manager.parse_all_emotes(message, emote_tag)

        now = utils.now()
        source.last_seen = now
        source.last_active = now

        if not whisper:
            # increment epm and ecount
            self.epm_manager.handle_emotes(emote_counts)
            self.ecount_manager.handle_emotes(emote_counts)

        urls = self.find_unique_urls(message)

        res = HandlerManager.trigger(
            "on_message",
            source=source,
            message=message,
            emote_instances=emote_instances,
            emote_counts=emote_counts,
            whisper=whisper,
            urls=urls,
            msg_id=msg_id,
            event=event,
        )
        if res is False:
            return False

        if source.ignored:
            return False

        if msg_lower[:1] == "!":
            msg_lower_parts = msg_lower.split(" ")
            trigger = msg_lower_parts[0][1:]
            msg_raw_parts = message.split(" ")
            remaining_message = " ".join(msg_raw_parts[1:]) if len(msg_raw_parts) > 1 else None
            if trigger in self.commands:
                command = self.commands[trigger]
                extra_args = {
                    "emote_instances": emote_instances,
                    "emote_counts": emote_counts,
                    "trigger": trigger,
                    "msg_id": msg_id,
                }
                command.run(self, source, remaining_message, event=event, args=extra_args, whisper=whisper)
Esempio n. 45
0
    def on_usernotice(self, source, tags, **rest):
        if "msg-id" not in tags:
            return

        if tags["msg-id"] == "resub":
            num_months = -1
            substreak_count = 0
            if "msg-param-months" in tags:
                num_months = int(tags["msg-param-months"])
            if "msg-param-cumulative-months" in tags:
                num_months = int(tags["msg-param-cumulative-months"])
            if "msg-param-streak-months" in tags:
                substreak_count = int(tags["msg-param-streak-months"])
            if "msg-param-should-share-streak" in tags:
                should_share = bool(tags["msg-param-should-share-streak"])
                if not should_share:
                    substreak_count = 0

            if "msg-param-sub-plan" not in tags:
                log.debug(
                    f"subalert msg-id is resub, but missing msg-param-sub-plan: {tags}"
                )
                return

            # log.debug('msg-id resub tags: {}'.format(tags))

            # TODO: Should we check room id with streamer ID here? Maybe that's for pajbot2 instead
            self.on_resub(source, num_months, tags["msg-param-sub-plan"], None,
                          substreak_count)
            HandlerManager.trigger("on_user_resub",
                                   user=source,
                                   num_months=num_months)
        elif tags["msg-id"] == "subgift":
            num_months = 0
            substreak_count = 0
            if "msg-param-months" in tags:
                num_months = int(tags["msg-param-months"])
            if "msg-param-cumulative-months" in tags:
                num_months = int(tags["msg-param-cumulative-months"])
            if "msg-param-streak-months" in tags:
                substreak_count = int(tags["msg-param-streak-months"])
            if "msg-param-should-share-streak" in tags:
                should_share = bool(tags["msg-param-should-share-streak"])
                if not should_share:
                    substreak_count = 0

            if "display-name" not in tags:
                log.debug(
                    f"subalert msg-id is subgift, but missing display-name: {tags}"
                )
                return

            with DBManager.create_session_scope() as db_session:
                receiver_id = tags["msg-param-recipient-id"]
                receiver_login = tags["msg-param-recipient-user-name"]
                receiver_name = tags["msg-param-recipient-display-name"]
                receiver = User.from_basics(
                    db_session,
                    UserBasics(receiver_id, receiver_login, receiver_name))

                if num_months > 1:
                    # Resub
                    self.on_resub(receiver, num_months,
                                  tags["msg-param-sub-plan"],
                                  tags["display-name"], substreak_count)
                    HandlerManager.trigger("on_user_resub",
                                           user=receiver,
                                           num_months=num_months)
                else:
                    # New sub
                    self.on_new_sub(receiver, tags["msg-param-sub-plan"],
                                    tags["display-name"])
                    HandlerManager.trigger("on_user_sub", user=receiver)
        elif tags["msg-id"] == "sub":
            if "msg-param-sub-plan" not in tags:
                log.debug(
                    f"subalert msg-id is sub, but missing msg-param-sub-plan: {tags}"
                )
                return

            self.on_new_sub(source, tags["msg-param-sub-plan"])
            HandlerManager.trigger("on_user_sub", user=source)
        elif tags["msg-id"] == "giftpaidupgrade":
            self.on_gift_upgrade(source)
        elif tags["msg-id"] == "extendsub":
            self.on_extend_sub(source)
        else:
            log.debug(f"Unhandled msg-id: {tags['msg-id']} - tags: {tags}")
Esempio n. 46
0
    def commit_all(self):
        for key, manager in self.commitable.items():
            manager.commit()

        HandlerManager.trigger("on_commit", stop_on_false=False)
Esempio n. 47
0
    def multi_end_raffle(self):
        if not self.raffle_running:
            return False

        self.raffle_running = False

        if len(self.raffle_users) == 0:
            self.bot.me("Wow, no one joined the raffle DansGame")
            return False

        num_participants = len(self.raffle_users)

        # start out with the theoretical maximum: everybody wins
        num_winners = num_participants

        # we want to impose three limits on the winner picking:
        # - a winner should get 100 points at minimum,
        num_winners = min(
            num_winners,
            math.floor(
                abs(self.raffle_points) /
                self.MULTI_RAFFLE_MIN_WIN_POINTS_AMOUNT))

        # - winner percentage should not be higher than 26%,
        num_winners = min(
            num_winners,
            math.floor(num_participants * self.MULTI_RAFFLE_MAX_WINNERS_RATIO))

        # - and we don't want to have more than 200 winners.
        num_winners = min(num_winners, self.MULTI_RAFFLE_MAX_WINNERS_AMOUNT)

        # we at least want one person to win (some of these restrictions might calculate a maximum of 0...)
        num_winners = max(num_winners, 1)

        # now we can figure out how much each participant should win
        points_per_user = int(round(self.raffle_points / num_winners))

        # and we can pick the winners!
        winner_ids = random.sample(self.raffle_users, num_winners)
        with DBManager.create_session_scope() as db_session:
            winners = db_session.query(User).filter(
                User.id.in_(winner_ids)).all()

            # reset
            self.raffle_users = set()

            if num_winners == 1:
                self.bot.me(
                    f"The multi-raffle has finished! 1 user {format_win(points_per_user)} points! PogChamp"
                )
            else:
                self.bot.me(
                    f"The multi-raffle has finished! {num_winners} users {format_win(points_per_user)} points each! PogChamp"
                )

            winners_arr = []
            for winner in winners:
                winner.points += points_per_user
                winners_arr.append(winner)

                winners_str = generate_winner_list(winners_arr)
                if len(winners_str) > 300:
                    if len(winners_arr) == 1:
                        self.bot.me(
                            f"{winners_str} {format_win(points_per_user)} points!"
                        )
                    else:
                        self.bot.me(
                            f"{winners_str} {format_win(points_per_user)} points each!"
                        )
                    winners_arr = []

            if len(winners_arr) > 0:
                winners_str = generate_winner_list(winners_arr)
                if len(winners_arr) == 1:
                    self.bot.me(
                        f"{winners_str} {format_win(points_per_user)} points!")
                else:
                    self.bot.me(
                        f"{winners_str} {format_win(points_per_user)} points each!"
                    )

            HandlerManager.trigger("on_multiraffle_win",
                                   winners=winners,
                                   points_per_user=points_per_user)
Esempio n. 48
0
    def pull(self, **options):
        log.debug('pull xd')
        message = options['message']
        user = options['source']
        bot = options['bot']

        if message is None:
            bot.whisper(user.username, 'I didn\'t recognize your bet! Usage: !slotmachine 150 to bet 150 points')
            return False

        low_tier_emotes = self.settings['low_tier_emotes'].split()
        high_tier_emotes = self.settings['high_tier_emotes'].split()

        if len(low_tier_emotes) == 0 or len(high_tier_emotes) == 0:
            return False

        msg_split = message.split(' ')
        try:
            bet = pajbot.utils.parse_points_amount(user, msg_split[0])
        except pajbot.exc.InvalidPointAmount as e:
            bot.whisper(user.username, str(e))
            return False

        if not user.can_afford(bet):
            bot.whisper(user.username, 'You don\'t have enough points to do a slot machine pull for {} points :('.format(bet))
            return False

        if bet < self.settings['min_bet']:
            bot.whisper(user.username, 'You have to bet at least {} point! :('.format(self.settings['min_bet']))
            return False

        # how much of the users point they're expected to get back (basically how much the house yoinks)
        expected_return = 1.0

        ltsw = self.settings['ltsw'] / 100.0
        htsw = self.settings['htsw'] / 100.0
        ltbw = self.settings['ltbw'] / 100.0
        htbw = self.settings['htbw'] / 100.0

        bet_return, randomized_emotes = pull_lol(low_tier_emotes, high_tier_emotes, bet, expected_return, ltsw, htsw, ltbw, htbw)

        # Calculating the result
        if bet_return <= 0.0:
            points = -bet
        else:
            points = bet * bet_return

        user.points += points

        arguments = {
            'bet': bet,
            'result': points,
            'user': user.username_raw,
            'points': user.points_available(),
            'win': points > 0,
            'emotes': ' '.join(randomized_emotes),
        }

        if points > 0:
            out_message = self.get_phrase('message_won', **arguments)
        else:
            out_message = self.get_phrase('message_lost', **arguments)

        if self.settings['options_output'] == '4. Combine output in chat':
            if bot.is_online:
                self.add_message(bot, arguments)
            else:
                bot.me(out_message)
        if self.settings['options_output'] == '1. Show results in chat':
            bot.me(out_message)
        if self.settings['options_output'] == '2. Show results in whispers':
            bot.whisper(user.username, out_message)
        if self.settings['options_output'] == '3. Show results in chat if it\'s over X points else it will be whispered.':
            if abs(points) >= self.settings['min_show_points']:
                bot.me(out_message)
            else:
                bot.whisper(user.username, out_message)

        HandlerManager.trigger('on_slot_machine_finish', user, points)
Esempio n. 49
0
    def accept_duel(self, **options):
        """
        Accepts any active duel requests you've received.

        How to add: !add funccommand accept accept_duel --cd 0 --usercd 0
        How to use: !accept
        """

        bot = options['bot']
        source = options['source']
        duel_tax = 0.3  # 30% tax

        if source.username not in self.duel_targets:
            bot.whisper(source.username, 'You are not being challenged to a duel by anyone.')
            return

        requestor = bot.users[self.duel_targets[source.username]]
        duel_price = self.duel_request_price[self.duel_targets[source.username]]

        if not source.can_afford(duel_price) or not requestor.can_afford(duel_price):
            bot.whisper(source.username, 'Your duel request with {} was cancelled due to one of you not having enough points.'.format(requestor.username_raw))
            bot.whisper(requestor.username, 'Your duel request with {} was cancelled due to one of you not having enough points.'.format(source.username_raw))

            del self.duel_requests[self.duel_targets[source.username]]
            del self.duel_targets[source.username]

            return False

        source.points -= duel_price
        requestor.points -= duel_price
        winning_pot = int(duel_price * (1.0 - duel_tax))
        participants = [source, requestor]
        winner = random.choice(participants)
        participants.remove(winner)
        loser = participants.pop()
        winner.points += duel_price
        winner.points += winning_pot

        winner.save()
        loser.save()

        DuelManager.user_won(winner, winning_pot)
        DuelManager.user_lost(loser, duel_price)

        arguments = {
                'winner': winner.username,
                'loser': loser.username,
                'total_pot': duel_price,
                'extra_points': winning_pot,
                }

        if duel_price > 0:
            message = self.get_phrase('message_won_points', **arguments)
            if duel_price >= 500 and self.settings['show_on_clr']:
                bot.websocket_manager.emit('notification', {'message': '{} won the duel vs {}'.format(winner.username_raw, loser.username_raw)})
        else:
            message = self.get_phrase('message_won', **arguments)
        bot.say(message)

        del self.duel_requests[self.duel_targets[source.username]]
        del self.duel_targets[source.username]

        HandlerManager.trigger('on_duel_complete',
                winner, loser,
                winning_pot, duel_price)