Пример #1
0
async def blacklist_user(event):
    user, reason = await get_user_and_text(event)
    if not reason:
        await event.reply("You can't blacklist user without a reason blyat!")
        return
    try:
        await ban_user(event, user['user_id'], event.chat_id, None)
    except Exception as err:
        await event.reply(err)
        logger.error(err)
        return
    old = mongodb.blacklisted_users.find_one({'user': user['user_id']})
    if old:
        new = {
            'user': user['user_id'],
            'date': old['date'],
            'by': old['by'],
            'reason': reason
        }
        mongodb.blacklisted_users.update_one({'_id': old['_id']}, {"$set": new}, upsert=False)
        await event.reply("This user already blacklisted! I'll update the reason.")
        return
    date = strftime("%Y-%m-%d %H:%M:%S", gmtime())
    new = {
        'user': user['user_id'],
        'date': date,
        'reason': reason,
        'by': event.from_id
    }
    user_id = user['user_id']
    logger.info(f'user {user_id} gbanned by {event.from_id}')
    mongodb.blacklisted_users.insert_one(new)
    await event.reply("Sudo {} blacklisted {}.\nDate: `{}`\nReason: `{}`".format(
        await user_link(event.from_id), await user_link(user['user_id']), date, reason))
Пример #2
0
async def un_blacklist_user(event):
    chat_id = event.chat_id
    user = await get_user(event)
    try:
        await unban_user(event, user['user_id'], chat_id)
    except Exception as err:
        await event.reply(err)
        logger.error(err)
    old = mongodb.blacklisted_users.find_one({'user': user['user_id']})
    if not old:
        await event.reply("This user isn't blacklisted!")
        return
    user_id = user['user_id']
    logger.info(f'user {user_id} ungbanned by {event.from_id}')
    mongodb.blacklisted_users.delete_one({'_id': old['_id']})
    await event.reply("Sudo {} unblacklisted {}.".format(
        await user_link(event.from_id), await user_link(user_id)))
Пример #3
0
async def un_blacklist_user(event):
    chat_id = event.chat_id
    user = await get_user(event, send_text=False)

    probably_id = event.pattern_match.group(1).split(" ")[0]

    if user:
        user_id = int(user['user_id'])
    if not user and probably_id.isdigit():
        user_id = int(probably_id)

    try:
        unbanned_rights = ChatBannedRights(
            until_date=None,
            view_messages=False,
            send_messages=False,
            send_media=False,
            send_stickers=False,
            send_gifs=False,
            send_games=False,
            send_inline=False,
            embed_links=False,
        )

        precheck = mongodb.gbanned_groups.find({'user': user})
        if precheck:
            chats = mongodb.gbanned_groups.find({'user': user})
        else:
            chats = chat_id
        for chat in chats:
            await event.client(
                EditBannedRequest(chat['chat'], user_id, unbanned_rights))

    except Exception as err:
        logger.error(str(err))
    old = mongodb.blacklisted_users.find_one({'user': user_id})
    if not old:
        await event.reply("This user isn't blacklisted!")
        return
    logger.info(f'user {user_id} ungbanned by {event.from_id}')
    mongodb.blacklisted_users.delete_one({'_id': old['_id']})
    await event.reply("Sudo {} unblacklisted {}.".format(
        await user_link(event.from_id), await user_link(user_id)))
Пример #4
0
async def gban_helper_2(event, strings):
    if event.user_joined is True or event.user_added is True:
        await asyncio.sleep(
            2)  # Sleep 2 seconds before check user to allow Simon gban user
        if hasattr(event.action_message.action, 'users'):
            from_id = event.action_message.action.users[0]
        else:
            from_id = event.action_message.from_id

        K = mongodb.blacklisted_users.find_one({'user': from_id})
        if not K:
            return

        banned_rights = ChatBannedRights(
            until_date=None,
            view_messages=True,
            send_messages=True,
            send_media=True,
            send_stickers=True,
            send_gifs=True,
            send_games=True,
            send_inline=True,
            embed_links=True,
        )

        try:
            ban = await event.client(
                EditBannedRequest(event.chat_id, from_id, banned_rights))

            if ban:
                mongodb.gbanned_groups.insert_one({
                    'user': from_id,
                    'chat': event.chat_id
                })
                msg = await event.reply(strings['user_is_blacklisted'].format(
                    user=await user_link(from_id), rsn=K['reason']))
                await asyncio.sleep(5)
                await event.client.delete_messages(event.chat_id, msg)

        except Exception as err:
            logger.info(
                f'Error on gbanning {from_id} in {event.chat_id} \n {err}')
            pass
