Skip to content

Commit 9bfd76a

Browse files
authored
[+] Greatly Improved Speed / Less Rate Limiting
if youd like to experiment and increase speed, with increased chance of failure = more time to send total amount of messages, you can change the following line: chunk_size = 4
1 parent 819aeec commit 9bfd76a

File tree

1 file changed

+169
-40
lines changed

1 file changed

+169
-40
lines changed

scripts/discord_webhook_spammer.py

Lines changed: 169 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,94 +2,223 @@
22
from colorama import Fore, init
33
import os
44
import time
5-
import threading
6-
from concurrent.futures import ThreadPoolExecutor, as_completed
5+
import asyncio
6+
import aiohttp
7+
import random
8+
from datetime import datetime, timedelta
79

810
init(autoreset=True)
911

12+
def format_time(seconds):
13+
if seconds == float('inf'):
14+
return "Unknown"
15+
return str(timedelta(seconds=int(seconds)))
16+
17+
class RateLimiter:
18+
def __init__(self):
19+
self.reset_time = time.time()
20+
self.success_count = 0
21+
self.fail_count = 0
22+
self.delay = 0.1
23+
self.last_success = time.time()
24+
self.consecutive_fails = 0
25+
26+
async def should_send(self):
27+
28+
success_ratio = self.success_count / (self.success_count + self.fail_count + 1)
29+
if success_ratio < 0.5:
30+
self.delay = min(2.0, self.delay * 1.2)
31+
elif success_ratio > 0.8:
32+
self.delay = max(0.1, self.delay * 0.8)
33+
34+
await asyncio.sleep(self.delay)
35+
return True
36+
37+
def update_stats(self, success):
38+
if success:
39+
self.success_count += 1
40+
self.consecutive_fails = 0
41+
self.last_success = time.time()
42+
else:
43+
self.fail_count += 1
44+
self.consecutive_fails += 1
45+
46+
class MessageQueue:
47+
def __init__(self, total_messages):
48+
self.queue = asyncio.Queue()
49+
self.failed_queue = asyncio.Queue()
50+
self.total = total_messages
51+
self.sent = 0
52+
self.retries = 0
53+
self.start_time = time.time()
54+
55+
async def add_failed(self, message_id):
56+
await self.failed_queue.put(message_id)
57+
self.retries += 1
58+
59+
def get_stats(self):
60+
elapsed = time.time() - self.start_time
61+
rate = self.sent / elapsed if elapsed > 0 else 0
62+
remaining = self.total - self.sent
63+
eta = remaining / rate if rate > 0 else float('inf')
64+
return rate, eta, remaining
65+
1066
def extract_webhooks(file_path):
1167
try:
1268
if not os.path.exists(file_path):
1369
print(f"{Fore.RED}[!] File not found: {file_path}")
1470
return []
1571

1672
with open(file_path, 'r') as file:
17-
1873
for _ in range(2):
19-
next(file, None)
20-
# Read remaining lines
74+
next(file)
75+
2176
webhooks = [line.strip() for line in file if line.strip()]
2277
return webhooks
2378
except Exception as e:
2479
print(f"{Fore.RED}[!] Error reading webhooks file: {e}")
2580
return []
2681

2782
def display_webhooks(webhooks):
28-
print(f"\n{Fore.RED}[*] {Fore.GREEN}Available Webhooks:")
83+
print(f"\n{Fore.GREEN}Available Webhooks:")
2984
for i, webhook in enumerate(webhooks, 1):
30-
print(f"{Fore.RED}[{i}] {Fore.GREEN}{webhook}")
85+
short_webhook = webhook[:50] + "..." if len(webhook) > 50 else webhook
86+
print(f"{Fore.RED}[{Fore.MAGENTA}{i}{Fore.RED}] -> {Fore.GREEN}URL: {Fore.RED}{short_webhook}{Fore.RESET}")
3187

