1+ import json
2+ import os
3+ import re
4+ from pathlib import Path
5+
6+ _env_path = Path (__file__ ).resolve ().parent / ".env"
7+ try :
8+ from dotenv import load_dotenv
9+
10+ if _env_path .exists ():
11+ load_dotenv (dotenv_path = _env_path , override = False )
12+ else :
13+ load_dotenv (override = False )
14+ except ImportError :
15+ if _env_path .exists ():
16+ with open (_env_path , "r" , encoding = "utf-8" ) as _f :
17+ for _line in _f :
18+ _line = _line .strip ()
19+ if not _line or _line .startswith ("#" ) or "=" not in _line :
20+ continue
21+ _k , _ , _v = _line .partition ("=" )
22+ _k = _k .strip ()
23+ _v = _v .strip ()
24+ if (_v .startswith ('"' ) and _v .endswith ('"' )) or (_v .startswith ("'" ) and _v .endswith ("'" )):
25+ _v = _v [1 :- 1 ]
26+ if _k and _k not in os .environ :
27+ os .environ [_k ] = _v
28+
29+
30+ def _get_str (key : str , default : str = "" ) -> str :
31+ val = os .getenv (key )
32+ if val is None :
33+ return default
34+ return str (val ).strip ()
35+
36+
37+ def _get_int (key : str , default : int = 0 ) -> int :
38+ val = os .getenv (key )
39+ if val is None or not str (val ).strip ():
40+ return default
41+ try :
42+ return int (str (val ).strip ())
43+ except (TypeError , ValueError ):
44+ return default
45+
46+
47+ def _get_bool (key : str , default : bool = False ) -> bool :
48+ val = os .getenv (key )
49+ if val is None or not str (val ).strip ():
50+ return default
51+ return str (val ).strip ().lower () in ("true" , "1" , "yes" , "y" , "on" )
52+
53+
54+ def _get_list_int (key : str , default : list | None = None ) -> list [int ]:
55+ if default is None :
56+ default = []
57+ val = os .getenv (key )
58+ if val is None or not str (val ).strip ():
59+ return default
60+ s = str (val ).strip ()
61+ if s .startswith ("[" ):
62+ try :
63+ parsed = json .loads (s )
64+ if isinstance (parsed , list ):
65+ return [int (x ) for x in parsed if str (x ).strip ().lstrip ("-" ).isdigit ()]
66+ except Exception :
67+ pass
68+ parts = re .split (r"[\s,]+" , s )
69+ out = [int (p ) for p in parts if p .strip ().lstrip ("-" ).isdigit ()]
70+ return out if out else default
71+
72+
73+ def _get_id_or_list (key : str , default : int | list = 0 ) -> int | list :
74+ val = os .getenv (key )
75+ if val is None or not str (val ).strip ():
76+ return default
77+ s = str (val ).strip ()
78+ if s .startswith ("[" ):
79+ try :
80+ parsed = json .loads (s )
81+ if isinstance (parsed , list ):
82+ return [int (x ) for x in parsed if str (x ).strip ().lstrip ("-" ).isdigit ()]
83+ except Exception :
84+ pass
85+ try :
86+ return int (s )
87+ except (TypeError , ValueError ):
88+ return default
89+
90+
91+ def _get_filter_mode (key : str , default : int = 1 ) -> int | str :
92+ val = os .getenv (key )
93+ if val is None or not str (val ).strip ():
94+ return default
95+ s = str (val ).strip ()
96+ if s .isdigit ():
97+ return int (s )
98+ return s
99+
100+
101+ def _get_chat_topic (key : str , default : int = 0 ) -> int | str :
102+ val = os .getenv (key )
103+ if val is None or not str (val ).strip ():
104+ return default
105+ s = str (val ).strip ()
106+ if s .lower () == "all" :
107+ return "all"
108+ try :
109+ return int (s )
110+ except (TypeError , ValueError ):
111+ return s
112+
113+
114+ # Core
115+ BOT_TOKEN = _get_str ("BOT_TOKEN" )
116+ API_ID = _get_int ("API_ID" , 0 )
117+ API_HASH = _get_str ("API_HASH" )
118+ MONGO_URI = _get_str ("MONGO_URI" )
119+ DATABASE_NAME = _get_str ("DATABASE_NAME" , "StreamX" )
120+ OWNER_ID = _get_id_or_list ("OWNER_ID" , 0 )
121+ SUDO_USERS = _get_list_int ("SUDO_USERS" , [])
122+ SECRET_KEY = _get_str ("SECRET_KEY" )
123+ GITHUB_TOKEN = _get_str ("GITHUB_TOKEN" )
124+ ONLY_API = _get_bool ("ONLY_API" , False )
125+
126+ # Firebase
127+ FIREBASE_CREDENTIALS = _get_str ("FIREBASE_CREDENTIALS" )
128+
129+ # Debug
130+ DEBUG = _get_bool ("DEBUG" , False )
131+
132+ # Thumbnail Generation
133+ COLLEGE = _get_bool ("COLLEGE" , True )
134+ TEXT_COLOR = _get_str ("TEXT_COLOR" , "#FFFFFF" )
135+
136+ # API & Web
137+ CORS_ORIGIN = _get_str ("CORS_ORIGIN" , "https://streamxweb-chi.vercel.app" )
138+ CORS_ORIGINS = _get_str ("CORS_ORIGINS" , CORS_ORIGIN )
139+ COOKIE_SECURE = _get_bool ("COOKIE_SECURE" , True )
140+ COOKIE_SAMESITE = _get_str ("COOKIE_SAMESITE" , "none" )
141+
142+ # Userbot
143+ SESSION_STRING = _get_str ("SESSION_STRING" )
144+ SOURCE_CHANNEL_IDS = _get_list_int ("SOURCE_CHANNEL_IDS" , [])
145+ CHAT_TOPIC = _get_chat_topic ("CHAT_TOPIC" , 0 )
146+
147+ # Misc
148+ CHANNEL_ID = _get_int ("CHANNEL_ID" , 0 )
149+ DUMP_CHANNEL_ID = _get_int ("DUMP_CHANNEL_ID" , 0 )
150+ FILTER_MODE = _get_filter_mode ("FILTER_MODE" , 1 )
151+ COLLABORATOR_ID = _get_list_int ("COLLABORATOR_ID" , [])
152+ COLLABORATOR_IDS = _get_list_int ("COLLABORATOR_IDS" , COLLABORATOR_ID )
153+
154+ # Lyrics API
155+ LRCLIB = _get_bool ("LRCLIB" , False )
156+ MUSIXMATCH = _get_bool ("MUSIXMATCH" , True )
157+
158+ # Spotify
159+ SPOTIFY_CLIENT_ID = _get_str ("SPOTIFY_CLIENT_ID" )
160+ SPOTIFY_CLIENT_SECRET = _get_str ("SPOTIFY_CLIENT_SECRET" )
161+
162+ # Multi-Clients
163+ MULTI_CLIENTS = _get_bool ("MULTI_CLIENTS" , False )
164+ MULTI_CLIENTS_1 = _get_str ("MULTI_CLIENTS_1" )
165+ MULTI_CLIENTS_2 = _get_str ("MULTI_CLIENTS_2" )
166+ MULTI_CLIENTS_3 = _get_str ("MULTI_CLIENTS_3" )
167+ MULTI_CLIENTS_4 = _get_str ("MULTI_CLIENTS_4" )
168+
169+ for _env_k , _env_v in os .environ .items ():
170+ if _env_k .startswith ("MULTI_CLIENTS_" ) and _env_k not in globals ():
171+ globals ()[_env_k ] = _env_v
0 commit comments