コード例 #1
0
ファイル: commands.py プロジェクト: alazymeme/pajbot
    def command_checkalias(**extra_args):
        json_data = request.get_json()
        if not json_data:
            return {"error": "No input data provided"}, 400
        try:
            data = CheckAliasSchema().load(json_data)
        except ValidationError as err:
            return {
                "error": f"Did not match schema: {json.dumps(err.messages)}"
            }, 400

        request_alias = data.alias.lower()

        command_manager = pajbot.managers.command.CommandManager(
            socket_manager=None,
            module_manager=ModuleManager(None).load(),
            bot=None).load(enabled=None)

        command_aliases = []

        for alias, command in command_manager.items():
            command_aliases.append(alias)
            if command.command and len(command.command) > 0:
                command_aliases.extend(command.command.split("|"))

        command_aliases = set(command_aliases)

        if request_alias in command_aliases:
            return {"error": "Alias already in use"}
        else:
            return {"success": "good job"}
コード例 #2
0
def get_cached_commands() -> List[Dict[str, Any]]:
    CACHE_TIME = 30  # seconds

    redis = RedisManager.get()
    commands_key = f"{StreamHelper.get_streamer()}:cache:commands"
    commands = redis.get(commands_key)
    if commands is not None:
        cached_bot_command_list = json.loads(commands)
        if not isinstance(cached_bot_command_list, list):
            return []
        return cached_bot_command_list

    log.debug("Updating commands...")
    bot_commands = pajbot.managers.command.CommandManager(
        socket_manager=None,
        module_manager=ModuleManager(None).load(),
        bot=None).load(load_examples=True)
    bot_commands_list = bot_commands.parse_for_web()

    bot_commands_list.sort(key=lambda x: (x.id or -1, x.main_alias))
    jsonified_bot_commands_list = [c.jsonify() for c in bot_commands_list]
    redis.setex(commands_key,
                value=json.dumps(jsonified_bot_commands_list,
                                 separators=(",", ":")),
                time=CACHE_TIME)

    return jsonified_bot_commands_list
コード例 #3
0
ファイル: admin.py プロジェクト: polle-vanhoof/pajbot
def commands(**options):
    from pajbot.models.command import CommandManager
    from pajbot.models.module import ModuleManager
    bot_commands = CommandManager(socket_manager=None,
                                  module_manager=ModuleManager(None).load(),
                                  bot=None).load(enabled=None)

    bot_commands_list = bot_commands.parse_for_web()
    custom_commands = []
    point_commands = []
    moderator_commands = []

    for command in bot_commands_list:
        if command.id is None:
            continue
        if command.level > 100 or command.mod_only:
            moderator_commands.append(command)
        elif command.cost > 0:
            point_commands.append(command)
        else:
            custom_commands.append(command)

    return render_template('admin/commands.html',
                           custom_commands=sorted(custom_commands,
                                                  key=lambda f: f.command),
                           point_commands=sorted(point_commands,
                                                 key=lambda a:
                                                 (a.cost, a.command)),
                           moderator_commands=sorted(
                               moderator_commands,
                               key=lambda c:
                               (c.level
                                if c.mod_only is False else 500, c.command)),
                           created=session.pop('command_created_id', None),
                           edited=session.pop('command_edited_id', None))
コード例 #4
0
def modules_edit(module_id, **options):
    module_manager = ModuleManager(None).load(do_reload=False)
    current_module = find(lambda m: m.ID == module_id,
                          module_manager.all_modules)

    if current_module is None:
        return render_template('admin/module_404.html'), 404

    sub_modules = []
    for module in module_manager.all_modules:
        module.db_module = None

    with DBManager.create_session_scope() as db_session:
        for db_module in db_session.query(Module):
            module = find(lambda m: m.ID == db_module.id,
                          module_manager.all_modules)
            if module:
                module.db_module = db_module
                if module.PARENT_MODULE == current_module.__class__:
                    sub_modules.append(module)

        if current_module.db_module is None:
            return render_template('admin/module_404.html'), 404

        if request.method == 'POST':
            form_values = {key: value for key, value in request.form.items()}
            res = current_module.parse_settings(**form_values)
            if res is False:
                return render_template('admin/module_404.html'), 404

            current_module.db_module.settings = json.dumps(res)
            db_session.commit()

            settings = None
            try:
                settings = json.loads(current_module.db_module.settings)
            except (TypeError, ValueError):
                pass
            current_module.load(settings=settings)

            SocketClientManager.send(
                'module.update', {'module_id': current_module.db_module.id})

            return render_template('admin/configure_module.html',
                                   module=current_module,
                                   sub_modules=sub_modules)
        else:
            settings = None
            try:
                settings = json.loads(current_module.db_module.settings)
            except (TypeError, ValueError):
                pass
            current_module.load(settings=settings)

            return render_template('admin/configure_module.html',
                                   module=current_module,
                                   sub_modules=sub_modules)
