webscout 7.5__py3-none-any.whl โ†’ 7.7__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.

Potentially problematic release.


This version of webscout might be problematic. Click here for more details.

Files changed (132) hide show
  1. webscout/AIauto.py +5 -53
  2. webscout/AIutel.py +8 -318
  3. webscout/DWEBS.py +460 -489
  4. webscout/Extra/YTToolkit/YTdownloader.py +14 -53
  5. webscout/Extra/YTToolkit/transcriber.py +12 -13
  6. webscout/Extra/YTToolkit/ytapi/video.py +0 -1
  7. webscout/Extra/__init__.py +0 -1
  8. webscout/Extra/autocoder/__init__.py +9 -9
  9. webscout/Extra/autocoder/autocoder_utiles.py +193 -199
  10. webscout/Extra/autocoder/rawdog.py +789 -677
  11. webscout/Extra/gguf.py +682 -428
  12. webscout/Extra/weather.py +178 -156
  13. webscout/Extra/weather_ascii.py +70 -17
  14. webscout/Litlogger/core/logger.py +1 -2
  15. webscout/Litlogger/handlers/file.py +1 -1
  16. webscout/Litlogger/styles/formats.py +0 -2
  17. webscout/Litlogger/utils/detectors.py +0 -1
  18. webscout/Provider/AISEARCH/DeepFind.py +0 -1
  19. webscout/Provider/AISEARCH/ISou.py +1 -22
  20. webscout/Provider/AISEARCH/felo_search.py +0 -1
  21. webscout/Provider/AllenAI.py +28 -30
  22. webscout/Provider/C4ai.py +29 -11
  23. webscout/Provider/ChatGPTClone.py +226 -0
  24. webscout/Provider/ChatGPTGratis.py +24 -56
  25. webscout/Provider/DeepSeek.py +25 -17
  26. webscout/Provider/Deepinfra.py +115 -48
  27. webscout/Provider/Gemini.py +1 -1
  28. webscout/Provider/Glider.py +33 -12
  29. webscout/Provider/HF_space/qwen_qwen2.py +2 -2
  30. webscout/Provider/HeckAI.py +23 -7
  31. webscout/Provider/Hunyuan.py +272 -0
  32. webscout/Provider/Jadve.py +20 -5
  33. webscout/Provider/LambdaChat.py +391 -0
  34. webscout/Provider/Netwrck.py +42 -19
  35. webscout/Provider/OLLAMA.py +256 -32
  36. webscout/Provider/PI.py +4 -2
  37. webscout/Provider/Perplexitylabs.py +26 -6
  38. webscout/Provider/PizzaGPT.py +10 -51
  39. webscout/Provider/TTI/AiForce/async_aiforce.py +4 -37
  40. webscout/Provider/TTI/AiForce/sync_aiforce.py +41 -38
  41. webscout/Provider/TTI/FreeAIPlayground/__init__.py +9 -9
  42. webscout/Provider/TTI/FreeAIPlayground/async_freeaiplayground.py +179 -206
  43. webscout/Provider/TTI/FreeAIPlayground/sync_freeaiplayground.py +180 -192
  44. webscout/Provider/TTI/MagicStudio/__init__.py +2 -0
  45. webscout/Provider/TTI/MagicStudio/async_magicstudio.py +111 -0
  46. webscout/Provider/TTI/MagicStudio/sync_magicstudio.py +109 -0
  47. webscout/Provider/TTI/PollinationsAI/async_pollinations.py +5 -24
  48. webscout/Provider/TTI/PollinationsAI/sync_pollinations.py +2 -22
  49. webscout/Provider/TTI/__init__.py +2 -3
  50. webscout/Provider/TTI/aiarta/async_aiarta.py +14 -14
  51. webscout/Provider/TTI/aiarta/sync_aiarta.py +52 -21
  52. webscout/Provider/TTI/artbit/async_artbit.py +3 -32
  53. webscout/Provider/TTI/artbit/sync_artbit.py +3 -31
  54. webscout/Provider/TTI/fastflux/__init__.py +22 -0
  55. webscout/Provider/TTI/fastflux/async_fastflux.py +261 -0
  56. webscout/Provider/TTI/fastflux/sync_fastflux.py +252 -0
  57. webscout/Provider/TTI/piclumen/__init__.py +22 -22
  58. webscout/Provider/TTI/piclumen/sync_piclumen.py +232 -232
  59. webscout/Provider/TTS/__init__.py +2 -2
  60. webscout/Provider/TTS/deepgram.py +12 -39
  61. webscout/Provider/TTS/elevenlabs.py +14 -40
  62. webscout/Provider/TTS/gesserit.py +11 -35
  63. webscout/Provider/TTS/murfai.py +13 -39
  64. webscout/Provider/TTS/parler.py +17 -40
  65. webscout/Provider/TTS/speechma.py +180 -0
  66. webscout/Provider/TTS/streamElements.py +17 -44
  67. webscout/Provider/TextPollinationsAI.py +39 -59
  68. webscout/Provider/Venice.py +25 -8
  69. webscout/Provider/WebSim.py +227 -0
  70. webscout/Provider/WiseCat.py +27 -5
  71. webscout/Provider/Youchat.py +64 -37
  72. webscout/Provider/__init__.py +12 -7
  73. webscout/Provider/akashgpt.py +20 -5
  74. webscout/Provider/flowith.py +33 -7
  75. webscout/Provider/freeaichat.py +32 -45
  76. webscout/Provider/koala.py +20 -5
  77. webscout/Provider/labyrinth.py +239 -0
  78. webscout/Provider/learnfastai.py +28 -15
  79. webscout/Provider/llamatutor.py +1 -1
  80. webscout/Provider/llmchat.py +30 -8
  81. webscout/Provider/multichat.py +65 -9
  82. webscout/Provider/sonus.py +208 -0
  83. webscout/Provider/talkai.py +1 -0
  84. webscout/Provider/turboseek.py +3 -0
  85. webscout/Provider/tutorai.py +2 -0
  86. webscout/Provider/typegpt.py +155 -65
  87. webscout/Provider/uncovr.py +297 -0
  88. webscout/Provider/x0gpt.py +3 -1
  89. webscout/Provider/yep.py +102 -20
  90. webscout/__init__.py +3 -0
  91. webscout/cli.py +53 -40
  92. webscout/conversation.py +1 -10
  93. webscout/litagent/__init__.py +2 -2
  94. webscout/litagent/agent.py +356 -20
  95. webscout/litagent/constants.py +34 -5
  96. webscout/litprinter/__init__.py +0 -3
  97. webscout/models.py +181 -0
  98. webscout/optimizers.py +1 -1
  99. webscout/prompt_manager.py +2 -8
  100. webscout/scout/core/scout.py +1 -4
  101. webscout/scout/core/search_result.py +1 -1
  102. webscout/scout/core/text_utils.py +1 -1
  103. webscout/scout/core.py +2 -5
  104. webscout/scout/element.py +1 -1
  105. webscout/scout/parsers/html_parser.py +1 -1
  106. webscout/scout/utils.py +0 -1
  107. webscout/swiftcli/__init__.py +1 -3
  108. webscout/tempid.py +1 -1
  109. webscout/update_checker.py +1 -3
  110. webscout/version.py +1 -1
  111. webscout/webscout_search_async.py +1 -2
  112. webscout/yep_search.py +297 -297
  113. {webscout-7.5.dist-info โ†’ webscout-7.7.dist-info}/LICENSE.md +4 -4
  114. {webscout-7.5.dist-info โ†’ webscout-7.7.dist-info}/METADATA +127 -405
  115. {webscout-7.5.dist-info โ†’ webscout-7.7.dist-info}/RECORD +118 -117
  116. webscout/Extra/autollama.py +0 -231
  117. webscout/Provider/Amigo.py +0 -274
  118. webscout/Provider/Bing.py +0 -243
  119. webscout/Provider/DiscordRocks.py +0 -253
  120. webscout/Provider/TTI/blackbox/__init__.py +0 -4
  121. webscout/Provider/TTI/blackbox/async_blackbox.py +0 -212
  122. webscout/Provider/TTI/blackbox/sync_blackbox.py +0 -199
  123. webscout/Provider/TTI/deepinfra/__init__.py +0 -4
  124. webscout/Provider/TTI/deepinfra/async_deepinfra.py +0 -227
  125. webscout/Provider/TTI/deepinfra/sync_deepinfra.py +0 -199
  126. webscout/Provider/TTI/imgninza/__init__.py +0 -4
  127. webscout/Provider/TTI/imgninza/async_ninza.py +0 -214
  128. webscout/Provider/TTI/imgninza/sync_ninza.py +0 -209
  129. webscout/Provider/TTS/voicepod.py +0 -117
  130. {webscout-7.5.dist-info โ†’ webscout-7.7.dist-info}/WHEEL +0 -0
  131. {webscout-7.5.dist-info โ†’ webscout-7.7.dist-info}/entry_points.txt +0 -0
  132. {webscout-7.5.dist-info โ†’ webscout-7.7.dist-info}/top_level.txt +0 -0
