-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
372 lines (303 loc) · 13.8 KB
/
Copy pathmain.py
File metadata and controls
372 lines (303 loc) · 13.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
import os
import sys
import time
import json
import random
import threading
import requests
import questionary
import websocket
from colorama import Fore, Style, init
from datetime import datetime
init(autoreset=True)
HEARTBEAT_INTERVAL = 41.250
GATEWAY_URL = "wss://gateway.discord.gg/?v=9&encoding=json"
CONFIG_FILE = "settings.json"
print_lock = threading.Lock()
def clear_screen():
os.system('cls' if os.name == 'nt' else 'clear')
def get_timestamp():
return datetime.now().strftime("%H:%M:%S")
def print_banner():
banner = r"""
__ __ _ _________ __
/ \ / \ | | / _____/ ____ ____ ____ ____ _/ |_ ____ ______
\ \/\/ / | | ______ \_____ \ / _ \ / \ / \ _/ __ \ \ __\/ __ \ \____ \
\ / | |__ /_____/ / \( <_> )| | \| | \ \ ___/ | | ( <_> )| |_> >
\__/\ / |____| /_______ / \____/ |___| /|___| / \___ > |__| \____/ | __/
\/ \/ \/ \/ \/ |__|
:: Voice Connector v0.1.4 :: Developer: syntt_ (1419678867005767783) ::
"""
print(Fore.CYAN + banner)
# Anti-Scam Warning Block
print(Fore.RED + " " + "─" * 74)
print(Fore.RED + " [!] LICENSE ALERT: This software is strictly FREE & OPEN SOURCE (GPLv3).")
print(Fore.RED + " [!] If you purchased this product, YOU HAVE BEEN SCAMMED.")
print(Fore.RED + " [!] Please request a refund immediately and report the seller to syntt_.")
print(Fore.RED + " " + "─" * 74 + "\n")
def safe_print(message):
with print_lock:
sys.stdout.write("\r" + " " * 100 + "\r")
sys.stdout.write(message + "\n")
sys.stdout.flush()
def load_settings():
if not os.path.exists(CONFIG_FILE):
return None
try:
with open(CONFIG_FILE, 'r') as f:
return json.load(f)
except:
return None
def save_settings(guild_id, channel_id, amount_choice):
data = {
"guild_id": str(guild_id),
"channel_id": str(channel_id),
"amount": str(amount_choice)
}
try:
with open(CONFIG_FILE, 'w') as f:
json.dump(data, f, indent=4)
except:
pass
def get_safe_amount(total_tokens: int, channel_limit: int, channel_name: str, default_val=None) -> int:
limit_str = f"{channel_limit}" if channel_limit > 0 else "Infinite"
if default_val:
if default_val == "all": return total_tokens
if str(default_val).isdigit() and 0 < int(default_val) <= total_tokens:
return int(default_val)
print(Fore.CYAN + f"[*] Configuration:")
print(Fore.WHITE + f" Available Tokens: {Fore.GREEN}{total_tokens}")
print(Fore.WHITE + f" Target Channel '{channel_name}': {Fore.YELLOW}Limit: {limit_str}")
print(Fore.LIGHTBLACK_EX + " (Press Enter to connect ALL accounts)")
while True:
user_input = questionary.text("How many accounts to connect?").ask()
if user_input is None: sys.exit()
if user_input.strip() == "":
return total_tokens
if not user_input.isdigit():
print(Fore.RED + " [!] Please enter a number or leave empty.")
continue
amount = int(user_input)
if amount <= 0 or amount > total_tokens:
print(Fore.RED + f" [!] Invalid amount (Max: {total_tokens}).")
continue
if channel_limit > 0 and amount > channel_limit:
if not questionary.confirm("Amount exceeds channel limit. Continue?").ask(): continue
return amount
class DiscordVoiceClient(threading.Thread):
def __init__(self, token, guild_id, channel_id, user_index, total_users):
super().__init__()
self.token = token
self.guild_id = str(guild_id)
self.channel_id = str(channel_id)
self.user_index = user_index
self.total_users = total_users
self.ws = None
self.connected = False
self.voice_connected = False
self.should_reconnect = True
self.user_info = "..."
self.user_id = None
self._stop_event = threading.Event()
def log(self, message, color=Fore.WHITE, level="INFO"):
msg_fmt = f"{Fore.LIGHTBLACK_EX}[{get_timestamp()}] {color}[{level}] ({self.user_index:02d}) {message}"
safe_print(msg_fmt)
def run(self):
while self.should_reconnect:
try:
self._stop_event.clear()
websocket.enableTrace(False)
self.ws = websocket.WebSocketApp(
GATEWAY_URL,
on_open=self.on_open,
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close
)
self.ws.run_forever()
except Exception:
pass
self.connected = False
self.voice_connected = False
self._stop_event.set()
if self.should_reconnect:
time.sleep(random.uniform(3, 8))
def send_json(self, payload):
try:
if self.ws and self.ws.sock and self.ws.sock.connected:
self.ws.send(json.dumps(payload))
except: pass
def on_open(self, ws):
auth_payload = {
"op": 2,
"d": {
"token": self.token,
"capabilities": 16381,
"properties": {
"os": "Windows", "browser": "Chrome", "device": "",
"system_locale": "en-US", "browser_user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"client_build_number": 260000
},
"presence": {"status": "online", "since": 0, "activities": [], "afk": False},
"compress": False,
"client_state": {"guild_hashes": {}, "highest_last_message_id": "0", "read_state_version": 0, "user_guild_settings_version": -1, "user_settings_version": -1}
}
}
self.send_json(auth_payload)
def on_message(self, ws, message):
try:
data = json.loads(message)
op = data.get("op")
t = data.get("t")
if op == 10:
interval = data["d"]["heartbeat_interval"] / 1000
threading.Thread(target=self.heartbeat, args=(interval,), daemon=True).start()
elif t == "READY":
self.user_info = f"{data['d']['user']['username']}#{data['d']['user']['discriminator']}"
self.user_id = str(data['d']['user']['id'])
self.connected = True
threading.Timer(2.0, self.join_voice).start()
elif t == "VOICE_STATE_UPDATE":
d = data['d']
if str(d.get('user_id')) == self.user_id:
channel_id = str(d.get('channel_id'))
if channel_id == self.channel_id:
if not self.voice_connected:
self.voice_connected = True
self.log(f"Connected to Voice: {self.user_info}", Fore.GREEN, "VOICE")
elif channel_id == "None":
self.voice_connected = False
except: pass
def join_voice(self):
voice_payload = {
"op": 4,
"d": {
"guild_id": self.guild_id,
"channel_id": self.channel_id,
"self_mute": True,
"self_deaf": True
}
}
self.send_json(voice_payload)
def heartbeat(self, interval):
while not self._stop_event.is_set() and self.connected:
time.sleep(interval)
try: self.send_json({"op": 1, "d": None})
except: break
def on_error(self, ws, error): pass
def on_close(self, ws, close_status_code, close_msg):
self.connected = False
self.voice_connected = False
def load_tokens():
if not os.path.exists('tokens.txt'): open('tokens.txt', 'w').close(); return []
with open('tokens.txt', 'r') as f: return [line.strip() for line in f if line.strip()]
def validate_tokens_and_get_guilds(tokens):
print(Fore.CYAN + "\n[*] Validating tokens...")
valid, maps = [], []
s = requests.Session()
for i, token in enumerate(tokens):
headers = {"Authorization": token, "Content-Type": "application/json"}
try:
r = s.get("https://discord.com/api/v9/users/@me", headers=headers, timeout=5)
if r.status_code == 200:
print(Fore.GREEN + f" [OK] Token {i+1}")
rg = s.get("https://discord.com/api/v9/users/@me/guilds", headers=headers)
if rg.status_code == 200:
maps.append({g['id']: g['name'] for g in rg.json()})
valid.append(token)
else: print(Fore.RED + f" [X] Token {i+1} Invalid")
except: print(Fore.RED + f" [!] Error Token {i+1}")
return valid, maps
def get_channels(guild_id, token):
headers = {"Authorization": token}
try:
r = requests.get(f"https://discord.com/api/v9/guilds/{guild_id}/channels", headers=headers)
if r.status_code == 200: return [c for c in r.json() if c['type'] == 2]
except: pass
return []
def main():
clear_screen()
print_banner()
tokens = load_tokens()
if not tokens: sys.exit("No tokens found in tokens.txt")
valid_tokens, guilds_map = validate_tokens_and_get_guilds(tokens)
if not valid_tokens: sys.exit()
common_ids = set(guilds_map[0].keys())
for m in guilds_map[1:]: common_ids &= set(m.keys())
if not common_ids: sys.exit("No common servers found among tokens.")
common_guilds_dict = {gid: guilds_map[0][gid] for gid in common_ids}
settings = load_settings()
use_saved = False
gid, cid, amount_to_connect = None, None, None
selected_channel_name = "Unknown"
selected_channel_limit = 0
if settings:
s_gid = settings.get("guild_id")
s_cid = settings.get("channel_id")
s_amt = settings.get("amount")
if s_gid in common_guilds_dict:
guild_name = common_guilds_dict[s_gid]
print(Fore.WHITE + f"\n[CONFIG] Saved configuration found:")
print(Fore.WHITE + f" Server : {Fore.GREEN}{guild_name}")
print(Fore.WHITE + f" Channel: {Fore.GREEN}{s_cid}")
print(Fore.WHITE + f" Amount : {Fore.GREEN}{s_amt if s_amt != 'all' else 'All'}")
if questionary.confirm("Load this configuration?").ask():
use_saved = True
gid = s_gid
cid = s_cid
channels = get_channels(gid, valid_tokens[0])
target_c = next((c for c in channels if c['id'] == cid), None)
if target_c:
selected_channel_name = target_c['name']
selected_channel_limit = target_c.get('user_limit', 0)
if s_amt == "all": amount_to_connect = len(valid_tokens)
else: amount_to_connect = int(s_amt)
else:
print(Fore.RED + " [!] Saved channel no longer exists. Restarting setup...")
use_saved = False
if not use_saved:
guild_choices = [questionary.Choice(n, str(v)) for v, n in common_guilds_dict.items()]
gid = questionary.select("Select Server:", choices=guild_choices).ask()
if not gid: sys.exit()
print(Fore.CYAN + "\n[*] Fetching channels...")
channels = get_channels(gid, valid_tokens[0])
if not channels: sys.exit("No voice channels found.")
channel_choices = [questionary.Choice(f"{c['name']} ({c['id']})", str(c['id'])) for c in channels]
cid = questionary.select("Select Channel:", choices=channel_choices).ask()
if not cid: sys.exit()
target_c = next((c for c in channels if c['id'] == cid), None)
selected_channel_name = target_c['name']
selected_channel_limit = target_c.get('user_limit', 0)
amount_to_connect = get_safe_amount(len(valid_tokens), selected_channel_limit, selected_channel_name)
save_val = "all" if amount_to_connect == len(valid_tokens) else str(amount_to_connect)
save_settings(gid, cid, save_val)
target_tokens = valid_tokens[:amount_to_connect]
clear_screen()
print_banner()
print(Fore.WHITE + f" TARGET: {selected_channel_name} (ID: {cid})")
print(Fore.WHITE + f" ACCOUNTS: {len(target_tokens)} | MODE: Auto-Healing\n")
print(Fore.WHITE + "─" * 80 + "\n")
threads = []
for i, token in enumerate(target_tokens):
t = DiscordVoiceClient(token, gid, cid, i+1, len(target_tokens))
t.daemon = True
t.start()
threads.append(t)
time.sleep(random.uniform(0.5, 1.5))
try:
while True:
alive = sum(1 for t in threads if t.is_alive())
conn = sum(1 for t in threads if t.connected)
voice = sum(1 for t in threads if t.voice_connected)
c_color = Fore.GREEN if voice == len(threads) else Fore.YELLOW
status_msg = f"{Fore.WHITE}[STATUS] Threads: {alive} | Gateway: {conn} | {c_color}Voice: {voice}/{len(threads)} "
with print_lock:
sys.stdout.write("\r" + status_msg)
sys.stdout.flush()
time.sleep(1)
except KeyboardInterrupt:
print(Fore.RED + "\n\n[!] Stopping...")
for t in threads: t.should_reconnect = False
sys.exit()
if __name__ == "__main__":
main()