コード例 #5
0
ファイル: admin.py プロジェクト: polle-vanhoof/pajbot
def modules_edit(module_id, **options):
    module_manager = ModuleManager(None).load(do_reload=False)
    current_module = find(lambda m: m.ID == module_id,
                          module_manager.all_modules)

    if current_module is None:
        return render_template('admin/module_404.html'), 404

    if request.method == 'POST':
        form_values = {key: value for key, value in request.form.items()}
        res = current_module.parse_settings(**form_values)
        if res is False:
            return render_template('admin/module_404.html'), 404

        with DBManager.create_session_scope() as db_session:
            db_module = db_session.query(Module).filter_by(
                id=module_id).one_or_none()
            if db_module is None:
                return render_template('admin/module_404.html'), 404

            db_module.settings = json.dumps(res)
            db_session.commit()

            current_module.db_module = db_module

            settings = None
            try:
                settings = json.loads(db_module.settings)
            except (TypeError, ValueError):
                pass
            current_module.load(settings=settings)

            SocketClientManager.send('module.update',
                                     {'module_id': db_module.id})

            return render_template('admin/configure_module.html',
                                   module=current_module)
        pass
    else:
        with DBManager.create_session_scope() as db_session:
            db_module = db_session.query(Module).filter_by(
                id=module_id).one_or_none()
            if db_module is None:
                return render_template('admin/module_404.html'), 404

            current_module.db_module = db_module

            settings = None
            try:
                settings = json.loads(db_module.settings)
            except (TypeError, ValueError):
                pass
            current_module.load(settings=settings)

            return render_template('admin/configure_module.html',
                                   module=current_module)
コード例 #6
0
ファイル: modules.py プロジェクト: alazymeme/pajbot
    def modules(**options) -> ResponseReturnValue:
        module_manager = ModuleManager(None).load(do_reload=False)
        with DBManager.create_session_scope() as db_session:
            for db_module in db_session.query(Module):
                module = find(lambda m: m.ID == db_module.id,
                              module_manager.all_modules)
                if module:
                    module.db_module = db_module

            return render_template("admin/modules.html",
                                   modules=module_manager.all_modules)
コード例 #7
0
def update_commands(signal_id):
    global bot_commands_list
    from pajbot.models.command import CommandManager
    bot_commands = CommandManager(
            socket_manager=None,
            module_manager=ModuleManager(None).load(),
            bot=None).load(load_examples=True)
    bot_commands_list = bot_commands.parse_for_web()

    bot_commands_list = sorted(bot_commands_list, key=lambda x: (x.id or -1, x.main_alias))
    del bot_commands
コード例 #8
0
    def update_commands(signal_id):
        log.debug('Updating commands...')
        from pajbot.models.command import CommandManager
        bot_commands = CommandManager(
            socket_manager=None,
            module_manager=ModuleManager(None).load(),
            bot=None).load(load_examples=True)
        app.bot_commands_list = bot_commands.parse_for_web()

        app.bot_commands_list.sort(key=lambda x: (x.id or -1, x.main_alias))
        del bot_commands
コード例 #9
0
    def commands(**options) -> ResponseReturnValue:
        from pajbot.models.module import ModuleManager

        bot_commands = pajbot.managers.command.CommandManager(
            socket_manager=None,
            module_manager=ModuleManager(None).load(),
            bot=None).load(enabled=None)

        bot_commands_list = bot_commands.parse_for_web()
        custom_commands = []
        point_commands = []
        moderator_commands = []

        for command in bot_commands_list:
            if command.id is None:
                continue
            if command.level > 100 or command.mod_only:
                moderator_commands.append(command)
            elif command.cost > 0:
                point_commands.append(command)
            else:
                custom_commands.append(command)

        with DBManager.create_session_scope() as db_session:
            commands_data = (db_session.query(CommandData).options(
                joinedload(CommandData.user),
                joinedload(CommandData.user2)).all())
            return render_template(
                "admin/commands.html",
                commands_data=commands_data,
                custom_commands=sorted(custom_commands,
                                       key=lambda f: f.command),
                point_commands=sorted(point_commands,
                                      key=lambda a: (a.cost, a.command)),
                moderator_commands=sorted(
                    moderator_commands,
                    key=lambda c:
                    (c.level if c.mod_only is False else 500, c.command)),
                created=session.pop("command_created_id", None),
                edited=session.pop("command_edited_id", None),
            )
コード例 #10
0
ファイル: utils.py プロジェクト: T-Brawl/pajbot
def get_cached_commands():
    CACHE_TIME = 30  # seconds

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

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

    return bot_commands_list
