def start_quest(self): HandlerManager.add_handler('on_message', self.on_message) redis = RedisManager.get() self.load_progress(redis=redis) self.load_data(redis=redis)
def command_start(self, **options): bot = options['bot'] source = options['source'] message = options['message'] if self.trivia_running: bot.safe_me('{}, a trivia is already running'.format(source.username_raw)) return self.trivia_running = True self.job.resume() try: self.point_bounty = int(message) if self.point_bounty < 0: self.point_bounty = 0 elif self.point_bounty > 50: self.point_bounty = 50 except: self.point_bounty = self.settings['default_point_bounty'] if self.point_bounty > 0: bot.safe_me('The trivia has started! {} points for each right answer!'.format(self.point_bounty)) else: bot.safe_me('The trivia has started!') HandlerManager.add_handler('on_message', self.on_message)
def stop_quest(self): HandlerManager.remove_handler('on_user_win_hs_bet', self.on_user_win_hs_bet) redis = RedisManager.get() self.reset_progress(redis=redis) redis.delete(self.hsbet_points_key)
def stop_quest(self): HandlerManager.remove_handler('on_duel_complete', self.on_duel_complete) redis = RedisManager.get() self.reset_progress(redis=redis) redis.delete(self.points_required_key)
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')
def stop_quest(self): HandlerManager.remove_handler('on_message', self.on_message) redis = RedisManager.get() self.reset_progress(redis=redis) redis.delete(self.current_emote_key)
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)
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)
def start_quest(self): HandlerManager.add_handler('on_user_win_hs_bet', self.on_user_win_hs_bet) redis = RedisManager.get() self.load_progress(redis=redis) self.load_data(redis=redis) self.LIMIT = self.hsbet_points_required
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)
def disable(self, bot): HandlerManager.remove_handler('on_message', self.on_message) HandlerManager.remove_handler('on_commit', self.on_commit) if self.db_session is not None: self.db_session.commit() self.db_session.close() self.db_session = None self.links = {}
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)
def start_quest(self): HandlerManager.add_handler('on_duel_complete', self.on_duel_complete) redis = RedisManager.get() self.load_progress(redis=redis) self.load_data(redis=redis) self.LIMIT = self.points_required
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)
def enable(self, bot): HandlerManager.add_handler('on_message', self.on_message, priority=200) HandlerManager.add_handler('on_commit', self.on_commit) if self.db_session is not None: self.db_session.commit() self.db_session.close() self.db_session = None self.links = {} self.db_session = DBManager.create_session()
def command_stop(self, **options): bot = options['bot'] source = options['source'] if not self.trivia_running: bot.safe_me('{}, no trivia is active right now'.format(source.username_raw)) return self.job.pause() self.trivia_running = False self.step_end() bot.safe_me('The trivia has been stopped.') HandlerManager.remove_handler('on_message', self.on_message)
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)
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)
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)
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)
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)
def do_tick(): HandlerManager.trigger("on_tick")
def disable(self, bot): HandlerManager.remove_handler('on_message', self.on_message) HandlerManager.remove_handler('on_usernotice', self.on_usernotice)
def enable(self, bot): self.checkjob.resume() self.checkPaused = False HandlerManager.add_handler("on_quit", self.stop_trivia)
def disable(self, bot): self.checkjob.pause() self.checkPaused = True HandlerManager.remove_handler("on_quit", self.stop_trivia)
def enable(self, bot): HandlerManager.add_handler("on_message", self.on_message, priority=150, run_if_propagation_stopped=True)
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) 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_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)
def enable(self, bot): HandlerManager.add_handler("on_message", self.on_message)
def start_quest(self): HandlerManager.add_handler('on_user_win_hs_bet', self.on_user_win_hs_bet) redis = RedisManager.get() self.load_progress(redis=redis)
def enable(self, bot): HandlerManager.add_handler('on_pubmsg', self.on_pubmsg) self.bot = bot
def __init__(self, config, args): self.config = config self.args = args self.last_ping = utils.now() self.last_pong = utils.now() 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) wait_for_redis_data_loaded(RedisManager.get()) self.nickname = config["main"].get("nickname", "pajbot") if config["main"].getboolean("verified", False): TMI.promote_to_verified() # 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() # 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"] 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"], ) HandlerManager.init_handlers() 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.spotify_api = None self.spotify_token_manager = None if ("client_id" in config["spotify"] and "client_secret" in config["spotify"] and "redirect_uri" in config["spotify"] and "user_id" in config["spotify"]): if (config["spotify"]["client_id"] != "" and config["spotify"]["client_secret"] != "" and config["spotify"]["redirect_uri"] != "" and config["spotify"]["user_id"] != ""): self.spotify_api = SpotifyApi( RedisManager.get(), config["spotify"]["client_id"], config["spotify"]["client_secret"], config["spotify"]["redirect_uri"], ) self.spotify_token_manager = SpotifyAccessTokenManager( self.spotify_api, RedisManager.get(), config["spotify"]["user_id"]) log.info("Spotify Loaded") self.streamlabs_api = None if "socket_access_token" in config["streamlabs"]: socket_access_token = config["streamlabs"]["socket_access_token"] if socket_access_token is not None and socket_access_token != "": self.streamlabs_api = StreamLabsAPI(socket_access_token) 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.pubsub_api = PubSubAPI( self, 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) # 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(self.on_connect) # 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 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() self.websocket_manager = WebSocketManager(self) # 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.songrequest_manager = SongrequestManager(self) self.songrequest_websocket_manager = SongRequestWebSocketManager(self) 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.discord_bot_manager = DiscordBotManager(self, RedisManager.get()) 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.spotify_streamlabs_manager = SpotifyStreamLabsManager(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 = 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, "bot_domain": self.bot_domain, } 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})"
def start_quest(self): HandlerManager.add_handler("on_duel_complete", self.on_duel_complete) redis = RedisManager.get() self.load_progress(redis=redis)
def disable(self, bot): HandlerManager.remove_handler("on_user_sub", self.on_user_sub) HandlerManager.remove_handler("on_user_resub", self.on_user_resub)
def enable(self, bot): self.bot = bot HandlerManager.add_handler("on_user_sub", self.on_user_sub) HandlerManager.add_handler("on_user_resub", self.on_user_resub)
def enable(self, bot): if not bot: return HandlerManager.add_handler("on_pubnotice", self.on_pubnotice)
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 winners = self.raffle_users[:num_winners] self.raffle_users = [] if negative: points_per_user *= -1 for winner in winners: if not winner.subscriber and random.randint(1, 10) > 5: winners.remove(winner) continue points_per_user = math.ceil(abs_points / len(winners)) 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)
def enable(self, bot): self.bot = bot HandlerManager.add_handler('on_tick', self.on_tick)
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 self.streamer == 'forsenlol' and whisper is False: follow_time = self.twitchapi.get_follow_relationship2(source.username, self.streamer) if follow_time is False: self._timeout(source.username, 600, '2 years follow mode (or api is down?)') return follow_age = datetime.datetime.now() - follow_time log.debug(follow_age) if follow_age.days < 730: log.debug('followed less than 730 days LUL') self._timeout(source.username, 600, '2 years follow mode') """ 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)
def enable(self, bot): self.bot = bot HandlerManager.add_handler('on_user_sub', self.on_user_sub) HandlerManager.add_handler('on_user_resub', self.on_user_resub) HandlerManager.add_handler('on_tick', self.on_tick)
def disable(self, bot): HandlerManager.remove_handler('on_message', self.on_message)
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 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)
def disable(self, bot): HandlerManager.remove_handler("on_message", self.on_message)
def disable(self, bot): HandlerManager.remove_handler('on_user_sub', self.on_user_sub) HandlerManager.remove_handler('on_user_resub', self.on_user_resub) HandlerManager.remove_handler('on_tick', self.on_tick)
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)
def disable(self, bot): HandlerManager.remove_handler('on_stream_start', self.on_stream_start) HandlerManager.remove_handler('on_stream_stop', self.on_stream_stop) HandlerManager.remove_handler('on_managers_loaded', self.on_managers_loaded)
def enable(self, bot): HandlerManager.add_handler('on_message', self.on_message) HandlerManager.add_handler('on_usernotice', self.on_usernotice) self.bot = bot
def enable(self, bot): HandlerManager.add_handler("on_message", self.on_message, priority=150)
def disable(self, bot): # Web interface, nothing to do if not bot: return HandlerManager.remove_handler("on_pubnotice", self.on_pubnotice)
def enable(self, bot): if not bot: return HandlerManager.add_handler("on_redeem", self.on_redeem)
def commit_all(self): for key, manager in self.commitable.items(): manager.commit() HandlerManager.trigger("on_commit", stop_on_false=False)
def do_tick(self): HandlerManager.trigger('on_tick')
def disable(self, bot): if not bot: return HandlerManager.remove_handler("on_redeem", self.on_redeem)
def disable(self, bot): HandlerManager.remove_handler('on_pubmsg', self.on_pubmsg)
def enable(self, bot): HandlerManager.add_handler("on_pubmsg", self.on_pubmsg)
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)
def disable(self, bot): HandlerManager.remove_handler("on_pubmsg", self.on_pubmsg)
def disable(self, bot): HandlerManager.remove_handler('on_tick', self.on_tick)
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)