Пример #5
0
def exit_gracefully(signum, frame):
    logger.info("Bye!")
    try:
        redis.bgsave()
    except Exception:
        logger.info("Redis error, exiting immediately!")
    logger.info("----------------------")
    os.kill(os.getpid(), signal.SIGUSR1)
Пример #6
0
def exit_gracefully(signum, frame):
    logger.info("Bye!")
    try:
        redis.bgsave()
    except Exception as err:
        logger.info("Redis error, exiting immediately!")
        logger.error(err)
        exit(1)
    logger.info("----------------------")
    sys.exit(1)
Пример #7
0
def exit_gracefully(signum, frame):
    logger.info("Bye!")

    try:
        loop.create_task(bot.close())
        loop.create_task(tbot.disconnect())
        loop.create_task(dp.storage.close())
        redis.save()
    except Exception:
        logger.info("Exiting immediately!")
    logger.info("----------------------")
    os.kill(os.getpid(), signal.SIGUSR1)
Пример #8
0
def update_devices():
    logger.info("Update info about OrangeFox builds..")
    global DEVICES_STABLE
    global DEVICES_BETA

    ftp = FTP(ftp_url, CONFIG['advanced']['ofox_ftp_user'], CONFIG['advanced']['ofox_ftp_pass'])

    data = ftp.mlsd("OrangeFox-Stable", ["type"])
    for device, facts in data:
        if not facts["type"] == "dir":
            continue

        info_file = []
        ftp.retrlines(f'RETR OrangeFox-Stable/{device}/device_info.txt', info_file.append)

        codename = info_file[0].split(': ')[1]
        fullname = info_file[1].split(': ')[1]
        maintainer = info_file[2].split(': ')[1]

        builds = list(ftp.mlsd("OrangeFox-Stable/" + device, ["type"]))
        builds.sort(key=lambda entry: entry[1]['modify'], reverse=True)
        for build, facts in builds:
            if not facts["type"] == "file":
                continue
            if build == "device_info.txt":
                continue
            if build == "README.md":
                continue
            last_build = build
            modified = facts['modify']
            break

        DEVICES_STABLE[device] = {
            "codename": codename,
            "fullname": fullname,
            "maintainer": maintainer,
            "ver": last_build,
            "modified": modified
        }

    data = ftp.mlsd("OrangeFox Beta", ["type"])
    for device, facts in data:
        if not facts["type"] == "dir":
            continue

        info_file = []
        ftp.retrlines(f'RETR OrangeFox Beta/{device}/device_info.txt', info_file.append)

        codename = info_file[0].split(': ')[1]
        fullname = info_file[1].split(': ')[1]
        maintainer = info_file[2].split(': ')[1]

        builds = list(ftp.mlsd("OrangeFox Beta/" + device, ["type"]))
        builds.sort(key=lambda entry: entry[1]['modify'], reverse=True)
        for build, facts in builds:
            if not facts["type"] == "file":
                continue
            if build == "device_info.txt":
                continue
            if build == "README.md":
                continue
            last_build = build
            modified = facts['modify']
            break

        DEVICES_BETA[device] = {
            "codename": codename,
            "fullname": fullname,
            "maintainer": maintainer,
            "ver": last_build,
            "modified": modified
        }
    logger.info("Done!")
Пример #9
0
import asyncio
import signal

from importlib import import_module

from sophie_bot import CONFIG, bot, redis, logger
from sophie_bot.modules import ALL_MODULES

LOAD_COMPONENTS = CONFIG["advanced"]["load_components"]

# Import modules
for module_name in ALL_MODULES:
    logger.debug("Importing " + module_name)
    imported_module = import_module("sophie_bot.modules." + module_name)

logger.info("Modules loaded!")

if LOAD_COMPONENTS is True:
    from sophie_bot.modules.components import ALL_COMPONENTS

    for module_name in ALL_COMPONENTS:
        logger.debug("Importing " + module_name)
        imported_module = import_module("sophie_bot.modules.components." +
                                        module_name)

    logger.info("Components loaded!")