コード例 #11
0
ファイル: commands.py プロジェクト: wijayantoap/bullbot
    def post(self, **extra_args):
        args = pajbot.utils.remove_none_values(self.post_parser.parse_args())

        request_alias = args['alias'].lower()

        command_manager = pajbot.managers.command.CommandManager(
                socket_manager=None,
                module_manager=ModuleManager(None).load(),
                bot=None).load(enabled=None)

        command_aliases = []

        for alias, command in command_manager.items():
            command_aliases.append(alias)
            if command.command and len(command.command) > 0:
                command_aliases.extend(command.command.split('|'))

        command_aliases = set(command_aliases)

        if request_alias in command_aliases:
            return {'error': 'Alias already in use'}
        else:
            return {'success': 'good job'}
コード例 #12
0
ファイル: utils.py プロジェクト: alazymeme/pajbot
def get_cached_enabled_modules() -> Set[str]:
    CACHE_TIME = 30  # seconds
    CACHE_KEY = f"{StreamHelper.get_streamer()}:cache:enabled_modules"

    enabled_modules: Set[str] = set()

    redis = RedisManager.get()
    redis_enabled_modules = redis.get(CACHE_KEY)
    if redis_enabled_modules is not None:
        cached_enabled_modules = json.loads(redis_enabled_modules)
        if not isinstance(cached_enabled_modules, list):
            log.warning("Poorly cached module states")
            return enabled_modules
        return set(cached_enabled_modules)

    log.debug("Updating enabled modules...")
    module_manager = ModuleManager(None).load()
    for module in module_manager.modules:
        enabled_modules.add(module.ID)
    redis.setex(CACHE_KEY,
                value=json.dumps(list(enabled_modules)),
                time=CACHE_TIME)

    return enabled_modules
コード例 #13
0
ファイル: api.py プロジェクト: cubelious/pajbot
def command_checkalias(**options):
    if 'alias' not in request.form:
        return make_response(jsonify({'error': 'Missing `alias` parameter.'}), 400)

    request_alias = request.form['alias'].lower()

    command_manager = CommandManager(
            socket_manager=None,
            module_manager=ModuleManager(None).load(),
            bot=None).load(enabled=None)

    command_aliases = []

    for alias, command in command_manager.items():
        command_aliases.append(alias)
        if command.command and len(command.command) > 0:
            command_aliases.extend(command.command.split('|'))

    command_aliases = set(command_aliases)

    if request_alias in command_aliases:
        return make_response(jsonify({'error': 'Alias already in use'}))
    else:
        return make_response(jsonify({'success': 'good job'}))
コード例 #14
0
ファイル: bot.py プロジェクト: mikuski08/pajbot
    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})"
コード例 #15
0
ファイル: bot.py プロジェクト: damngamerz/bullbot
    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)
コード例 #16
0
def init(args):
    import subprocess
    import sys

    from flask import request
    from flask import session

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

    config = load_config(args.config)

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

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

    RedisManager.init(redis_options)

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

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

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

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

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

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

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

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

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

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

    SocketClientManager.init(app.streamer.login)

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

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

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

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

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

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

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

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

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

    version = VERSION
    last_commit = None

    if app.bot_dev:
        version = extend_version_if_possible(VERSION)

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

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

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

    @app.context_processor
    def inject_default_variables():
        return default_variables
コード例 #17
0
ファイル: __init__.py プロジェクト: sadlyfell/bullbot
def init(args):
    import configparser
    import logging
    import subprocess
    import sys

    from flask import request
    from flask import session
    from flask_scrypt import generate_random_salt

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

    log = logging.getLogger(__name__)

    config = configparser.ConfigParser()

    config = load_config(args.config)
    config.read("webconfig.ini")

    api_client_credentials = ClientCredentials(
        config["twitchapi"]["client_id"], config["twitchapi"]["client_secret"], config["twitchapi"]["redirect_uri"]
    )

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

    RedisManager.init(**redis_options)

    id_api = TwitchIDAPI(api_client_credentials)
    app_token_manager = AppAccessTokenManager(id_api, RedisManager.get())
    twitch_helix_api = TwitchHelixAPI(RedisManager.get(), app_token_manager)

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

    if "pleblist_password_salt" not in config["web"]:
        salt = generate_random_salt()
        config.set("web", "pleblist_password_salt", salt.decode("utf-8"))

    if "pleblist_password" not in config["web"]:
        salt = generate_random_salt()
        config.set("web", "pleblist_password", salt.decode("utf-8"))

    if "secret_key" not in config["web"]:
        salt = generate_random_salt()
        config.set("web", "secret_key", salt.decode("utf-8"))

    if "logo" not in config["web"]:
        try:
            download_logo(twitch_helix_api, config["main"]["streamer"])
            config.set("web", "logo", "set")
        except:
            log.exception("Error downloading logo")

    StreamHelper.init_web(config["main"]["streamer"])
    SocketClientManager.init(config["main"]["streamer"])

    with open(args.config, "w") as configfile:
        config.write(configfile)

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

    DBManager.init(config["main"]["db"])
    TimeManager.init_timezone(config["main"].get("timezone", "UTC"))

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

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

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

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

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

    version = extend_version_if_possible(VERSION)

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

    default_variables = {
        "version": version,
        "last_commit": last_commit,
        "bot": {"name": config["main"]["nickname"]},
        "site": {
            "domain": config["web"]["domain"],
            "deck_tab_images": config.getboolean("web", "deck_tab_images"),
            "websocket": {
                "host": config["websocket"].get("host", "wss://{}/clrsocket".format(config["web"]["domain"]))
            },
        },
        "streamer": {"name": config["web"]["streamer_name"], "full_name": config["main"]["streamer"]},
        "modules": app.bot_modules,
        "request": request,
        "session": session,
        "google_analytics": config["web"].get("google_analytics", None),
    }

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

    @app.context_processor
    def inject_default_variables():
        return default_variables