32-
def spam_single_message(webhook, message):
88+
async def send_message(session, webhook, message, message_id, queue, rate_limiter):
3389
try:
34-
response = requests.post(webhook, json={"content": message})
35-
if response.status_code == 429:
36-
retry_after = float(response.headers.get('Retry-After', 0.5))
37-
time.sleep(retry_after)
38-
# Retry the request
39-
response = requests.post(webhook, json={"content": message})
90+
await rate_limiter.should_send()
4091

41-
if response.status_code == 204:
42-
print(f"{Fore.GREEN}[*] Successfully sent message to webhook: {Fore.RED}{webhook}{Fore.RESET}")
43-
else:
44-
print(f"{Fore.RED}[!] Failed to send message to webhook: {Fore.RED}{webhook} (Status: {response.status_code}){Fore.RESET}")
45-
except Exception as e:
46-
print(f"{Fore.RED}[!] Error sending message to webhook: {e}")
92+
headers = {
93+
'Content-Type': 'application/json',
94+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
95+
}
4796

48-
def spam_webhook(webhook, message, count=1):
49-
with ThreadPoolExecutor(max_workers=7) as executor:
50-
futures = [
51-
executor.submit(spam_single_message, webhook, message)
52-
for _ in range(count)
53-
]
54-
for _ in as_completed(futures):
55-
pass
97+
async with session.post(webhook, json={"content": message}, headers=headers, timeout=5) as response:
98+
if response.status == 429:
99+
retry_after = float(response.headers.get('Retry-After', 1))
100+
rate_limiter.update_stats(False)
101+
print(f"{Fore.RED}[!] {Fore.GREEN}Rate Limited : {Fore.RED}Message queued ({retry_after:.1f}s){Fore.RESET}")
102+
await queue.add_failed(message_id)
103+
return False
56104

105+
elif response.status == 204:
106+
rate_limiter.update_stats(True)
107+
queue.sent += 1
108+
print(f"{Fore.RED}[+] {Fore.GREEN}Success : {Fore.RED}Message sent{Fore.RESET}")
109+
return True
57110

58-
def run():
111+
else:
112+
rate_limiter.update_stats(False)
113+
print(f"{Fore.RED}[!] {Fore.GREEN}Failed : {Fore.RED}Status {response.status}{Fore.RESET}")
114+
if response.status != 404:
115+
await queue.add_failed(message_id)
116+
return False
117+
118+
except Exception as e:
119+
print(f"{Fore.RED}[!] {Fore.GREEN}Error : {Fore.RED}{str(e)}{Fore.RESET}")
120+
await queue.add_failed(message_id)
121+
return False
122+
123+
async def spam_webhook(webhook, message, count):
124+
connector = aiohttp.TCPConnector(limit=None, ttl_dns_cache=300)
125+
timeout = aiohttp.ClientTimeout(total=30)
126+
rate_limiter = RateLimiter()
127+
queue = MessageQueue(count)
128+
129+
async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
130+
message_ids = list(range(count))
131+
chunk_size = 4
132+
133+
while message_ids or not queue.failed_queue.empty():
134+
current_chunk = []
135+
136+
137+
while len(current_chunk) < chunk_size:
138+
if message_ids:
139+
current_chunk.append(message_ids.pop(0))
140+
elif not queue.failed_queue.empty():
141+
failed_id = await queue.failed_queue.get()
142+
current_chunk.append(failed_id)
143+
else:
144+
break
145+
146+
if not current_chunk:
147+
break
148+
149+
tasks = [
150+
asyncio.create_task(
151+
send_message(session, webhook, message, msg_id, queue, rate_limiter)
152+
)
153+
for msg_id in current_chunk
154+
]
155+
156+
await asyncio.gather(*tasks)
157+
158+
rate, eta, remaining = queue.get_stats()
159+
print(f"{Fore.YELLOW}Progress: {queue.sent}/{count} sent ({rate:.1f} msg/s | ETA: {format_time(eta)})")
160+
161+
162+
await asyncio.sleep(0.5)
163+
164+
return queue.sent
165+
166+
async def main():
59167
webhooks_file_path = "input/discord-webhooks.txt"
60168
webhooks = extract_webhooks(webhooks_file_path)
61169