else:
    logger.info("Components disabled!")

# Catch up missed updates
if CONFIG["advanced"]["catch_up"] is True:
Пример #10
0
import glob
import os.path

from sophie_bot import logger
from sophie_bot.config import get_config_key

NO_LOAD_COMPONENTS = get_config_key("not_load_this_components")


def list_all_components():
    components = []
    mod_paths = glob.glob(os.path.dirname(__file__) + "/*.py")
    all_components = [
        os.path.basename(f)[:-3] for f in mod_paths if os.path.isfile(f)
        and f.endswith(".py") and not f.endswith("__init__.py")
    ]
    for component in all_components:
        if component not in NO_LOAD_COMPONENTS:
            components.append(component)

    return components


ALL_COMPONENTS = sorted(list(list_all_components()))

print(ALL_COMPONENTS)

logger.info("Components to load: %s", str(ALL_COMPONENTS))
__all__ = ALL_COMPONENTS + ["ALL_COMPONENTS"]
Пример #11
0
async def blacklist_user(event):
    user, reason = await get_user_and_text(event, send_text=False)

    probably_id = event.pattern_match.group(1).split()[0]

    if user:
        user_id = int(user['user_id'])
    if not user and probably_id.isdigit():
        probably_reason = event.pattern_match.group(1).split()[1]

        user_id = int(probably_id)
        reason = probably_reason

    if user_id in WHITELISTED:
        await event.reply("You can't blacklist a Whitelisted user")
        return

    if not reason:
        await event.reply("You can't blacklist user without a reason blyat!")
        return

    try:
        banned_rights = ChatBannedRights(
            until_date=None,
            view_messages=True,
            send_messages=True,
            send_media=True,
            send_stickers=True,
            send_gifs=True,
            send_games=True,
            send_inline=True,
            embed_links=True,
        )

        await event.client(
            EditBannedRequest(event.chat_id, user_id, banned_rights))

    except Exception as err:
        logger.error(str(err))
        await event.reply(str(err))

    old = mongodb.blacklisted_users.find_one({'user': user_id})
    if old:
        new = {
            'user': user_id,
            'date': old['date'],
            'by': old['by'],
            'reason': reason
        }
        mongodb.blacklisted_users.update_one({'_id': old['_id']},
                                             {"$set": new},
                                             upsert=False)
        await event.reply(
            "This user already blacklisted! I'll update the reason.")
        return
    date = strftime("%Y-%m-%d %H:%M:%S", gmtime())
    new = {
        'user': user_id,
        'date': date,
        'reason': reason,
        'by': event.from_id
    }
    logger.info(f'user {user_id} gbanned by {event.from_id}')
    mongodb.blacklisted_users.insert_one(new)
    await event.reply(
        "Sudo {} blacklisted {}.\nDate: `{}`\nReason: `{}`".format(
            await user_link(event.from_id), await user_link(user_id), date,
            reason))