コード例 #18
0
    def commands_create(**options) -> ResponseReturnValue:
        session.pop("command_created_id", None)
        session.pop("command_edited_id", None)
        if request.method != "POST":
            return render_template("admin/create_command.html")

        if "aliases" not in request.form:
            abort(403)
        alias_str = request.form.get("aliases", "").replace("!", "").lower()
        delay_all = request.form.get("cd", Command.DEFAULT_CD_ALL)
        delay_user = request.form.get("usercd", Command.DEFAULT_CD_USER)
        level = request.form.get("level", Command.DEFAULT_LEVEL)
        cost = request.form.get("cost", 0)
        can_execute_with_whisper = request.form.get("whisperable",
                                                    "off") == "on"
        sub_only = request.form.get("subonly", "off") == "on"
        mod_only = request.form.get("modonly", "off") == "on"
        run_through_banphrases = request.form.get("checkmsg", "off") == "on"

        try:
            delay_all = int(delay_all)
            delay_user = int(delay_user)
            level = int(level)
            cost = int(cost)
        except ValueError:
            abort(403)

        if not alias_str:
            abort(403)
        if delay_all < 0 or delay_all > 9999:
            abort(403)
        if delay_user < 0 or delay_user > 9999:
            abort(403)
        if level < 0 or level > 2000:
            abort(403)
        if cost < 0 or cost > 9999999:
            abort(403)

        user = options.get("user", None)

        if user is None:
            abort(403)

        options = {
            "delay_all": delay_all,
            "delay_user": delay_user,
            "level": level,
            "cost": cost,
            "added_by": user.id,
            "can_execute_with_whisper": can_execute_with_whisper,
            "sub_only": sub_only,
            "mod_only": mod_only,
            "run_through_banphrases": run_through_banphrases,
        }

        valid_action_types = ["say", "me", "announce", "whisper", "reply"]
        action_type = request.form.get("reply", "say").lower()
        if action_type not in valid_action_types:
            abort(403)

        response = request.form.get("response", "")
        if not response:
            abort(403)

        action = {"type": action_type, "message": response}
        options["action"] = action

        command_manager = pajbot.managers.command.CommandManager(
            socket_manager=None,
            module_manager=ModuleManager(None).load(),
            bot=None).load(enabled=None)

        command_aliases_list = []

        for alias, command in command_manager.items():
            command_aliases_list.append(alias)
            if command.command and len(command.command) > 0:
                command_aliases_list.extend(command.command.split("|"))

        command_aliases = set(command_aliases_list)

        alias_str = alias_str.replace(" ", "").replace("!", "").lower()
        alias_list = alias_str.split("|")

        alias_list = [alias for alias in alias_list if len(alias) > 0]

        if not alias_list:
            return render_template("admin/create_command_fail.html")

        for alias in alias_list:
            if alias in command_aliases:
                return render_template("admin/create_command_fail.html")

        alias_str = "|".join(alias_list)

        command = Command(command=alias_str, **options)
        command.data = CommandData(command.id, **options)
        log_msg = f"The !{command.command.split('|')[0]} command has been created"
        AdminLogManager.add_entry("Command created", user, log_msg)
        with DBManager.create_session_scope(
                expire_on_commit=False) as db_session:
            db_session.add(command)
            db_session.add(command.data)
            db_session.commit()
            db_session.expunge(command)
            db_session.expunge(command.data)

        SocketClientManager.send("command.update", {"command_id": command.id})
        session["command_created_id"] = command.id
        return redirect("/admin/commands", 303)