62170
if not webhooks:
63-
print(f"{Fore.RED}[!] No webhooks found in /input/discord-webhooks.txt - Exiting...")
171+
print(f"{Fore.RED}[!] No webhooks found in /input/discord-webhooks.txt")
64172
return
65173

66174
display_webhooks(webhooks)
67-
68-
choice = input(f"\n{Fore.RED}[*] {Fore.GREEN}Select webhook or enter 'A' to use all: ").strip()
175+
print(f"\n{Fore.YELLOW}Select webhook or type 'A' to use all...")
176+
choice = input(f"{Fore.RED}[+] {Fore.GREEN}Webhook >> {Fore.RED}").strip()
69177

70178
if choice.lower() == 'a':
71-
selected_webhooks = webhooks
179+
selected_webhooks = webhooks
72180
elif choice.isdigit() and 1 <= int(choice) <= len(webhooks):
73-
selected_webhooks = [webhooks[int(choice) - 1]]
181+
selected_webhooks = [webhooks[int(choice) - 1]]
74182
else:
75183
print(f"{Fore.RED}[!] Invalid choice. Exiting...")
76184
return
77185

78-
message = input(f"\n{Fore.RED}[+] {Fore.GREEN}Message -> ").strip()
79-
count = input(f"\n{Fore.RED}[+] {Fore.GREEN}Number of messages to send -> ").strip()
186+
message = input(f"{Fore.RED}[+] {Fore.GREEN}Message >> {Fore.RED}").strip()
187+
count = input(f"{Fore.RED}[+] {Fore.GREEN}Count >> {Fore.RED}").strip()
80188

81189
try:
82190
count = int(count)
83191
if count < 1:
84192
raise ValueError
85193
except ValueError:
86-
print(f"{Fore.RED}[!] Invalid number. Exiting...")
194+
print(f"{Fore.RED}[!] Invalid count. Exiting...")
87195
return
88196

89-
for webhook in selected_webhooks:
90-
spam_webhook(webhook, message, count)
197+
print(f"\n{Fore.YELLOW}Starting...")
198+
total_start_time = time.time()
199+
total_sent = 0
91200

92-
print(f"\n{Fore.RED}[*] {Fore.LIGHTGREEN_EX}Finished sending {count} messages to {len(selected_webhooks)} webhook(s)!")
201+
try:
202+
for webhook in selected_webhooks:
203+
sent = await spam_webhook(webhook, message, count)
204+
total_sent += sent
205+
206+
except KeyboardInterrupt:
207+
print(f"\n{Fore.RED}[!] Operation interrupted by user")
208+
except Exception as e:
209+
print(f"\n{Fore.RED}[!] An error occurred: {str(e)}")
210+
finally:
211+
total_time = time.time() - total_start_time
212+
rate = total_sent / total_time if total_time > 0 else 0
213+
214+
print(f"\n{Fore.RED}[+] {Fore.GREEN}Final Summary:")
215+
print(f"{Fore.RED}[+] {Fore.GREEN}Total Sent : {Fore.RED}{total_sent}")
216+
print(f"{Fore.RED}[+] {Fore.GREEN}Time Elapsed : {Fore.RED}{format_time(total_time)}")
217+
print(f"{Fore.RED}[+] {Fore.GREEN}Average Rate : {Fore.RED}{rate:.1f} msg/s")
218+
print(f"{Fore.RED}[+] {Fore.GREEN}Webhooks Used : {Fore.RED}{len(selected_webhooks)}")
219+
220+
def run():
221+
asyncio.run(main())
93222

94223
if __name__ == "__main__":
95224
run()

0 commit comments

Comments
 (0)