Пример #12
0
async def update_devices(event):
    if event.chat_id not in fox_dev_chats:
        return

    logger.info("Update info about OrangeFox builds..")
    global DEVICES_STABLE
    global DEVICES_BETA

    DEVICES_STABLE = {}
    DEVICES_BETA = {}
    if os.path.exists("update.json"):
        f = open("update.json", "r")
        jfile = ujson.load(f)
        old_beta = jfile['beta']
        old_stable = jfile['stable']
    else:
        await event.reply("update.json didn't found in the bot directory, regenerating...")
        old_beta = []
        old_stable = []

    released_stable = ""
    released_beta = ""

    ftp = FTP(ftp_url, CONFIG['advanced']['ofox_ftp_user'], CONFIG['advanced']['ofox_ftp_pass'])

    Omsg = await event.reply("Updating Stable devices..")
    data = ftp.mlsd("OrangeFox-Stable", ["type"])
    for device, facts in data:
        await asyncio.sleep(0.5)
        if not facts["type"] == "dir":
            continue

        info_file = []
        ftp.retrlines(f'RETR OrangeFox-Stable/{device}/device_info.txt', info_file.append)

        codename = info_file[0].split(': ')[1].lower()
        fullname = info_file[1].split(': ')[1]
        maintainer = info_file[2].split(': ')[1]
        msg = ""
        if len(info_file) >= 4:
            msg = info_file[3].split(': ')[1]

        builds = list(ftp.mlsd("OrangeFox-Stable/" + device, ["type"]))
        builds.sort(key=lambda entry: entry[1]['modify'], reverse=True)
        readme = None
        done = 0
        for build, facts in builds:
            logger.debug(build)
            if not facts["type"] == "file":
                continue
            elif build == "README.md":
                readme = "README.md"
                continue

            ext = os.path.splitext(build)[1]
            if ext == '.zip' and done == 0:
                last_build = build
                modified = facts['modify']
                done = 1

        mm = list(ftp.mlsd(f"OrangeFox-Stable/{device}/{last_build[:-4]}.txt"))
        if mm:
            handle = open("changelog.txt", 'wb')
            ftp.retrbinary(f'RETR OrangeFox-Stable/{device}/{last_build[:-4]}.txt', handle.write)
            handle.close()
            handle = open("changelog.txt", 'rU')
            changelog = handle.read()
            handle.close()
        else:
            changelog = None

        DEVICES_STABLE[codename] = {
            "codename": codename,
            "fullname": fullname,
            "maintainer": maintainer,
            "ver": last_build,
            "modified": modified,
            "readme": readme,
            "msg": msg,
            "changelog": changelog
        }

        # Check on update
        if codename not in old_stable or int(modified) > int(old_stable[codename]['modified']):
            released_stable += f"{codename} "
            logger.info(f'Stable - new update of {codename} detected.')
            link = 'https://files.orangefox.website/OrangeFox-Stable/' + device + "/" + last_build

            await tbot.send_message(
                STABLE_CHANNEL,
                NEW_STABLE_TEXT.format_map(DEVICES_STABLE[codename]),
                buttons=[[custom.Button.url(
                    "⬇️ Download this build", link
                )]],
                link_preview=False
            )

    await Omsg.edit("Updating Beta devices..")
    data = ftp.mlsd("OrangeFox-Beta", ["type"])
    for device, facts in data:
        await asyncio.sleep(0.2)
        if not facts["type"] == "dir":
            continue

        info_file = []
        ftp.retrlines(f'RETR OrangeFox-Beta/{device}/device_info.txt', info_file.append)

        codename = info_file[0].split(': ')[1].lower()
        fullname = info_file[1].split(': ')[1]
        maintainer = info_file[2].split(': ')[1]
        msg = None
        if len(info_file) >= 4:
            msg = info_file[3].split(': ')[1]

        builds = list(ftp.mlsd("OrangeFox-Beta/" + device, ["type"]))
        builds.sort(key=lambda entry: entry[1]['modify'], reverse=True)
        readme = None
        done = 0
        for build, facts in builds:
            logger.debug(build)
            if not facts["type"] == "file":
                continue
            elif build == "README.md":
                readme = "README.md"
                continue

            ext = os.path.splitext(build)[1]
            if ext == '.zip' and done == 0:
                last_build = build
                modified = facts['modify']
                done = 1

        mm = list(ftp.mlsd(f"OrangeFox-Beta/{device}/{last_build[:-4]}.txt"))
        if mm:
            handle = open("changelog.txt", 'wb')
            ftp.retrbinary(f'RETR OrangeFox-Beta/{device}/{last_build[:-4]}.txt', handle.write)
            handle.close()
            handle = open("changelog.txt", 'rU')
            changelog = handle.read()
            handle.close()
        else:
            changelog = None

        DEVICES_BETA[codename] = {
            "codename": codename,
            "fullname": fullname,
            "maintainer": maintainer,
            "ver": last_build,
            "modified": modified,
            "readme": readme,
            "msg": msg,
            "changelog": changelog
        }

        # Check on update
        if codename not in old_beta or int(modified) > int(old_beta[codename]['modified']):
            released_beta += f"{codename} "
            logger.info(f'BETA - new update of {codename} detected.')
            link = 'https://files.orangefox.website/OrangeFox-Beta/' + device + "/" + last_build

            await tbot.send_message(
                BETA_CHANNEL,
                NEW_BETA_TEXT.format_map(DEVICES_BETA[codename]),
                buttons=[[custom.Button.url(
                    "⬇️ Download this Beta", link
                )]],
                link_preview=False
            )

    date = strftime("%Y-%m-%d %H:%M:%S", gmtime())

    JSON_FILE = {
        'stable': DEVICES_STABLE,
        'beta': DEVICES_BETA,
        'json_file_info': {"ver": 4, "generated_date": date}
    }
    f = open("update.json", "w+")

    ujson.dump(JSON_FILE, f, indent=1)
    f.close()
    with open('update.json', 'rb') as f:
        ftp.storbinary('STOR %s' % 'Others/update.json', f)

    ftp.quit()

    text = "Done!\n"
    if released_stable:
        text += f"Stable updates released:\n{released_stable}\n"
    if released_beta:
        text += f"Beta updates released:\n{released_beta}"

    await Omsg.edit(text)

    logger.info(text)