コード例 #19
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
コード例 #20
0
def init(args):
    import configparser
    import logging
    import subprocess
    import sys

    from flask import request
    from flask import session
    from flask_scrypt import generate_random_salt

    import pajbot.utils
    import pajbot.web.common
    import pajbot.web.routes
    from pajbot.bot import Bot
    from pajbot.managers.db import DBManager
    from pajbot.managers.redis import RedisManager
    from pajbot.managers.time import TimeManager
    from pajbot.models.module import ModuleManager
    from pajbot.models.sock import SocketClientManager
    from pajbot.models.sock import SocketManager
    from pajbot.streamhelper import StreamHelper
    from pajbot.utils import load_config
    from pajbot.web.models import errors
    from pajbot.web.utils import download_logo

    log = logging.getLogger(__name__)

    config = configparser.ConfigParser()

    config = load_config(args.config)
    config.read("webconfig.ini")

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

    if "pleblist_password_salt" not in config["web"]:
        salt = generate_random_salt()
        config.set("web", "pleblist_password_salt", salt.decode("utf-8"))

    if "pleblist_password" not in config["web"]:
        salt = generate_random_salt()
        config.set("web", "pleblist_password", salt.decode("utf-8"))

    if "secret_key" not in config["web"]:
        salt = generate_random_salt()
        config.set("web", "secret_key", salt.decode("utf-8"))

    if "logo" not in config["web"]:
        res = download_logo(config["webtwitchapi"]["client_id"],
                            config["main"]["streamer"])
        if res:
            config.set("web", "logo", "set")

    StreamHelper.init_web(config["main"]["streamer"])
    SocketClientManager.init(config["main"]["streamer"])

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

    RedisManager.init(**redis_options)

    with open(args.config, "w") as configfile:
        config.write(configfile)

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

    DBManager.init(config["main"]["db"])
    TimeManager.init_timezone(config["main"].get("timezone", "UTC"))

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

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

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

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

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

    version = Bot.version
    last_commit = ""
    commit_number = 0
    try:
        current_branch = subprocess.check_output(
            ["git", "rev-parse", "--abbrev-ref",
             "HEAD"]).decode("utf8").strip()
        latest_commit = subprocess.check_output(["git", "rev-parse", "HEAD"
                                                 ]).decode("utf8").strip()[:8]
        commit_number = subprocess.check_output(
            ["git", "rev-list", "HEAD", "--count"]).decode("utf8").strip()
        last_commit = subprocess.check_output(
            ["git", "log", "-1", "--format=%cd"]).decode("utf8").strip()
        version = "{0} DEV ({1}, {2}, commit {3})".format(
            version, current_branch, latest_commit, commit_number)
    except:
        pass

    default_variables = {
        "version": version,
        "last_commit": last_commit,
        "commit_number": commit_number,
        "bot": {
            "name": config["main"]["nickname"]
        },
        "site": {
            "domain": config["web"]["domain"],
            "deck_tab_images": config.getboolean("web", "deck_tab_images"),
            "websocket": {
                "host":
                config["websocket"].get(
                    "host",
                    "wss://{}/clrsocket".format(config["web"]["domain"]))
            },
        },
        "streamer": {
            "name": config["web"]["streamer_name"],
            "full_name": config["main"]["streamer"]
        },
        "modules": app.bot_modules,
        "request": request,
        "session": session,
        "google_analytics": config["web"].get("google_analytics", None),
    }

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

    @app.context_processor
    def inject_default_variables():
        return default_variables
コード例 #21
0
ファイル: bot.py プロジェクト: sadlyfell/bullbot
    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,
        }
