Path: blob/master/bot/core/config_manager.py
1630 views
from importlib import import_module1from ast import literal_eval2from os import getenv34from bot import LOGGER567class Config:8AS_DOCUMENT = False9AUTHORIZED_CHATS = ""10BASE_URL = ""11BASE_URL_PORT = 8012BOT_TOKEN = ""13CMD_SUFFIX = ""14CLONE_DUMP_CHATS = ""15DATABASE_URL = ""16DATABASE_NAME = "mltb"17DEFAULT_UPLOAD = "rc"18EQUAL_SPLITS = False19EXCLUDED_EXTENSIONS = ""20INCLUDED_EXTENSIONS = ""21FFMPEG_CMDS = {}22FILELION_API = ""23FILES_LINKS = False24GDRIVE_ID = ""25INCOMPLETE_TASK_NOTIFIER = False26INDEX_URL = ""27IS_TEAM_DRIVE = False28JD_EMAIL = ""29JD_PASS = ""30LEECH_DUMP_CHAT = ""31LEECH_FILENAME_PREFIX = ""32LEECH_SPLIT_SIZE = 209715200033MEDIA_GROUP = False34HYBRID_LEECH = False35HYDRA_IP = ""36HYDRA_API_KEY = ""37NAME_SUBSTITUTE = r""38OWNER_ID = 039QUEUE_ALL = 040QUEUE_DOWNLOAD = 041QUEUE_UPLOAD = 042RCLONE_FLAGS = ""43RCLONE_PATH = ""44RCLONE_SERVE_URL = ""45RCLONE_SERVE_USER = ""46RCLONE_SERVE_PASS = ""47RCLONE_SERVE_PORT = 808048RSS_CHAT = ""49RSS_DELAY = 60050RSS_SIZE_LIMIT = 051SEARCH_API_LINK = ""52SEARCH_LIMIT = 053SEARCH_PLUGINS = []54STATUS_LIMIT = 455STATUS_UPDATE_INTERVAL = 1556STOP_DUPLICATE = False57STREAMWISH_API = ""58SUDO_USERS = ""59TELEGRAM_API = 060TELEGRAM_HASH = ""61TG_PROXY = {}62THUMBNAIL_LAYOUT = ""63TORRENT_TIMEOUT = 064UPLOAD_PATHS = {}65UPSTREAM_REPO = ""66UPSTREAM_BRANCH = "master"67USENET_SERVERS = []68USER_SESSION_STRING = ""69USER_TRANSMISSION = False70USE_SERVICE_ACCOUNTS = False71WEB_PINCODE = False72YT_DLP_OPTIONS = {}7374@classmethod75def _convert(cls, key: str, value):76if not hasattr(cls, key):77raise KeyError(f"{key} is not a valid configuration key.")7879expected_type = type(getattr(cls, key))8081if value is None:82return None8384if isinstance(value, expected_type):85return value8687if expected_type is bool:88return str(value).strip().lower() in {"true", "1", "yes"}8990if expected_type in [list, dict]:91if not isinstance(value, str):92raise TypeError(93f"{key} should be {expected_type.__name__}, got {type(value).__name__}"94)9596if not value:97return expected_type()9899try:100evaluated = literal_eval(value)101if not isinstance(evaluated, expected_type):102raise TypeError(103f"Expected {expected_type.__name__}, got {type(evaluated).__name__}"104)105return evaluated106except (ValueError, SyntaxError, TypeError) as e:107raise TypeError(108f"{key} should be {expected_type.__name__}, got invalid string: {value}"109) from e110111try:112return expected_type(value)113except (ValueError, TypeError) as exc:114raise TypeError(115f"Invalid type for {key}: expected {expected_type}, got {type(value)}"116) from exc117118@classmethod119def get(cls, key: str):120return getattr(cls, key, None)121122@classmethod123def set(cls, key: str, value) -> None:124if not hasattr(cls, key):125raise KeyError(f"{key} is not a valid configuration key.")126127converted_value = cls._convert(key, value)128setattr(cls, key, converted_value)129130@classmethod131def get_all(cls):132return {133key: getattr(cls, key)134for key in cls.__dict__.keys()135if not key.startswith("__") and not callable(getattr(cls, key))136}137138@classmethod139def _is_valid_config_attr(cls, attr: str) -> bool:140if attr.startswith("__") or callable(getattr(cls, attr, None)):141return False142return hasattr(cls, attr)143144@classmethod145def _process_config_value(cls, attr: str, value):146if not value:147return None148149converted_value = cls._convert(attr, value)150151if isinstance(converted_value, str):152converted_value = converted_value.strip()153154if attr == "DEFAULT_UPLOAD" and converted_value != "gd":155return "rc"156157if attr in {158"BASE_URL",159"RCLONE_SERVE_URL",160"SEARCH_API_LINK",161}:162return converted_value.strip("/") if converted_value else ""163164if attr == "USENET_SERVERS" and (165not converted_value or not converted_value[0].get("host")166):167return None168169return converted_value170171@classmethod172def _load_from_module(cls) -> bool:173try:174settings = import_module("config")175except ModuleNotFoundError:176return False177178for attr in dir(settings):179if not cls._is_valid_config_attr(attr):180continue181182raw_value = getattr(settings, attr)183processed_value = cls._process_config_value(attr, raw_value)184185if processed_value is not None:186setattr(cls, attr, processed_value)187188return True189190@classmethod191def _load_from_env(cls) -> None:192for attr in dir(cls):193if not cls._is_valid_config_attr(attr):194continue195196env_value = getenv(attr)197if env_value is None:198continue199200processed_value = cls._process_config_value(attr, env_value)201if processed_value is not None:202setattr(cls, attr, processed_value)203204@classmethod205def _validate_required_config(cls) -> None:206required_keys = ["BOT_TOKEN", "OWNER_ID", "TELEGRAM_API", "TELEGRAM_HASH"]207208for key in required_keys:209value = getattr(cls, key)210if isinstance(value, str):211value = value.strip()212if not value:213raise ValueError(f"{key} variable is missing!")214215@classmethod216def load(cls) -> None:217if not cls._load_from_module():218LOGGER.info(219"Config module not found, loading from environment variables..."220)221cls._load_from_env()222223cls._validate_required_config()224225@classmethod226def load_dict(cls, config_dict) -> None:227for key, value in config_dict.items():228if not hasattr(cls, key):229continue230231processed_value = cls._process_config_value(key, value)232233if key == "USENET_SERVERS" and processed_value is None:234processed_value = []235236if processed_value is not None:237setattr(cls, key, processed_value)238239cls._validate_required_config()240241242