import csv
from time import gmtime, strftime

from sophie_bot import mongodb, logger

f = open("owo.csv")
reader = csv.DictReader(f, delimiter=',')
F = 0
for row in reader:
    F += 1
    if not F >= 12900:
        continue
    user_id = row["id"]
    reason = row["reason"]
    logger.info(f"{F} - Gbanning " + user_id)
    date = strftime("%Y-%m-%d %H:%M:%S", gmtime())
    new = {
        'user': user_id,
        'date': date,
        'by': "SophieBot import module",
        'reason': reason
    }
    old = mongodb.blacklisted_users.find_one({'user': user_id})
    if old:
        logger.info(f"User {user_id} already gbanned, ill update the reason")
        mongodb.blacklisted_users.update_one({'_id': old['_id']}, {"$set": new}, upsert=False)
    else:
        mongodb.blacklisted_users.insert_one(new)
        logger.info(f"User {user_id} gbanned!")
Пример #14
0
# Copyright (C) 2018 - 2019 MrYacha
#
# This file is part of SophieBot.
#
# SophieBot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Licensed under the Raphielscape Public License, Version 1.c (the "License");
# you may not use this file except in compliance with the License.

from sophie_bot import logger


def list_all_modules():
    from os.path import dirname, basename, isfile
    import glob

    mod_paths = glob.glob(dirname(__file__) + "/*.py")
    all_modules = [
        basename(f)[:-3]
        for f in mod_paths
        if isfile(f) and f.endswith(".py") and not f.endswith("__init__.py")
    ]
    return all_modules


ALL_MODULES = sorted(list_all_modules())
logger.info("Modules to load: %s", str(ALL_MODULES))
__all__ = ALL_MODULES + ["ALL_MODULES"]
from sophie_bot import mongodb, logger

f = open("owo.txt").read()
F = 0
L = round(sum(1 for line in open("owo.txt")) / 2)


oof = re.findall("\[x\] ?(.+) - (\d+)\nReason: (.*)", f, re.MULTILINE)
for user in oof:
    F += 1
    name = user[0]
    user_id = user[1]
    reason = user[2]

    logger.info(f"{F}/~{L} - Gbanning {name} - {user_id}")

    date = strftime("%Y-%m-%d %H:%M:%S", gmtime())
    new = {
        'user': user_id,
        'date': date,
        'by': "SophieBot import module",
        'reason': reason
    }
    old = mongodb.blacklisted_users.find_one({'user': user_id})
    if old:
        logger.info(f"User {user_id} already gbanned, ill update the reason")
        mongodb.blacklisted_users.update_one({'_id': old['_id']}, {"$set": new}, upsert=False)
    else:
        mongodb.blacklisted_users.insert_one(new)
        logger.info(f"User {user_id} gbanned!")
Пример #16
0
            continue
        text = BeautifulSoup(raw.text, 'html.parser')
        codename = re.search(r"Codename: (.*)", str(text)).group(1)
        fullname = re.search(r"Device name: (.*)", str(text)).group(1)
        maintainer = re.search(r"Maintainer: (.*)", str(text)).group(1)

        DEVICES_BETA[device] = {
            "codename": codename,
            "fullname": fullname,
            "maintainer": maintainer,
            "ver": builds.group()
        }


# Main
logger.info("Update info about OrangeFox builds..")
update_devices()
logger.info("Done!")
print(DEVICES_STABLE)
print(DEVICES_BETA)