コード例 #22
0
    def __init__(self, config, args=None):
        self.load_config(config)
        self.last_ping = datetime.datetime.now()
        self.last_pong = datetime.datetime.now()

        self.load_default_phrases()

        self.db_session = DBManager.create_session()

        try:
            subprocess.check_call(
                ['alembic', 'upgrade', 'head'] +
                ['--tag="{0}"'.format(' '.join(sys.argv[1:]))])
        except subprocess.CalledProcessError:
            log.exception('aaaa')
            log.error(
                'Unable to call `alembic upgrade head`, this means the database could be out of date. Quitting.'
            )
            sys.exit(1)
        except PermissionError:
            log.error(
                'No permission to run `alembic upgrade head`. This means your user probably doesn\'t have execution rights on the `alembic` binary.'
            )
            log.error(
                'The error can also occur if it can\'t find `alembic` in your PATH, and instead tries to execute the alembic folder.'
            )
            sys.exit(1)
        except FileNotFoundError:
            log.error(
                'Could not found an installation of alembic. Please install alembic to continue.'
            )
            sys.exit(1)
        except:
            log.exception('Unhandled exception when calling db update')
            sys.exit(1)

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

        self.users = UserManager()
        self.decks = DeckManager().reload()
        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().reload()
        self.emotes = EmoteManager(self).reload()
        self.twitter_manager = TwitterManager(self).reload()
        self.duel_manager = DuelManager(self)

        HandlerManager.trigger('on_managers_loaded')

        # Reloadable managers
        self.reloadable = {
            'filters': self.filters,
            'kvi': self.kvi,
            'emotes': self.emotes,
            'twitter': self.twitter_manager,
            'decks': self.decks,
        }

        # Commitable managers
        self.commitable = {
            'commands': self.commands,
            'filters': self.filters,
            'kvi': self.kvi,
            'emotes': self.emotes,
            'twitter': self.twitter_manager,
            'decks': self.decks,
            'users': self.users,
            'banphrases': self.banphrase_manager,
        }

        self.execute_every(10 * 60, self.commit_all)
        self.execute_every(
            30, lambda: self.connection_manager.get_main_conn().ping(
                'tmi.twitch.tv'))

        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:
            self.users[self.admin].level = 2000

        self.parse_version()

        self.connection_manager = ConnectionManager(self.reactor,
                                                    self,
                                                    TMI.message_limit,
                                                    streamer=self.streamer)
        chub = self.config['main'].get('control_hub', None)
        if chub is not None:
            self.control_hub = ConnectionManager(self.reactor,
                                                 self,
                                                 TMI.message_limit,
                                                 streamer=chub,
                                                 backup_conns=1)
            log.info('start pls')
        else:
            self.control_hub = None

        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)

        self.twitchapi = TwitchAPI(twitch_client_id, twitch_oauth)

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

        self.whisper_manager = WhisperConnectionManager(
            self.reactor, self, self.streamer, TMI.whispers_message_limit,
            TMI.whispers_limit_interval)
        self.whisper_manager.start(accounts=[{
            'username':
            self.nickname,
            'oauth':
            self.password,
            'can_send_whispers':
            self.config.getboolean('main', 'add_self_as_whisper_account')
        }])

        self.ascii_timeout_duration = 120
        self.msg_length_timeout_duration = 120

        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.silent = True if args.silent else self.silent

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

        self.reconnection_interval = 5
        """
        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)
        """
        Update chatters every `update_chatters_interval' minutes.
        By default, this is set to run every 5 minutes.
        """
        self.execute_every(self.update_chatters_interval * 60,
                           self.action_queue.add,
                           (self.update_chatters_stage1, ))

        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)
コード例 #23
0
ファイル: __init__.py プロジェクト: T-Brawl/pajbot
def init(args):
    import configparser
    import datetime
    import logging
    import subprocess
    import sys

    from flask import request
    from flask import session
    from flask.ext.scrypt import generate_random_salt

    import pajbot.web.common
    import pajbot.web.routes
    from pajbot.bot import Bot
    from pajbot.managers.db import DBManager
    from pajbot.managers.redis import RedisManager
    from pajbot.managers.time import TimeManager
    from pajbot.models.module import ModuleManager
    from pajbot.models.sock import SocketClientManager
    from pajbot.streamhelper import StreamHelper
    from pajbot.tbutil import load_config
    from pajbot.web.models import errors
    from pajbot.web.utils import download_logo

    log = logging.getLogger(__name__)

    log.info('XD')

    config = configparser.ConfigParser()

    config = load_config(args.config)
    config.read('webconfig.ini')

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

    if 'pleblist_password_salt' not in config['web']:
        salt = generate_random_salt()
        config.set('web', 'pleblist_password_salt', salt.decode('utf-8'))

    if 'secret_key' not in config['web']:
        salt = generate_random_salt()
        config.set('web', 'secret_key', salt.decode('utf-8'))

    if 'logo' not in config['web']:
        res = download_logo(config['main']['streamer'])
        if res:
            config.set('web', 'logo', 'set')

    StreamHelper.init_web(config['main']['streamer'])

    redis_options = {}
    if 'redis' in config:
        redis_options = config._sections['redis']

    RedisManager.init(**redis_options)

    with open(args.config, 'w') as configfile:
        config.write(configfile)

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

    if 'sock' in config and 'sock_file' in config['sock']:
        SocketClientManager.init(config['sock']['sock_file'])

    DBManager.init(config['main']['db'])
    TimeManager.init_timezone(config['main'].get('timezone', 'UTC'))

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

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

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

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

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

    version = Bot.version
    last_commit = ''
    commit_number = 0
    try:
        current_branch = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).decode('utf8').strip()
        latest_commit = subprocess.check_output(['git', 'rev-parse', 'HEAD']).decode('utf8').strip()[:8]
        commit_number = subprocess.check_output(['git', 'rev-list', 'HEAD', '--count']).decode('utf8').strip()
        last_commit = subprocess.check_output(['git', 'log', '-1', '--format=%cd']).decode('utf8').strip()
        version = '{0} DEV ({1}, {2}, commit {3})'.format(version, current_branch, latest_commit, commit_number)
    except:
        pass

    default_variables = {
            'version': version,
            'last_commit': last_commit,
            'commit_number': commit_number,
            'bot': {
                'name': config['main']['nickname'],
                },
            'site': {
                'domain': config['web']['domain'],
                'deck_tab_images': config.getboolean('web', 'deck_tab_images'),
                'websocket': {
                    'host': config['websocket'].get('host', config['web']['domain']),
                    'port': config['websocket']['port'],
                    'ssl': config.getboolean('websocket', 'ssl')
                    }
                },
            'streamer': {
                'name': config['web']['streamer_name'],
                'full_name': config['main']['streamer']
                },
            'modules': app.bot_modules,
            'request': request,
            'session': session,
            'google_analytics': config['web'].get('google_analytics', None),
            }

    if 'streamtip' in config:
        default_variables['streamtip_data'] = {
                'client_id': config['streamtip']['client_id'],
                'redirect_uri': config['streamtip']['redirect_uri'],
                }
    else:
        default_variables['streamtip_data'] = {
                'client_id': 'MISSING',
                'redirect_uri': 'MISSING',
                }

    if 'twitchalerts' in config:
        default_variables['twitchalerts_data'] = {
                'client_id': config['twitchalerts']['client_id'],
                'redirect_uri': config['twitchalerts']['redirect_uri'],
                }
    else:
        default_variables['twitchalerts_data'] = {
                'client_id': 'MISSING',
                'redirect_uri': 'MISSING',
                }

    @app.context_processor
    def current_time():
        current_time = {}
        current_time['current_time'] = datetime.datetime.now()
        return current_time

    @app.context_processor
    def inject_default_variables():
        return default_variables
コード例 #24
0
    else:
        cnt = s.rfind(dsep)
    if cnt > 0:
        rhs = dsep + s[cnt + 1:]
        s = s[:cnt]
    else:
        rhs = ''

    splt = ''
    while s != '':
        splt = s[-3:] + tsep + splt
        s = s[:-3]

    return lhs + splt[:-1] + rhs

module_manager = ModuleManager(None).load()

nav_bar_header = []
nav_bar_header.append(('/', 'home', 'Home'))
nav_bar_header.append(('/commands/', 'commands', 'Commands'))
if 'deck' in module_manager:
    nav_bar_header.append(('/decks/', 'decks', 'Decks'))
if config['main']['nickname'] not in ['scamazbot']:
    nav_bar_header.append(('/points/', 'points', 'Points'))
nav_bar_header.append(('/stats/', 'stats', 'Stats'))
nav_bar_header.append(('/highlights/', 'highlights', 'Highlights'))
if 'pleblist' in modules:
    nav_bar_header.append(('/pleblist/history/', 'pleblist', 'Pleblist'))

nav_bar_admin_header = []
nav_bar_admin_header.append(('/', 'home', 'Home'))
コード例 #25
0
ファイル: modules.py プロジェクト: sgaweda/troybot
    def modules_edit(module_id, **options):
        module_manager = ModuleManager(None).load(do_reload=False)
        current_module = find(lambda m: m.ID == module_id,
                              module_manager.all_modules)

        user = options["user"]

        if user.level < current_module.CONFIGURE_LEVEL:
            return (
                render_template(
                    "errors/403.html",
                    extra_message=
                    "You do not have permission to configure this module."),
                403,
            )

        if current_module is None:
            return render_template("admin/module_404.html"), 404

        sub_modules = []
        for module in module_manager.all_modules:
            module.db_module = None

        with DBManager.create_session_scope() as db_session:
            for db_module in db_session.query(Module):
                module = find(lambda m: m.ID == db_module.id,
                              module_manager.all_modules)
                if module:
                    module.db_module = db_module
                    if module.PARENT_MODULE == current_module.__class__:
                        sub_modules.append(module)

            if current_module.db_module is None:
                return render_template("admin/module_404.html"), 404

            if request.method != "POST":
                settings = None
                try:
                    settings = json.loads(current_module.db_module.settings)
                except (TypeError, ValueError):
                    pass
                current_module.load(settings=settings)

                return render_template("admin/configure_module.html",
                                       module=current_module,
                                       sub_modules=sub_modules)

            form_values = {key: value for key, value in request.form.items()}
            res = current_module.parse_settings(**form_values)
            if res is False:
                return render_template("admin/module_404.html"), 404

            current_module.db_module.settings = json.dumps(res)
            db_session.commit()

            settings = None
            try:
                settings = json.loads(current_module.db_module.settings)
            except (TypeError, ValueError):
                pass
            current_module.load(settings=settings)

            payload = {"id": current_module.db_module.id}

            SocketClientManager.send("module.update", payload)

            AdminLogManager.post("Module edited", user, current_module.NAME)

            return render_template("admin/configure_module.html",
                                   module=current_module,
                                   sub_modules=sub_modules)
コード例 #26
0
ファイル: __init__.py プロジェクト: metrize/troybot
def init(args):
    import subprocess
    import sys

    from flask import request
    from flask import session
    from flask import g
    from flask_scrypt import generate_random_salt

    import pajbot.utils
    import pajbot.web.common
    import pajbot.web.routes

    from pajbot.managers.db import DBManager
    from pajbot.managers.redis import RedisManager
    from pajbot.managers.schedule import ScheduleManager
    from pajbot.managers.songrequest_queue_manager import SongRequestQueueManager
    from pajbot.models.module import ModuleManager
    from pajbot.models.sock import SocketClientManager
    from pajbot.streamhelper import StreamHelper
    from pajbot.utils import load_config
    from pajbot.web.models import errors
    from pajbot.web.utils import download_logo
    from pajbot.web.utils import download_sub_badge

    ScheduleManager.init()

    config = load_config(args.config)
    # ScheduleManager.init()
    api_client_credentials = ClientCredentials(
        config["twitchapi"]["client_id"], config["twitchapi"]["client_secret"], config["twitchapi"]["redirect_uri"]
    )

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

    RedisManager.init(**redis_options)

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

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

    if "secret_key" not in config["web"]:
        salt = generate_random_salt()
        config.set("web", "secret_key", salt.decode("utf-8"))

        with open(args.config, "w") as configfile:
            config.write(configfile)

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

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

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

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

    SocketClientManager.init(streamer)

    app.bot_modules = config["web"].get("modules", "").split()
    app.bot_commands_list = []
    app.bot_config = config
    app.secret_key = config["web"]["secret_key"]
    app.bot_dev = "flags" in config and "dev" in config["flags"] and config["flags"]["dev"] == "1"

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

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

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

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

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

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

    version = VERSION
    last_commit = None

    if app.bot_dev:
        version = extend_version_if_possible(VERSION)

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

    default_variables = {
        "version": version,
        "last_commit": last_commit,
        "bot": {"name": config["main"]["nickname"]},
        "site": {
            "domain": config["web"]["domain"],
            "deck_tab_images": config.getboolean("web", "deck_tab_images"),
            "websocket": {"host": config["websocket"].get("host", f"wss://{config['web']['domain']}/clrsocket")},
            "songrequestWS": {
                "host": config["songrequest-websocket"].get(
                    "host", f"wss://{config['web']['domain']}/songrequest_websocket"
                )
            },
        },
        "streamer": {"name": config["web"]["streamer_name"], "full_name": config["main"]["streamer"]},
        "modules": app.bot_modules,
        "request": request,
        "session": session,
        "google_analytics": config["web"].get("google_analytics", None),
    }

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

    @app.context_processor
    def inject_default_variables():
        return default_variables
コード例 #27
0
ファイル: admin.py プロジェクト: polle-vanhoof/pajbot
def commands_create(**options):
    session.pop('command_created_id', None)
    session.pop('command_edited_id', None)
    if request.method == 'POST':
        if 'aliases' not in request.form:
            abort(403)
        alias_str = request.form.get('aliases', '').replace('!', '').lower()
        delay_all = request.form.get('cd', Command.DEFAULT_CD_ALL)
        delay_user = request.form.get('usercd', Command.DEFAULT_CD_USER)
        level = request.form.get('level', Command.DEFAULT_LEVEL)
        cost = request.form.get('cost', 0)

        try:
            delay_all = int(delay_all)
            delay_user = int(delay_user)
            level = int(level)
            cost = int(cost)
        except ValueError:
            abort(403)

        if len(alias_str) == 0:
            abort(403)
        if delay_all < 0 or delay_all > 9999:
            abort(403)
        if delay_user < 0 or delay_user > 9999:
            abort(403)
        if level < 0 or level > 2000:
            abort(403)
        if cost < 0 or cost > 9999999:
            abort(403)

        options = {
            'delay_all': delay_all,
            'delay_user': delay_user,
            'level': level,
            'cost': cost,
        }

        valid_action_types = ['say', 'me', 'whisper', 'reply']
        action_type = request.form.get('reply', 'say').lower()
        if action_type not in valid_action_types:
            abort(403)

        response = request.form.get('response', '')
        if len(response) == 0:
            abort(403)

        action = {'type': action_type, 'message': response}
        options['action'] = action

        command_manager = CommandManager(
            socket_manager=None,
            module_manager=ModuleManager(None).load(),
            bot=None).load(enabled=None)

        command_aliases = []

        for alias, command in command_manager.items():
            command_aliases.append(alias)
            if command.command and len(command.command) > 0:
                command_aliases.extend(command.command.split('|'))

        command_aliases = set(command_aliases)

        alias_str = alias_str.replace(' ', '').replace('!', '').lower()
        alias_list = alias_str.split('|')

        alias_list = [alias for alias in alias_list if len(alias) > 0]

        if len(alias_list) == 0:
            return render_template('admin/create_command_fail.html')

        for alias in alias_list:
            if alias in command_aliases:
                return render_template('admin/create_command_fail.html')

        alias_str = '|'.join(alias_list)

        command = Command(command=alias_str, **options)
        command.data = CommandData(command.id)
        with DBManager.create_session_scope(
                expire_on_commit=False) as db_session:
            db_session.add(command)
            db_session.add(command.data)
            db_session.commit()
            db_session.expunge(command)
            db_session.expunge(command.data)

        SocketClientManager.send('command.update', {'command_id': command.id})
        session['command_created_id'] = command.id
        return redirect('/admin/commands/', 303)
    else:
        return render_template('admin/create_command.html')