webscout/cli.py CHANGED
@@ -1,34 +1,12 @@
1
- import os
2
1
  import sys
3
- from concurrent.futures import ThreadPoolExecutor, as_completed
4
- from datetime import datetime
5
- from urllib.parse import unquote
6
- from pathlib import Path
7
- from .swiftcli import CLI, option, argument, group
8
- from curl_cffi import requests
9
- import pyreqwest_impersonate as pri
2
+ from .swiftcli import CLI, option
10
3
  from .webscout_search import WEBS
11
- from .utils import json_dumps, json_loads
12
4
  from .version import __version__
13
- from .Litlogger import LitLogger, LogFormat, ColorScheme
14
5
  from rich.console import Console
15
6
  from rich.panel import Panel
16
- from rich.markdown import Markdown
17
7
  from rich.table import Table
18
- from rich.style import Style
19
8
  from rich.text import Text
20
- from rich.align import Align
21
- from rich.progress import track, Progress
22
- from rich.prompt import Prompt, Confirm
23
- from rich.columns import Columns
24
- from pyfiglet import figlet_format
25
9
 
26
- logger = LitLogger(
27
- name="webscout",
28
- format=LogFormat.MODERN_EMOJI,
29
- color_scheme=ColorScheme.CYBERPUNK,
30
- console_output=True
31
- )
32
10
 