@decorator.command("listbeta")
@flood_limit_dec("listbeta")
async def listbeta(event):
    if event.chat_id not in fox_groups:
        return
    text = "**Supported beta devices:**\n"
    for device in DEVICES_BETA:
        text += "* {} (`{}`)\n".format(
            DEVICES_BETA[device]['fullname'], DEVICES_BETA[device]["codename"])
Пример #17
0
from telethon import custom
from telethon.tl.custom import Button

from sophie_bot import decorator, logger, mongodb
from sophie_bot.modules.helper_func.flood import flood_limit_dec
from sophie_bot.modules.language import (LANGUAGES, get_chat_lang, get_string,
                                         lang_info)

# Generate help cache
HELP = []
for module in LANGUAGES['en']['HELPS']:
    logger.debug("Loading help for " + module)
    HELP.append(module)
HELP = sorted(HELP)
logger.info("Help loaded for: {}".format(HELP))


@decorator.t_command('start')
@flood_limit_dec("start")
async def start(event):
    if not event.from_id == event.chat_id:
        await event.reply('Hey there, My name is Sophie!')
        return
    text, buttons = get_start(event)
    await event.reply(text, buttons=buttons)


@decorator.t_command('help')
@flood_limit_dec("help")
async def help(event):
Пример #18
0
# import uvloop


LOAD_COMPONENTS = get_config_key("load_components")
CATCH_UP = get_config_key("skip_catch_up")

LOADED_MODULES = []

# Import modules
for module_name in ALL_MODULES:
    logger.debug("Importing " + module_name)
    imported_module = import_module("sophie_bot.modules." + module_name)
    LOADED_MODULES.append(imported_module)

logger.info("Modules loaded!")

if LOAD_COMPONENTS is True:
    from sophie_bot.modules.components import ALL_COMPONENTS

    for module_name in ALL_COMPONENTS:
        logger.debug("Importing " + module_name)
        imported_module = import_module("sophie_bot.modules.components." + module_name)
        LOADED_MODULES.append(imported_module)

    logger.info("Components loaded!")
else:
    logger.info("Components disabled!")


# Asyncio magic
Пример #19
0
async def startup():
    logger.info("Aiogram: Using polling method")
    loop.create_task(dp.start_polling())
Пример #20
0
async def start():
    logger.info("Running webserver..")
    config = hypercorn.Config()
    config.bind = ["localhost:8083"]
    await hypercorn.asyncio.serve(quart, config)
Пример #21
0
# lang = yaml.load(f, Loader=yaml.CLoader)
# LANGUAGES[lang['language_info']['code']] = lang
# LANGS.append(lang['language_info']['code'])

for filename in os.listdir('sophie_bot/modules/langs'):
    logger.debug("Loading language file " + filename)
    f = open('sophie_bot/modules/langs/' + filename, "r")
    lang = yaml.load(f, Loader=yaml.CLoader)

    lang_code = lang['language_info']['code']
    LANGS.append(lang_code)
    LANGUAGES[lang_code] = lang

LANGS.sort()

logger.info("Languages loaded: {}".format(LANGS))


@decorator.t_command("lang")
async def lang(event):
    if event.chat_id == event.from_id:
        pm = True
    else:
        pm = False

    K = await is_user_admin(event.chat_id, event.from_id)
    if K is False:
        await event.reply("You don't have rights to set language here!")
        return

    text, buttons = lang_info(event.chat_id, pm=pm)
Пример #22
0
from aiogram import executor

LOAD_COMPONENTS = CONFIG["advanced"]["load_components"]
CATCH_UP = CONFIG["advanced"]["skip_catch_up"]

LOADED_MODULES = []

loop = asyncio.get_event_loop()

# Import modules
for module_name in ALL_MODULES:
    logger.debug("Importing " + module_name)
    imported_module = import_module("sophie_bot.modules." + module_name)
    LOADED_MODULES.append(imported_module)

logger.info("Modules loaded!")

if LOAD_COMPONENTS is True:
    from sophie_bot.modules.components import ALL_COMPONENTS

    for module_name in ALL_COMPONENTS:
        logger.debug("Importing " + module_name)
        imported_module = import_module("sophie_bot.modules.components." +
                                        module_name)
        LOADED_MODULES.append(imported_module)

    logger.info("Components loaded!")
else:
    logger.info("Components disabled!")

# Catch up missed updates