# ╔══════════════════════════════════════════════════════════════════╗ # ║ ║ # ║ +-+-+-+-+-+-+-+-+ ║ # ║ |H|e|x|a|H|o|s|t| ║ # ║ +-+-+-+-+-+-+-+-+ ║ # ║ ║ # ║ © 2026 HexaHost — All Rights Reserved ║ # ║ ║ # ║ discord ── https://discord.gg/hexahost ║ # ║ github ── https://github.com/theoneandonlymace ║ # ║ ║ # ╚══════════════════════════════════════════════════════════════════╝ import os from dotenv import load_dotenv load_dotenv() TOKEN = os.environ.get("TOKEN") BRAND_NAME = os.environ.get("brand_name", "Axiom") NAME = BRAND_NAME BotName = BRAND_NAME server = "https://discord.gg/hexahost" serverLink = "https://discord.gg/hexahost" # ── Security / feature toggles ──────────────────────────────────────────────── def _env_bool(key: str, default: bool = False) -> bool: raw = os.getenv(key, str(default)).strip().lower() return raw in ("1", "true", "yes", "on") JISHAKU_ENABLED = _env_bool("JISHAKU_ENABLED", False) API_ENABLED = _env_bool("API_ENABLED", False) TUNNEL_ENABLED = _env_bool("TUNNEL_ENABLED", False) TUNNEL_ALLOW_BINARY_DOWNLOAD = _env_bool("TUNNEL_ALLOW_BINARY_DOWNLOAD", False) API_HOST = os.getenv("API_HOST", "127.0.0.1").strip() or "127.0.0.1" API_PORT = int(os.getenv("API_PORT", "8000")) # ── Webhooks (only active when explicitly configured) ───────────────────────── def _valid_webhook_url(url: str | None) -> str | None: if not url: return None url = url.strip() if not url or url == "https://discord.com/api/webhooks/": return None if "discord.com/api/webhooks/" not in url and "discordapp.com/api/webhooks/" not in url: return None return url CMD_WEBHOOK_URL = _valid_webhook_url(os.getenv("CMD_WEBHOOK_URL")) # ── Optional Discord log / stats channels (unset = disabled) ────────────────── def _parse_optional_id(env_key: str) -> int | None: raw = os.getenv(env_key, "").strip() if not raw or not raw.isdigit(): return None return int(raw) LOG_CHANNEL_ID = _parse_optional_id("LOG_CHANNEL_ID") SERVER_COUNT_CHANNEL_ID = _parse_optional_id("SERVER_COUNT_CHANNEL_ID") USER_COUNT_CHANNEL_ID = _parse_optional_id("USER_COUNT_CHANNEL_ID") # ── Owner / Staff IDs ───────────────────────────────────────────────────────── # REQUIRED: set OWNER_IDS in .env — no hardcoded fallback IDs. def _parse_ids(env_key: str) -> list[int]: raw = os.getenv(env_key, "").strip() if not raw: return [] return [int(p.strip()) for p in raw.split(",") if p.strip().isdigit()] OWNER_IDS: list[int] = _parse_ids("OWNER_IDS") OWNER_IDS_STR: list[str] = [str(i) for i in OWNER_IDS] # Discord application / OAuth client id (same as dashboard DISCORD_CLIENT_ID) DISCORD_CLIENT_ID = os.getenv("DISCORD_CLIENT_ID", "").strip() # ── Discord sharding ────────────────────────────────────────────────────────── # SHARD_COUNT empty = AutoShardedBot asks Discord for recommended count (in-process). # SHARD_IDS (e.g. "0,1") + SHARD_COUNT = this process only runs those shards (cluster). # Primary process runs API / slash sync / emoji sync / stats (shard 0 or override). def _parse_optional_int(env_key: str) -> int | None: raw = os.getenv(env_key, "").strip() if not raw or not raw.isdigit(): return None return int(raw) SHARD_COUNT: int | None = _parse_optional_int("SHARD_COUNT") SHARD_IDS: list[int] = _parse_ids("SHARD_IDS") def get_shard_kwargs() -> dict: """Kwargs for AutoShardedBot.__init__ (omit keys for full auto-sharding).""" kwargs: dict = {} if SHARD_COUNT is not None: kwargs["shard_count"] = SHARD_COUNT if SHARD_IDS: if SHARD_COUNT is None: raise ValueError("SHARD_IDS requires SHARD_COUNT to be set") kwargs["shard_ids"] = SHARD_IDS kwargs["shard_count"] = SHARD_COUNT return kwargs def _resolve_is_shard_primary() -> bool: raw = os.getenv("SHARD_PRIMARY", "").strip().lower() if raw in ("1", "true", "yes", "on"): return True if raw in ("0", "false", "no", "off"): return False if not SHARD_IDS: return True return 0 in SHARD_IDS IS_SHARD_PRIMARY: bool = _resolve_is_shard_primary() # Aliases kept for backwards compatibility with files that import these names BOT_OWNER_IDS = OWNER_IDS BOT_OWNER_IDS_STR = OWNER_IDS_STR STAFF_IDS = OWNER_IDS STAFF_IDS_STR = OWNER_IDS_STR