33
11
  COLORS = {
34
12
  0: "black",
@@ -71,6 +49,42 @@ def _print_data(data):
71
49
  console.print(Panel(table, title=f"Result {i}", expand=False, style="green on black"))
72
50
  console.print("\n")
73
51
 
52
+ def _print_weather(data):
53
+ """Prints weather data in a clean, focused format."""
54
+ console = Console()
55
+
56
+ # Current weather panel
57
+ current = data["current"]
58
+ current_table = Table(show_header=False, show_lines=True, expand=True, box=None)
59
+ current_table.add_column("Metric", style="cyan", no_wrap=True, width=15)
60
+ current_table.add_column("Value", style="white")
61
+
62
+ current_table.add_row("Temperature", f"{current['temperature_c']}ยฐC")
63
+ current_table.add_row("Feels Like", f"{current['feels_like_c']}ยฐC")
64
+ current_table.add_row("Humidity", f"{current['humidity']}%")
65
+ current_table.add_row("Wind", f"{current['wind_speed_ms']} m/s")
66
+ current_table.add_row("Direction", f"{current['wind_direction']}ยฐ")
67
+
68
+ console.print(Panel(current_table, title=f"Current Weather in {data['location']}", expand=False, style="green on black"))
69
+ console.print("\n")
70
+
71
+ # Daily forecast panel
72
+ daily_table = Table(show_header=True, show_lines=True, expand=True, box=None)
73
+ daily_table.add_column("Date", style="cyan")
74
+ daily_table.add_column("Condition", style="white")
75
+ daily_table.add_column("High", style="red")
76
+ daily_table.add_column("Low", style="blue")
77
+
78
+ for day in data["daily_forecast"][:5]: # Show next 5 days
79
+ daily_table.add_row(
80
+ day["date"],
81
+ day["condition"],
82
+ f"{day['max_temp_c']}ยฐC",
83
+ f"{day['min_temp_c']}ยฐC"
84
+ )
85
+
86
+ console.print(Panel(daily_table, title="5-Day Forecast", expand=False, style="green on black"))
87
+
74
88
  # Initialize CLI app
75
89
  app = CLI(name="webscout", help="Search the web with a rich UI", version=__version__)
76
90
 
@@ -89,7 +103,7 @@ def chat(proxy: str = None, model: str = "gpt-4o-mini"):
89
103
  console = Console()
90
104
 
91
105
  # Display header
92
- console.print(f"[bold blue]{figlet_format('Webscout Chat')}[/]\n", justify="center")
106
+ # console.print(f"[bold blue]{figlet_format('Webscout Chat')}[/]\n", justify="center")
93
107
  console.print(f"[bold green]Using model:[/] {model}\n")
94
108
  console.print("[cyan]Type your message and press Enter. Press Ctrl+C or type 'exit' to quit.[/]\n")
95
109
 
@@ -97,23 +111,18 @@ def chat(proxy: str = None, model: str = "gpt-4o-mini"):
97
111
  try:
98
112
  while True:
99
113
  try:
100
- user_input = input("You: ").strip()
114
+ user_input = input(">>> ").strip()
101
115
  if not user_input or user_input.lower() in ['exit', 'quit']:
102
116
  break
103
117
 
104
- logger.info(f"Sending message to {model}")
105
118
  response = webs.chat(keywords=user_input, model=model)
106
119
  console.print(f"\nAI: {response}\n")
107
- logger.success("Received response from AI")
108
120
 
109
121
  except Exception as e:
110
- logger.error(f"Error in chat: {str(e)}")
111
122
  console.print(f"[bold red]Error:[/] {str(e)}\n")
112
123
 
113
124
  except KeyboardInterrupt:
114
- logger.info("Chat session terminated by user")
115
-
116
- console.print("\n[cyan]Chat session ended. Goodbye![/]")
125
+ console.print("\n[bold red]Chat session interrupted. Exiting...[/]")
117
126
 
118
127
  @app.command()
119
128
  @option("--keywords", "-k", help="Search keywords", required=True)
@@ -130,7 +139,6 @@ def text(keywords: str, region: str, safesearch: str, timelimit: str, backend: s
130
139
  results = webs.text(keywords, region, safesearch, timelimit, backend, max_results)
131
140
  _print_data(results)
132
141
  except Exception as e:
133
- logger.error(f"Error in text search: {e}")
134
142
  raise e
135
143
 
136
144
  @app.command()
@@ -143,7 +151,6 @@ def answers(keywords: str, proxy: str = None):
143
151
  results = webs.answers(keywords)
144
152
  _print_data(results)
145
153
  except Exception as e:
146
- logger.error(f"Error in answers search: {e}")
147
154
  raise e
148
155
 
149
156
  @app.command()
@@ -177,7 +184,6 @@ def images(
177
184
  results = webs.images(keywords, region, safesearch, timelimit, size, color, type, layout, license, max_results)
178
185
  _print_data(results)
179
186
  except Exception as e:
180
- logger.error(f"Error in images search: {e}")
181
187
  raise e
182
188
 
183
189
  @app.command()
@@ -207,7 +213,6 @@ def videos(
207
213
  results = webs.videos(keywords, region, safesearch, timelimit, resolution, duration, license, max_results)
208
214
  _print_data(results)
209
215
  except Exception as e:
210
- logger.error(f"Error in videos search: {e}")
211
216
  raise e
212
217
 
213
218
  @app.command()
@@ -224,7 +229,6 @@ def news(keywords: str, region: str, safesearch: str, timelimit: str, max_result
224
229
  results = webs.news(keywords, region, safesearch, timelimit, max_results)
225
230
  _print_data(results)
226
231
  except Exception as e:
227
- logger.error(f"Error in news search: {e}")
228
232
  raise e
229
233
 
230
234
  @app.command()
@@ -275,7 +279,6 @@ def maps(
275
279
  )
276
280
  _print_data(results)
277
281
  except Exception as e:
278
- logger.error(f"Error in maps search: {e}")
279
282
  raise e
280
283
 
281
284
  @app.command()
@@ -290,7 +293,6 @@ def translate(keywords: str, from_: str, to: str, proxy: str = None):
290
293
  results = webs.translate(keywords, from_, to)
291
294
  _print_data(results)
292
295
  except Exception as e:
293
- logger.error(f"Error in translation: {e}")
294
296
  raise e
295
297
 
296
298
  @app.command()
@@ -304,7 +306,19 @@ def suggestions(keywords: str, region: str, proxy: str = None):
304
306
  results = webs.suggestions(keywords, region)
305
307
  _print_data(results)
306
308
  except Exception as e:
307
- logger.error(f"Error in suggestions search: {e}")
309
+ raise e
310
+
311
+ @app.command()
312
+ @option("--location", "-l", help="Location to get weather for", required=True)
313
+ @option("--language", "-lang", help="Language code (e.g. 'en', 'es')", default="en")
314
+ @option("--proxy", "-p", help="Proxy URL to use for requests")
315
+ def weather(location: str, language: str, proxy: str = None):
316
+ """Get weather information for a location from DuckDuckGo."""
317
+ webs = WEBS(proxy=proxy)
318
+ try:
319
+ results = webs.weather(location, language)
320
+ _print_weather(results)
321
+ except Exception as e:
308
322
  raise e
309
323
 
310
324
  def main():
@@ -312,7 +326,6 @@ def main():
312
326
  try:
313
327
  app.run()
314
328
  except Exception as e:
315
- logger.error(f"Error: {e}")
316
329
  sys.exit(1)
317
330
 
318
331
  if __name__ == "__main__":
webscout/conversation.py CHANGED
@@ -1,13 +1,6 @@
1
1
  import os
2
- import logging
3
2
  from typing import Optional
4
- from .Litlogger import Logger, LogFormat
5
3
 
6
- # Create a logger instance for this module
7
- logger = Logger(
8
- name="Conversation",
9
- format=LogFormat.MODERN_EMOJI,
10
- )
11
4
 
12
5
  class Conversation:
13
6
  """Handles prompt generation based on history and maintains chat context.
@@ -79,11 +72,9 @@ class Conversation:
79
72
  ), f"File '{filepath}' does not exist"
80
73
 
81
74
  if not os.path.isfile(filepath):
82
- logging.debug(f"Creating new chat-history file - '{filepath}'")
83
75
  with open(filepath, "w", encoding="utf-8") as fh:
84
76
  fh.write(self.intro)
85
77
  else:
86
- logging.debug(f"Loading conversation from '{filepath}'")
87
78
  with open(filepath, encoding="utf-8") as fh:
88
79
  file_contents = fh.readlines()
89
80
  if file_contents:
@@ -221,7 +212,7 @@ class Conversation:
221
212
  if role in role_formats:
222
213
  self.chat_history += f"\n{role_formats[role]} : {content}"
223
214
  else:
224
- logger.warning(f"Unknown role '{role}' for message: {content}")
215
+ raise ValueError(f"Invalid role: {role}. Must be one of {list(role_formats.keys())}")
225
216
 
226
217
  # # Enhanced logging for message addition
227
218
  # logger.info(f"Added message from {role}: {content}")
@@ -22,8 +22,8 @@ Examples:
22
22
  """
23
23
 
24
24
  from .agent import LitAgent
25
- from .constants import BROWSERS, OS_VERSIONS, DEVICES
25
+ from .constants import BROWSERS, OS_VERSIONS, DEVICES, FINGERPRINTS
26
26
 
27
27
  agent = LitAgent()
28
28
 
29
- __all__ = ['LitAgent', 'agent', 'BROWSERS', 'OS_VERSIONS', 'DEVICES']
29
+ __all__ = ['LitAgent', 'agent', 'BROWSERS', 'OS_VERSIONS', 'DEVICES', 'FINGERPRINTS']
@@ -1,21 +1,31 @@
1
1
  """Main LitAgent implementation."""
2
2
 
3
3
  import random
4
- from typing import List
5
- from webscout.Litlogger import Logger, LogFormat
6
- from webscout.litagent.constants import BROWSERS, OS_VERSIONS, DEVICES
4
+ import threading
5
+ from typing import List, Dict, Any, Optional
6
+
7
+ from webscout.litagent.constants import BROWSERS, OS_VERSIONS, DEVICES, FINGERPRINTS
7
8
 
8
- logger = Logger(
9
- name="LitAgent",
10
- format=LogFormat.MODERN_EMOJI,
11
- )
12
9
 
13
10
  class LitAgent:
14
11
  """A lit user agent generator that keeps it fresh! ๐ŸŒŸ"""
15
12
 
16
- def __init__(self):
17
- """Initialize LitAgent with style! ๐Ÿ’ซ"""
13
+ def __init__(self, thread_safe: bool = False):
14
+ """Initialize LitAgent with style! ๐Ÿ’ซ
15
+
16
+ Args:
17
+ thread_safe (bool): Enable thread-safety for multi-threaded applications
18
+ """
18
19
  self.agents = self._generate_agents(100) # Keep 100 agents in memory
20
+ self.thread_safe = thread_safe
21
+ self.lock = threading.RLock() if thread_safe else None
22
+ self._refresh_timer = None
23
+ self._stats = {
24
+ "total_generated": 100,
25
+ "requests_served": 0,
26
+ "browser_usage": {browser: 0 for browser in BROWSERS.keys()},
27
+ "device_usage": {device: 0 for device in DEVICES.keys()}
28
+ }
19
29
 
20
30
  def _generate_agents(self, count: int) -> List[str]:
21
31
  """Generate some lit user agents! ๐Ÿ› ๏ธ"""
@@ -24,7 +34,7 @@ class LitAgent:
24
34
  browser = random.choice(list(BROWSERS.keys()))
25
35
  version = random.randint(*BROWSERS[browser])
26
36
 
27
- if browser in ['chrome', 'firefox', 'edge', 'opera']:
37
+ if browser in ['chrome', 'firefox', 'edge', 'opera', 'brave', 'vivaldi']:
28
38
  os_type = random.choice(['windows', 'mac', 'linux'])
29
39
  os_ver = random.choice(OS_VERSIONS[os_type])
30
40
 
@@ -44,6 +54,10 @@ class LitAgent:
44
54
  agent += f"Edge/{version}.0.0.0"
45
55
  elif browser == 'opera':
46
56
  agent += f"OPR/{version}.0.0.0"
57
+ elif browser == 'brave':
58
+ agent += f"Chrome/{version}.0.0.0 Safari/537.36 Brave/{version}.0.0.0"
59
+ elif browser == 'vivaldi':
60
+ agent += f"Chrome/{version}.0.0.0 Safari/537.36 Vivaldi/{version}.0.{random.randint(1000, 9999)}"
47
61
 
48
62
  elif browser == 'safari':
49
63
  device = random.choice(['mac', 'ios'])
@@ -60,29 +74,127 @@ class LitAgent:
60
74
 
61
75
  return list(set(agents)) # Remove any duplicates
62
76
 
77
+ def _update_stats(self, browser_type=None, device_type=None):
78
+ """Update usage statistics."""
79
+ if self.thread_safe and self.lock:
80
+ with self.lock:
81
+ self._stats["requests_served"] += 1
82
+ if browser_type:
83
+ self._stats["browser_usage"][browser_type] = self._stats["browser_usage"].get(browser_type, 0) + 1
84
+ if device_type:
85
+ self._stats["device_usage"][device_type] = self._stats["device_usage"].get(device_type, 0) + 1
86
+ else:
87
+ self._stats["requests_served"] += 1
88
+ if browser_type:
89
+ self._stats["browser_usage"][browser_type] = self._stats["browser_usage"].get(browser_type, 0) + 1
90
+ if device_type:
91
+ self._stats["device_usage"][device_type] = self._stats["device_usage"].get(device_type, 0) + 1
92
+
63
93
  def random(self) -> str:
64
94
  """Get a random user agent! ๐ŸŽฒ"""
65
- return random.choice(self.agents)
95
+ if self.thread_safe and self.lock:
96
+ with self.lock:
97
+ agent = random.choice(self.agents)
98
+ self._update_stats()
99
+ return agent
100
+ else:
101
+ agent = random.choice(self.agents)
102
+ self._update_stats()
103
+ return agent
66
104
 
67
105
  def browser(self, name: str) -> str:
68
106
  """Get a browser-specific agent! ๐ŸŒ"""
69
107
  name = name.lower()
70
108
  if name not in BROWSERS:
71
- logger.warning(f"Unknown browser: {name} - Using random browser")
72
109
  return self.random()
73
110
 
74
- agents = [a for a in self.agents if name in a.lower()]
75
- return random.choice(agents) if agents else self.random()
111
+ if self.thread_safe and self.lock:
112
+ with self.lock:
113
+ agents = [a for a in self.agents if name in a.lower()]
114
+ agent = random.choice(agents) if agents else self.random()
115
+ self._update_stats(browser_type=name)
116
+ return agent
117
+ else:
118
+ agents = [a for a in self.agents if name in a.lower()]
119
+ agent = random.choice(agents) if agents else self.random()
120
+ self._update_stats(browser_type=name)
121
+ return agent
76
122
 
77
123
  def mobile(self) -> str:
78
124
  """Get a mobile device agent! ๐Ÿ“ฑ"""
79
- agents = [a for a in self.agents if any(d in a for d in DEVICES['mobile'])]
80
- return random.choice(agents) if agents else self.random()
125
+ if self.thread_safe and self.lock:
126
+ with self.lock:
127
+ agents = [a for a in self.agents if any(d in a for d in DEVICES['mobile'])]
128
+ agent = random.choice(agents) if agents else self.random()
129
+ self._update_stats(device_type="mobile")
130
+ return agent
131
+ else:
132
+ agents = [a for a in self.agents if any(d in a for d in DEVICES['mobile'])]
133
+ agent = random.choice(agents) if agents else self.random()
134
+ self._update_stats(device_type="mobile")
135
+ return agent
81
136
 
82
137
  def desktop(self) -> str:
83
138
  """Get a desktop agent! ๐Ÿ’ป"""
84
- agents = [a for a in self.agents if 'Windows' in a or 'Macintosh' in a or 'Linux' in a]
85
- return random.choice(agents) if agents else self.random()
139
+ if self.thread_safe and self.lock:
140
+ with self.lock:
141
+ agents = [a for a in self.agents if 'Windows' in a or 'Macintosh' in a or 'Linux' in a]
142
+ agent = random.choice(agents) if agents else self.random()
143
+ self._update_stats(device_type="desktop")
144
+ return agent
145
+ else:
146
+ agents = [a for a in self.agents if 'Windows' in a or 'Macintosh' in a or 'Linux' in a]
147
+ agent = random.choice(agents) if agents else self.random()
148
+ self._update_stats(device_type="desktop")
149
+ return agent
150
+
151
+ def tablet(self) -> str:
152
+ """Get a tablet agent! ๐Ÿ“ฑ"""
153
+ if self.thread_safe and self.lock:
154
+ with self.lock:
155
+ # Focus on iPad and Android tablets
156
+ agents = [a for a in self.agents if 'iPad' in a or 'Android' in a and not 'Mobile' in a]
157
+ agent = random.choice(agents) if agents else self.random()
158
+ self._update_stats(device_type="tablet")
159
+ return agent
160
+ else:
161
+ agents = [a for a in self.agents if 'iPad' in a or 'Android' in a and not 'Mobile' in a]
162
+ agent = random.choice(agents) if agents else self.random()
163
+ self._update_stats(device_type="tablet")
164
+ return agent
165
+
166
+ def smart_tv(self) -> str:
167
+ """Get a Smart TV agent! ๐Ÿ“บ"""
168
+ # Create a TV-specific agent since they may not be in our standard pool
169
+ tv_type = random.choice(DEVICES['tv'])
170
+ if 'Samsung' in tv_type:
171
+ agent = f"Mozilla/5.0 (SMART-TV; SAMSUNG; {tv_type}; Tizen 5.5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.38 Safari/537.36"
172
+ elif 'LG' in tv_type:
173
+ agent = f"Mozilla/5.0 (Web0S; {tv_type}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
174
+ elif 'Android' in tv_type:
175
+ agent = f"Mozilla/5.0 (Linux; Android 9; {tv_type}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
176
+ elif 'Apple' in tv_type:
177
+ agent = f"Mozilla/5.0 (AppleTV; CPU like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
178
+ else:
179
+ agent = f"Mozilla/5.0 (Linux; {tv_type}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
180
+
181
+ self._update_stats(device_type="tv")
182
+ return agent
183
+
184
+ def gaming(self) -> str:
185
+ """Get a gaming console agent! ๐ŸŽฎ"""
186
+ console_type = random.choice(DEVICES['console'])
187
+ if 'PlayStation' in console_type:
188
+ agent = f"Mozilla/5.0 ({console_type}/5.0) AppleWebKit/601.2 (KHTML, like Gecko)"
189
+ elif 'Xbox' in console_type:
190
+ agent = f"Mozilla/5.0 ({console_type}; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19041"
191
+ elif 'Nintendo' in console_type:
192
+ agent = f"Mozilla/5.0 (Nintendo Switch; {console_type}) AppleWebKit/601.6 (KHTML, like Gecko) NintendoBrowser/5.1.0.13343"
193
+ else:
194
+ agent = self.random()
195
+
196
+ self._update_stats(device_type="console")
197
+ return agent
86
198
 
87
199
  def chrome(self) -> str:
88
200
  """Get a Chrome agent! ๐ŸŒ"""
@@ -103,10 +215,225 @@ class LitAgent:
103
215
  def opera(self) -> str:
104
216
  """Get an Opera agent! ๐ŸŽญ"""
105
217
  return self.browser('opera')
218
+
219
+ def brave(self) -> str:
220
+ """Get a Brave agent! ๐Ÿฆ"""
221
+ return self.browser('brave')
222
+
223
+ def vivaldi(self) -> str:
224
+ """Get a Vivaldi agent! ๐ŸŽจ"""
225
+ return self.browser('vivaldi')
226
+
227
+ # OS-specific agents
228
+ def windows(self) -> str:
229
+ """Get a Windows agent! ๐ŸชŸ"""
230
+ agents = [a for a in self.agents if 'Windows' in a]
231
+ agent = random.choice(agents) if agents else self.random()
232
+ self._update_stats()
233
+ return agent
234
+
235
+ def macos(self) -> str:
236
+ """Get a macOS agent! ๐ŸŽ"""
237
+ agents = [a for a in self.agents if 'Macintosh' in a]
238
+ agent = random.choice(agents) if agents else self.random()
239
+ self._update_stats()
240
+ return agent
241
+
242
+ def linux(self) -> str:
243
+ """Get a Linux agent! ๐Ÿง"""
244
+ agents = [a for a in self.agents if 'Linux' in a and 'Android' not in a]
245
+ agent = random.choice(agents) if agents else self.random()
246
+ self._update_stats()
247
+ return agent
248
+
249
+ def android(self) -> str:
250
+ """Get an Android agent! ๐Ÿค–"""
251
+ agents = [a for a in self.agents if 'Android' in a]
252
+ agent = random.choice(agents) if agents else self.random()
253
+ self._update_stats()
254
+ return agent
255
+
256
+ def ios(self) -> str:
257
+ """Get an iOS agent! ๐Ÿ“ฑ"""
258
+ agents = [a for a in self.agents if 'iPhone' in a or 'iPad' in a]
259
+ agent = random.choice(agents) if agents else self.random()
260
+ self._update_stats()
261
+ return agent
262
+
263
+ def custom(self, browser: str, version: Optional[str] = None,
264
+ os: Optional[str] = None, os_version: Optional[str] = None,
265
+ device_type: Optional[str] = None) -> str:
266
+ """Generate a custom user agent with specified parameters! ๐Ÿ› ๏ธ
267
+
268
+ Args:
269
+ browser: Browser name (chrome, firefox, safari, edge, opera)
270
+ version: Browser version (optional)
271
+ os: Operating system (windows, mac, linux, android, ios)
272
+ os_version: OS version (optional)
273
+ device_type: Device type (desktop, mobile, tablet)
274
+
275
+ Returns:
276
+ Customized user agent string
277
+ """
278
+ browser = browser.lower() if browser else 'chrome'
279
+ if browser not in BROWSERS:
280
+ browser = 'chrome'
281
+
282
+ if version:
283
+ try:
284
+ version_num = int(version.split('.')[0])
285
+ except (ValueError, IndexError):
286
+ version_num = random.randint(*BROWSERS[browser])
287
+ else:
288
+ version_num = random.randint(*BROWSERS[browser])
289
+
290
+ os = os.lower() if os else random.choice(['windows', 'mac', 'linux'])
291
+ if os not in OS_VERSIONS:
292
+ os = 'windows'
293
+
294
+ os_ver = os_version or random.choice(OS_VERSIONS[os])
295
+
296
+ device_type = device_type.lower() if device_type else 'desktop'
297
+
298
+ # Build the user agent
299
+ if os == 'windows':
300
+ platform = f"Windows NT {os_ver}"
301
+ elif os == 'mac':
302
+ platform = f"Macintosh; Intel Mac OS X {os_ver}"
303
+ elif os == 'linux':
304
+ platform = f"X11; Linux {OS_VERSIONS['linux'][0]}"
305
+ elif os == 'android':
306
+ platform = f"Linux; Android {os_ver}; {random.choice(DEVICES['mobile'])}"
307
+ elif os == 'ios':
308
+ device = 'iPhone' if device_type == 'mobile' else 'iPad'
309
+ platform = f"{device}; CPU OS {os_ver} like Mac OS X"
310
+ else:
311
+ platform = f"Windows NT 10.0" # Default fallback
312
+
313
+ agent = f"Mozilla/5.0 ({platform}) AppleWebKit/537.36 (KHTML, like Gecko) "
314
+
315
+ if browser == 'chrome':
316
+ agent += f"Chrome/{version_num}.0.0.0 Safari/537.36"
317
+ elif browser == 'firefox':
318
+ agent += f"Firefox/{version_num}.0"
319
+ elif browser == 'safari':
320
+ safari_ver = random.randint(*BROWSERS['safari'])
321
+ agent += f"Version/{version_num}.0 Safari/{safari_ver}.0"
322
+ elif browser == 'edge':
323
+ agent += f"Chrome/{version_num}.0.0.0 Safari/537.36 Edg/{version_num}.0.0.0"
324
+ elif browser == 'opera':
325
+ agent += f"Chrome/{version_num}.0.0.0 Safari/537.36 OPR/{version_num}.0.0.0"
326
+ elif browser == 'brave':
327
+ agent += f"Chrome/{version_num}.0.0.0 Safari/537.36 Brave/{version_num}.1.0"
328
+
329
+ self._update_stats(browser_type=browser, device_type=device_type)
330
+ return agent
331
+
332
+ def generate_fingerprint(self, browser: Optional[str] = None) -> Dict[str, str]:
333
+ """Generate a consistent browser fingerprint! ๐Ÿ‘†
334
+
335
+ This creates a coherent set of headers for anti-fingerprinting.
336
+
337
+ Args:
338
+ browser: Specific browser to generate fingerprint for
339
+
340
+ Returns:
341
+ Dictionary with fingerprinting headers
342
+ """
343
+ # Get a random user agent using the random() method
344
+ user_agent = self.random()
345
+
346
+ # If browser is specified, try to get a matching one
347
+ if browser:
348
+ browser = browser.lower()
349
+ if browser in BROWSERS:
350
+ user_agent = self.browser(browser)
351
+
352
+ accept_language = random.choice(FINGERPRINTS["accept_language"])
353
+ accept = random.choice(FINGERPRINTS["accept"])
354
+ platform = random.choice(FINGERPRINTS["platforms"])
355
+
356
+ # Generate sec-ch-ua based on the user agent
357
+ sec_ch_ua = ""
358
+ for browser_name in FINGERPRINTS["sec_ch_ua"]:
359
+ if browser_name in user_agent.lower():
360
+ version = random.randint(*BROWSERS[browser_name])
361
+ sec_ch_ua = FINGERPRINTS["sec_ch_ua"][browser_name].format(version, version)
362
+ break
363
+
364
+ fingerprint = {
365
+ "user_agent": user_agent,
366
+ "accept_language": accept_language,
367
+ "accept": accept,
368
+ "sec_ch_ua": sec_ch_ua,
369
+ "platform": platform
370
+ }
371
+
372
+ self._update_stats(browser_type=browser)
373
+ return fingerprint
106
374
 
107
375
  def refresh(self) -> None:
108
376
  """Refresh the agents with new ones! ๐Ÿ”„"""
109
- self.agents = self._generate_agents(100)
377
+ if self.thread_safe and self.lock:
378
+ with self.lock:
379
+ self.agents = self._generate_agents(100)
380
+ self._stats["total_generated"] += 100
381
+ else:
382
+ self.agents = self._generate_agents(100)
383
+ self._stats["total_generated"] += 100
384
+
385
+
386
+ def auto_refresh(self, interval_minutes: int = 30) -> None:
387
+ """Set up automatic refreshing of agents pool! โฑ๏ธ
388
+
389
+ Args:
390
+ interval_minutes: Minutes between refreshes
391
+ """
392
+ if self._refresh_timer:
393
+ self._refresh_timer.cancel()
394
+
395
+ def _refresh_task():
396
+ self.refresh()
397
+ self._refresh_timer = threading.Timer(interval_minutes * 60, _refresh_task)
398
+ self._refresh_timer.daemon = True
399
+ self._refresh_timer.start()
400
+
401
+ self._refresh_timer = threading.Timer(interval_minutes * 60, _refresh_task)
402
+ self._refresh_timer.daemon = True
403
+ self._refresh_timer.start()
404
+
405
+ def get_stats(self) -> Dict[str, Any]:
406
+ """Get statistics about agent usage! ๐Ÿ“Š
407
+
408
+ Returns:
409
+ Dictionary with usage statistics
410
+ """
411
+ stats_copy = self._stats.copy()
412
+ # Calculate top browser
413
+ top_browser = max(stats_copy["browser_usage"].items(), key=lambda x: x[1])[0] if stats_copy["browser_usage"] else None
414
+ stats_copy["top_browser"] = top_browser
415
+
416
+ # Calculate fake detection avoidance rate (just for fun)
417
+ stats_copy["avoidance_rate"] = min(99.9, 90 + (stats_copy["total_generated"] / 1000))
418
+
419
+ return stats_copy
420
+
421
+ def export_stats(self, filename: str) -> bool:
422
+ """Export usage statistics to a file! ๐Ÿ’พ
423
+
424
+ Args:
425
+ filename: Path to export the stats
426
+
427
+ Returns:
428
+ True if export was successful, False otherwise
429
+ """
430
+ try:
431
+ import json
432
+ with open(filename, 'w') as f:
433
+ json.dump(self.get_stats(), f, indent=2)
434
+ return True
435
+ except Exception as e:
436
+ return False
110
437
 
111
438
  if __name__ == "__main__":
112
439
  # Test it out! ๐Ÿงช
@@ -116,4 +443,13 @@ if __name__ == "__main__":
116
443
  print("Firefox:", agent.firefox())
117
444
  print("Safari:", agent.safari())
118
445
  print("Mobile:", agent.mobile())
119
- print("Desktop:", agent.desktop())
446
+ print("Desktop:", agent.desktop())
447
+ print("Tablet:", agent.tablet())
448
+ print("Smart TV:", agent.smart_tv())
449
+ print("Gaming:", agent.gaming())
450
+
451
+ # Test custom agent
452
+ print("Custom:", agent.custom(browser="chrome", os="windows", os_version="10.0"))
453
+
454
+ # Test fingerprinting
455
+ print("Fingerprint:", agent.generate_fingerprint("chrome"))