webscout 8.3.6__py3-none-any.whl → 2025.10.11__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.
- webscout/AIauto.py +250 -250
- webscout/AIbase.py +379 -379
- webscout/AIutel.py +60 -58
- webscout/Bard.py +1012 -1012
- webscout/Bing_search.py +417 -417
- webscout/DWEBS.py +529 -529
- webscout/Extra/Act.md +309 -309
- webscout/Extra/GitToolkit/__init__.py +10 -10
- webscout/Extra/GitToolkit/gitapi/README.md +110 -110
- webscout/Extra/GitToolkit/gitapi/__init__.py +11 -11
- webscout/Extra/GitToolkit/gitapi/repository.py +195 -195
- webscout/Extra/GitToolkit/gitapi/user.py +96 -96
- webscout/Extra/GitToolkit/gitapi/utils.py +61 -61
- webscout/Extra/YTToolkit/README.md +375 -375
- webscout/Extra/YTToolkit/YTdownloader.py +956 -956
- webscout/Extra/YTToolkit/__init__.py +2 -2
- webscout/Extra/YTToolkit/transcriber.py +475 -475
- webscout/Extra/YTToolkit/ytapi/README.md +44 -44
- webscout/Extra/YTToolkit/ytapi/__init__.py +6 -6
- webscout/Extra/YTToolkit/ytapi/channel.py +307 -307
- webscout/Extra/YTToolkit/ytapi/errors.py +13 -13
- webscout/Extra/YTToolkit/ytapi/extras.py +118 -118
- webscout/Extra/YTToolkit/ytapi/https.py +88 -88
- webscout/Extra/YTToolkit/ytapi/patterns.py +61 -61
- webscout/Extra/YTToolkit/ytapi/playlist.py +58 -58
- webscout/Extra/YTToolkit/ytapi/pool.py +7 -7
- webscout/Extra/YTToolkit/ytapi/query.py +39 -39
- webscout/Extra/YTToolkit/ytapi/stream.py +62 -62
- webscout/Extra/YTToolkit/ytapi/utils.py +62 -62
- webscout/Extra/YTToolkit/ytapi/video.py +232 -232
- webscout/Extra/autocoder/__init__.py +9 -9
- webscout/Extra/autocoder/autocoder.py +1105 -1105
- webscout/Extra/autocoder/autocoder_utiles.py +332 -332
- webscout/Extra/gguf.md +429 -429
- webscout/Extra/gguf.py +1213 -1213
- webscout/Extra/tempmail/README.md +487 -487
- webscout/Extra/tempmail/__init__.py +27 -27
- webscout/Extra/tempmail/async_utils.py +140 -140
- webscout/Extra/tempmail/base.py +160 -160
- webscout/Extra/tempmail/cli.py +186 -186
- webscout/Extra/tempmail/emailnator.py +84 -84
- webscout/Extra/tempmail/mail_tm.py +360 -360
- webscout/Extra/tempmail/temp_mail_io.py +291 -291
- webscout/Extra/weather.md +281 -281
- webscout/Extra/weather.py +193 -193
- webscout/Litlogger/README.md +10 -10
- webscout/Litlogger/__init__.py +15 -15
- webscout/Litlogger/formats.py +13 -13
- webscout/Litlogger/handlers.py +121 -121
- webscout/Litlogger/levels.py +13 -13
- webscout/Litlogger/logger.py +134 -134
- webscout/Provider/AISEARCH/Perplexity.py +332 -332
- webscout/Provider/AISEARCH/README.md +279 -279
- webscout/Provider/AISEARCH/__init__.py +33 -11
- webscout/Provider/AISEARCH/felo_search.py +206 -206
- webscout/Provider/AISEARCH/genspark_search.py +323 -323
- webscout/Provider/AISEARCH/hika_search.py +185 -185
- webscout/Provider/AISEARCH/iask_search.py +410 -410
- webscout/Provider/AISEARCH/monica_search.py +219 -219
- webscout/Provider/AISEARCH/scira_search.py +316 -314
- webscout/Provider/AISEARCH/stellar_search.py +177 -177
- webscout/Provider/AISEARCH/webpilotai_search.py +255 -255
- webscout/Provider/Aitopia.py +314 -315
- webscout/Provider/Andi.py +3 -3
- webscout/Provider/Apriel.py +306 -0
- webscout/Provider/ChatGPTClone.py +236 -236
- webscout/Provider/ChatSandbox.py +343 -342
- webscout/Provider/Cloudflare.py +324 -324
- webscout/Provider/Cohere.py +208 -207
- webscout/Provider/Deepinfra.py +370 -369
- webscout/Provider/ExaAI.py +260 -260
- webscout/Provider/ExaChat.py +308 -387
- webscout/Provider/Flowith.py +221 -221
- webscout/Provider/GMI.py +293 -0
- webscout/Provider/Gemini.py +164 -162
- webscout/Provider/GeminiProxy.py +167 -166
- webscout/Provider/GithubChat.py +371 -370
- webscout/Provider/Groq.py +800 -800
- webscout/Provider/HeckAI.py +383 -379
- webscout/Provider/Jadve.py +282 -297
- webscout/Provider/K2Think.py +308 -0
- webscout/Provider/Koboldai.py +206 -384
- webscout/Provider/LambdaChat.py +423 -425
- webscout/Provider/Nemotron.py +244 -245
- webscout/Provider/Netwrck.py +248 -247
- webscout/Provider/OLLAMA.py +395 -394
- webscout/Provider/OPENAI/Cloudflare.py +394 -395
- webscout/Provider/OPENAI/FalconH1.py +452 -457
- webscout/Provider/OPENAI/FreeGemini.py +297 -299
- webscout/Provider/OPENAI/{monochat.py → K2Think.py} +432 -329
- webscout/Provider/OPENAI/NEMOTRON.py +241 -244
- webscout/Provider/OPENAI/PI.py +428 -427
- webscout/Provider/OPENAI/README.md +959 -959
- webscout/Provider/OPENAI/TogetherAI.py +345 -345
- webscout/Provider/OPENAI/TwoAI.py +466 -467
- webscout/Provider/OPENAI/__init__.py +33 -59
- webscout/Provider/OPENAI/ai4chat.py +313 -303
- webscout/Provider/OPENAI/base.py +249 -269
- webscout/Provider/OPENAI/chatglm.py +528 -0
- webscout/Provider/OPENAI/chatgpt.py +593 -588
- webscout/Provider/OPENAI/chatgptclone.py +521 -524
- webscout/Provider/OPENAI/chatsandbox.py +202 -177
- webscout/Provider/OPENAI/deepinfra.py +319 -315
- webscout/Provider/OPENAI/e2b.py +1665 -1665
- webscout/Provider/OPENAI/exaai.py +420 -420
- webscout/Provider/OPENAI/exachat.py +452 -452
- webscout/Provider/OPENAI/friendli.py +232 -232
- webscout/Provider/OPENAI/{refact.py → gmi.py} +324 -274
- webscout/Provider/OPENAI/groq.py +364 -364
- webscout/Provider/OPENAI/heckai.py +314 -311
- webscout/Provider/OPENAI/llmchatco.py +337 -337
- webscout/Provider/OPENAI/netwrck.py +355 -354
- webscout/Provider/OPENAI/oivscode.py +290 -290
- webscout/Provider/OPENAI/opkfc.py +518 -518
- webscout/Provider/OPENAI/pydantic_imports.py +1 -1
- webscout/Provider/OPENAI/scirachat.py +535 -529
- webscout/Provider/OPENAI/sonus.py +308 -308
- webscout/Provider/OPENAI/standardinput.py +442 -442
- webscout/Provider/OPENAI/textpollinations.py +340 -348
- webscout/Provider/OPENAI/toolbaz.py +419 -413
- webscout/Provider/OPENAI/typefully.py +362 -362
- webscout/Provider/OPENAI/utils.py +295 -295
- webscout/Provider/OPENAI/venice.py +436 -436
- webscout/Provider/OPENAI/wisecat.py +387 -387
- webscout/Provider/OPENAI/writecream.py +166 -166
- webscout/Provider/OPENAI/x0gpt.py +378 -378
- webscout/Provider/OPENAI/yep.py +389 -389
- webscout/Provider/OpenGPT.py +230 -230
- webscout/Provider/Openai.py +244 -496
- webscout/Provider/PI.py +405 -404
- webscout/Provider/Perplexitylabs.py +430 -431
- webscout/Provider/QwenLM.py +272 -254
- webscout/Provider/STT/__init__.py +32 -2
- webscout/Provider/{Llama3.py → Sambanova.py} +257 -258
- webscout/Provider/StandardInput.py +309 -309
- webscout/Provider/TTI/README.md +82 -82
- webscout/Provider/TTI/__init__.py +33 -12
- webscout/Provider/TTI/aiarta.py +413 -413
- webscout/Provider/TTI/base.py +136 -136
- webscout/Provider/TTI/bing.py +243 -243
- webscout/Provider/TTI/gpt1image.py +149 -149
- webscout/Provider/TTI/imagen.py +196 -196
- webscout/Provider/TTI/infip.py +211 -211
- webscout/Provider/TTI/magicstudio.py +232 -232
- webscout/Provider/TTI/monochat.py +219 -219
- webscout/Provider/TTI/piclumen.py +214 -214
- webscout/Provider/TTI/pixelmuse.py +232 -232
- webscout/Provider/TTI/pollinations.py +232 -232
- webscout/Provider/TTI/together.py +288 -288
- webscout/Provider/TTI/utils.py +12 -12
- webscout/Provider/TTI/venice.py +367 -367
- webscout/Provider/TTS/README.md +192 -192
- webscout/Provider/TTS/__init__.py +33 -10
- webscout/Provider/TTS/parler.py +110 -110
- webscout/Provider/TTS/streamElements.py +333 -333
- webscout/Provider/TTS/utils.py +280 -280
- webscout/Provider/TeachAnything.py +237 -236
- webscout/Provider/TextPollinationsAI.py +311 -318
- webscout/Provider/TogetherAI.py +356 -357
- webscout/Provider/TwoAI.py +313 -569
- webscout/Provider/TypliAI.py +312 -311
- webscout/Provider/UNFINISHED/ChatHub.py +208 -208
- webscout/Provider/UNFINISHED/ChutesAI.py +313 -313
- webscout/Provider/{GizAI.py → UNFINISHED/GizAI.py} +294 -294
- webscout/Provider/{Marcus.py → UNFINISHED/Marcus.py} +198 -198
- webscout/Provider/{Qodo.py → UNFINISHED/Qodo.py} +477 -477
- webscout/Provider/UNFINISHED/VercelAIGateway.py +338 -338
- webscout/Provider/{XenAI.py → UNFINISHED/XenAI.py} +324 -324
- webscout/Provider/UNFINISHED/Youchat.py +330 -330
- webscout/Provider/UNFINISHED/liner.py +334 -0
- webscout/Provider/UNFINISHED/liner_api_request.py +262 -262
- webscout/Provider/UNFINISHED/puterjs.py +634 -634
- webscout/Provider/UNFINISHED/samurai.py +223 -223
- webscout/Provider/UNFINISHED/test_lmarena.py +119 -119
- webscout/Provider/Venice.py +251 -250
- webscout/Provider/VercelAI.py +256 -255
- webscout/Provider/WiseCat.py +232 -231
- webscout/Provider/WrDoChat.py +367 -366
- webscout/Provider/__init__.py +33 -86
- webscout/Provider/ai4chat.py +174 -174
- webscout/Provider/akashgpt.py +331 -334
- webscout/Provider/cerebras.py +446 -340
- webscout/Provider/chatglm.py +394 -214
- webscout/Provider/cleeai.py +211 -212
- webscout/Provider/deepseek_assistant.py +1 -1
- webscout/Provider/elmo.py +282 -282
- webscout/Provider/geminiapi.py +208 -208
- webscout/Provider/granite.py +261 -261
- webscout/Provider/hermes.py +263 -265
- webscout/Provider/julius.py +223 -222
- webscout/Provider/learnfastai.py +309 -309
- webscout/Provider/llama3mitril.py +214 -214
- webscout/Provider/llmchat.py +243 -243
- webscout/Provider/llmchatco.py +290 -290
- webscout/Provider/meta.py +801 -801
- webscout/Provider/oivscode.py +309 -309
- webscout/Provider/scira_chat.py +384 -457
- webscout/Provider/searchchat.py +292 -291
- webscout/Provider/sonus.py +258 -258
- webscout/Provider/toolbaz.py +370 -364
- webscout/Provider/turboseek.py +274 -265
- webscout/Provider/typefully.py +208 -207
- webscout/Provider/x0gpt.py +1 -0
- webscout/Provider/yep.py +372 -371
- webscout/__init__.py +30 -31
- webscout/__main__.py +5 -5
- webscout/auth/api_key_manager.py +189 -189
- webscout/auth/config.py +175 -175
- webscout/auth/models.py +185 -185
- webscout/auth/routes.py +664 -664
- webscout/auth/simple_logger.py +236 -236
- webscout/cli.py +523 -523
- webscout/conversation.py +438 -438
- webscout/exceptions.py +361 -361
- webscout/litagent/Readme.md +298 -298
- webscout/litagent/__init__.py +28 -28
- webscout/litagent/agent.py +581 -581
- webscout/litagent/constants.py +59 -59
- webscout/litprinter/__init__.py +58 -58
- webscout/models.py +181 -181
- webscout/optimizers.py +419 -419
- webscout/prompt_manager.py +288 -288
- webscout/sanitize.py +1078 -1078
- webscout/scout/README.md +401 -401
- webscout/scout/__init__.py +8 -8
- webscout/scout/core/__init__.py +6 -6
- webscout/scout/core/crawler.py +297 -297
- webscout/scout/core/scout.py +706 -706
- webscout/scout/core/search_result.py +95 -95
- webscout/scout/core/text_analyzer.py +62 -62
- webscout/scout/core/text_utils.py +277 -277
- webscout/scout/core/web_analyzer.py +51 -51
- webscout/scout/element.py +599 -599
- webscout/scout/parsers/__init__.py +69 -69
- webscout/scout/parsers/html5lib_parser.py +172 -172
- webscout/scout/parsers/html_parser.py +236 -236
- webscout/scout/parsers/lxml_parser.py +178 -178
- webscout/scout/utils.py +37 -37
- webscout/swiftcli/Readme.md +323 -323
- webscout/swiftcli/__init__.py +95 -95
- webscout/swiftcli/core/__init__.py +7 -7
- webscout/swiftcli/core/cli.py +308 -308
- webscout/swiftcli/core/context.py +104 -104
- webscout/swiftcli/core/group.py +241 -241
- webscout/swiftcli/decorators/__init__.py +28 -28
- webscout/swiftcli/decorators/command.py +221 -221
- webscout/swiftcli/decorators/options.py +220 -220
- webscout/swiftcli/decorators/output.py +302 -302
- webscout/swiftcli/exceptions.py +21 -21
- webscout/swiftcli/plugins/__init__.py +9 -9
- webscout/swiftcli/plugins/base.py +135 -135
- webscout/swiftcli/plugins/manager.py +269 -269
- webscout/swiftcli/utils/__init__.py +59 -59
- webscout/swiftcli/utils/formatting.py +252 -252
- webscout/swiftcli/utils/parsing.py +267 -267
- webscout/update_checker.py +117 -117
- webscout/version.py +1 -1
- webscout/webscout_search.py +1183 -1183
- webscout/webscout_search_async.py +649 -649
- webscout/yep_search.py +346 -346
- webscout/zeroart/README.md +89 -89
- webscout/zeroart/__init__.py +134 -134
- webscout/zeroart/base.py +66 -66
- webscout/zeroart/effects.py +100 -100
- webscout/zeroart/fonts.py +1238 -1238
- {webscout-8.3.6.dist-info → webscout-2025.10.11.dist-info}/METADATA +937 -936
- webscout-2025.10.11.dist-info/RECORD +300 -0
- webscout/Provider/AISEARCH/DeepFind.py +0 -254
- webscout/Provider/AllenAI.py +0 -440
- webscout/Provider/Blackboxai.py +0 -793
- webscout/Provider/FreeGemini.py +0 -250
- webscout/Provider/GptOss.py +0 -207
- webscout/Provider/Hunyuan.py +0 -283
- webscout/Provider/Kimi.py +0 -445
- webscout/Provider/MCPCore.py +0 -322
- webscout/Provider/MiniMax.py +0 -207
- webscout/Provider/OPENAI/BLACKBOXAI.py +0 -1045
- webscout/Provider/OPENAI/MiniMax.py +0 -298
- webscout/Provider/OPENAI/Qwen3.py +0 -304
- webscout/Provider/OPENAI/autoproxy.py +0 -1067
- webscout/Provider/OPENAI/copilot.py +0 -321
- webscout/Provider/OPENAI/gptoss.py +0 -288
- webscout/Provider/OPENAI/kimi.py +0 -469
- webscout/Provider/OPENAI/mcpcore.py +0 -431
- webscout/Provider/OPENAI/multichat.py +0 -378
- webscout/Provider/OPENAI/qodo.py +0 -630
- webscout/Provider/OPENAI/xenai.py +0 -514
- webscout/Provider/Reka.py +0 -214
- webscout/Provider/UNFINISHED/fetch_together_models.py +0 -90
- webscout/Provider/asksteve.py +0 -220
- webscout/Provider/copilot.py +0 -441
- webscout/Provider/freeaichat.py +0 -294
- webscout/Provider/koala.py +0 -182
- webscout/Provider/lmarena.py +0 -198
- webscout/Provider/monochat.py +0 -275
- webscout/Provider/multichat.py +0 -375
- webscout/Provider/scnet.py +0 -244
- webscout/Provider/talkai.py +0 -194
- webscout/tempid.py +0 -128
- webscout-8.3.6.dist-info/RECORD +0 -327
- {webscout-8.3.6.dist-info → webscout-2025.10.11.dist-info}/WHEEL +0 -0
- {webscout-8.3.6.dist-info → webscout-2025.10.11.dist-info}/entry_points.txt +0 -0
- {webscout-8.3.6.dist-info → webscout-2025.10.11.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.3.6.dist-info → webscout-2025.10.11.dist-info}/top_level.txt +0 -0
|
@@ -1,292 +1,292 @@
|
|
|
1
|
-
"""
|
|
2
|
-
TempMail.io Provider Implementation
|
|
3
|
-
Based on temp-mail.io API
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import aiohttp
|
|
7
|
-
import asyncio
|
|
8
|
-
from dataclasses import dataclass
|
|
9
|
-
from typing import List, Dict, Any, Optional, Union, Tuple, NoReturn
|
|
10
|
-
|
|
11
|
-
from .base import AsyncTempMailProvider, TempMailProvider, generate_random_string
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@dataclass
|
|
15
|
-
class DomainModel:
|
|
16
|
-
"""Domain model for TempMail.io API"""
|
|
17
|
-
name: str
|
|
18
|
-
type: str
|
|
19
|
-
forward_available: str
|
|
20
|
-
forward_max_seconds: str
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@dataclass
|
|
24
|
-
class CreateEmailResponseModel:
|
|
25
|
-
"""Response model for email creation in TempMail.io API"""
|
|
26
|
-
email: str
|
|
27
|
-
token: str
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@dataclass
|
|
31
|
-
class MessageResponseModel:
|
|
32
|
-
"""Message model for TempMail.io API"""
|
|
33
|
-
attachments: Optional[List[Any]]
|
|
34
|
-
body_html: Optional[str]
|
|
35
|
-
body_text: Optional[str]
|
|
36
|
-
cc: Optional[str]
|
|
37
|
-
created_at: str
|
|
38
|
-
email_from: Optional[str]
|
|
39
|
-
id: str
|
|
40
|
-
subject: Optional[str]
|
|
41
|
-
email_to: Optional[str]
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class TempMailIOAsync(AsyncTempMailProvider):
|
|
45
|
-
"""
|
|
46
|
-
TempMail.io API client for temporary email services
|
|
47
|
-
Implements the AsyncTempMailProvider interface
|
|
48
|
-
"""
|
|
49
|
-
|
|
50
|
-
def __init__(self):
|
|
51
|
-
"""Initialize TempMail.io Async client"""
|
|
52
|
-
self._session = None
|
|
53
|
-
self.email = None
|
|
54
|
-
self.token = None
|
|
55
|
-
|
|
56
|
-
async def initialize(self):
|
|
57
|
-
"""Initialize the aiohttp session"""
|
|
58
|
-
self._session = aiohttp.ClientSession(
|
|
59
|
-
base_url="https://api.internal.temp-mail.io",
|
|
60
|
-
headers={
|
|
61
|
-
'Host': 'api.internal.temp-mail.io',
|
|
62
|
-
'User-Agent': 'okhttp/4.5.0',
|
|
63
|
-
'Connection': 'close'
|
|
64
|
-
}
|
|
65
|
-
)
|
|
66
|
-
return self
|
|
67
|
-
|
|
68
|
-
async def close(self) -> None:
|
|
69
|
-
"""Close the aiohttp session"""
|
|
70
|
-
if self._session and not self._session.closed:
|
|
71
|
-
await self._session.close()
|
|
72
|
-
self._session = None
|
|
73
|
-
|
|
74
|
-
async def __aenter__(self):
|
|
75
|
-
"""Context manager entry"""
|
|
76
|
-
return await self.initialize()
|
|
77
|
-
|
|
78
|
-
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
79
|
-
"""Context manager exit"""
|
|
80
|
-
await self.close()
|
|
81
|
-
return None
|
|
82
|
-
|
|
83
|
-
async def get_domains(self) -> List[DomainModel]:
|
|
84
|
-
"""Get available domains"""
|
|
85
|
-
if not self._session:
|
|
86
|
-
await self.initialize()
|
|
87
|
-
|
|
88
|
-
try:
|
|
89
|
-
async with self._session.get("/api/v3/domains") as response:
|
|
90
|
-
response_json = await response.json()
|
|
91
|
-
return [DomainModel(
|
|
92
|
-
domain['name'],
|
|
93
|
-
domain['type'],
|
|
94
|
-
domain['forward_available'],
|
|
95
|
-
domain['forward_max_seconds']
|
|
96
|
-
) for domain in response_json['domains']]
|
|
97
|
-
except Exception:
|
|
98
|
-
return []
|
|
99
|
-
|
|
100
|
-
async def create_email(self, alias: Optional[str] = None, domain: Optional[str] = None) -> Tuple[str, str]:
|
|
101
|
-
"""Create a new temporary email"""
|
|
102
|
-
if not self._session:
|
|
103
|
-
await self.initialize()
|
|
104
|
-
|
|
105
|
-
try:
|
|
106
|
-
async with self._session.post(
|
|
107
|
-
"/api/v3/email/new",
|
|
108
|
-
data={'name': alias, 'domain': domain}
|
|
109
|
-
) as response:
|
|
110
|
-
response_json = await response.json()
|
|
111
|
-
self.email = response_json['email']
|
|
112
|
-
self.token = response_json['token']
|
|
113
|
-
return self.email, self.token
|
|
114
|
-
except Exception:
|
|
115
|
-
return "", ""
|
|
116
|
-
|
|
117
|
-
async def delete_email(self) -> bool:
|
|
118
|
-
"""Delete a temporary email"""
|
|
119
|
-
if not self._session or not self.email or not self.token:
|
|
120
|
-
return False
|
|
121
|
-
|
|
122
|
-
try:
|
|
123
|
-
async with self._session.delete(
|
|
124
|
-
f"/api/v3/email/{self.email}",
|
|
125
|
-
data={'token': self.token}
|
|
126
|
-
) as response:
|
|
127
|
-
success = response.status == 200
|
|
128
|
-
if success:
|
|
129
|
-
self.email = None
|
|
130
|
-
self.token = None
|
|
131
|
-
return success
|
|
132
|
-
except Exception:
|
|
133
|
-
return False
|
|
134
|
-
|
|
135
|
-
async def get_messages(self) -> List[Dict]:
|
|
136
|
-
"""Get messages for a temporary email"""
|
|
137
|
-
if not self._session or not self.email:
|
|
138
|
-
return []
|
|
139
|
-
|
|
140
|
-
try:
|
|
141
|
-
async with self._session.get(f"/api/v3/email/{self.email}/messages") as response:
|
|
142
|
-
response_json = await response.json()
|
|
143
|
-
if len(response_json) == 0:
|
|
144
|
-
return []
|
|
145
|
-
|
|
146
|
-
messages = []
|
|
147
|
-
for message in response_json:
|
|
148
|
-
msg_dict = {
|
|
149
|
-
'msg_id': message['id'],
|
|
150
|
-
'from': message['from'],
|
|
151
|
-
'to': message['to'],
|
|
152
|
-
'subject': message['subject'] if 'subject' in message else "",
|
|
153
|
-
'body': message['body_text'] or message['body_html'],
|
|
154
|
-
'hasAttachments': bool(message['attachments'] and len(message['attachments']) > 0),
|
|
155
|
-
'createdAt': message['created_at']
|
|
156
|
-
}
|
|
157
|
-
messages.append(msg_dict)
|
|
158
|
-
return messages
|
|
159
|
-
except Exception:
|
|
160
|
-
return []
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
class TempMailIO(TempMailProvider):
|
|
164
|
-
"""
|
|
165
|
-
Synchronous implementation for TempMail.io API
|
|
166
|
-
Implements the TempMailProvider interface
|
|
167
|
-
"""
|
|
168
|
-
|
|
169
|
-
def __init__(self, auto_create=False):
|
|
170
|
-
"""
|
|
171
|
-
Initialize TempMail.io client
|
|
172
|
-
|
|
173
|
-
Args:
|
|
174
|
-
auto_create: Automatically create an email upon initialization
|
|
175
|
-
"""
|
|
176
|
-
import requests
|
|
177
|
-
self.session = requests.Session()
|
|
178
|
-
self.session.headers.update({
|
|
179
|
-
'Host': 'api.internal.temp-mail.io',
|
|
180
|
-
'User-Agent': 'okhttp/4.5.0',
|
|
181
|
-
'Connection': 'close'
|
|
182
|
-
})
|
|
183
|
-
self.base_url = "https://api.internal.temp-mail.io"
|
|
184
|
-
self.email = None
|
|
185
|
-
self.token = None
|
|
186
|
-
self.messages_count = 0
|
|
187
|
-
|
|
188
|
-
if auto_create:
|
|
189
|
-
self.create_account()
|
|
190
|
-
|
|
191
|
-
def get_domains(self) -> List[DomainModel]:
|
|
192
|
-
"""Get available domains"""
|
|
193
|
-
try:
|
|
194
|
-
response = self.session.get(f"{self.base_url}/api/v3/domains")
|
|
195
|
-
response.raise_for_status()
|
|
196
|
-
response_json = response.json()
|
|
197
|
-
return [DomainModel(
|
|
198
|
-
domain['name'],
|
|
199
|
-
domain['type'],
|
|
200
|
-
domain['forward_available'],
|
|
201
|
-
domain['forward_max_seconds']
|
|
202
|
-
) for domain in response_json['domains']]
|
|
203
|
-
except Exception:
|
|
204
|
-
return []
|
|
205
|
-
|
|
206
|
-
def create_account(self) -> bool:
|
|
207
|
-
"""Create a new temporary email account"""
|
|
208
|
-
try:
|
|
209
|
-
response = self.session.post(
|
|
210
|
-
f"{self.base_url}/api/v3/email/new",
|
|
211
|
-
data={}
|
|
212
|
-
)
|
|
213
|
-
response.raise_for_status()
|
|
214
|
-
response_json = response.json()
|
|
215
|
-
self.email = response_json['email']
|
|
216
|
-
self.token = response_json['token']
|
|
217
|
-
return True
|
|
218
|
-
except Exception:
|
|
219
|
-
return False
|
|
220
|
-
|
|
221
|
-
def get_messages(self) -> List[Dict]:
|
|
222
|
-
"""Get all messages in the inbox"""
|
|
223
|
-
if not self.email:
|
|
224
|
-
return []
|
|
225
|
-
|
|
226
|
-
try:
|
|
227
|
-
response = self.session.get(f"{self.base_url}/api/v3/email/{self.email}/messages")
|
|
228
|
-
response.raise_for_status()
|
|
229
|
-
response_json = response.json()
|
|
230
|
-
if len(response_json) == 0:
|
|
231
|
-
return []
|
|
232
|
-
|
|
233
|
-
messages = []
|
|
234
|
-
for message in response_json:
|
|
235
|
-
msg_dict = {
|
|
236
|
-
'msg_id': message['id'],
|
|
237
|
-
'from': message['from'] if 'from' in message else "",
|
|
238
|
-
'to': message['to'] if 'to' in message else "",
|
|
239
|
-
'subject': message['subject'] if 'subject' in message else "",
|
|
240
|
-
'body': message['body_text'] or message['body_html'] or "",
|
|
241
|
-
'hasAttachments': bool(message.get('attachments') and len(message['attachments']) > 0),
|
|
242
|
-
'createdAt': message['created_at']
|
|
243
|
-
}
|
|
244
|
-
messages.append(msg_dict)
|
|
245
|
-
return messages
|
|
246
|
-
except Exception:
|
|
247
|
-
return []
|
|
248
|
-
|
|
249
|
-
def check_new_messages(self) -> List[Dict]:
|
|
250
|
-
"""Check for new messages and return only the new ones"""
|
|
251
|
-
messages = self.get_messages()
|
|
252
|
-
if not messages:
|
|
253
|
-
return []
|
|
254
|
-
|
|
255
|
-
if len(messages) > self.messages_count:
|
|
256
|
-
new_msg_count = len(messages) - self.messages_count
|
|
257
|
-
new_messages = messages[:new_msg_count]
|
|
258
|
-
self.messages_count = len(messages)
|
|
259
|
-
return new_messages
|
|
260
|
-
|
|
261
|
-
self.messages_count = len(messages)
|
|
262
|
-
return []
|
|
263
|
-
|
|
264
|
-
def delete_account(self) -> bool:
|
|
265
|
-
"""Delete the current temporary email account"""
|
|
266
|
-
if not self.email or not self.token:
|
|
267
|
-
return False
|
|
268
|
-
|
|
269
|
-
try:
|
|
270
|
-
response = self.session.delete(
|
|
271
|
-
f"{self.base_url}/api/v3/email/{self.email}",
|
|
272
|
-
data={'token': self.token}
|
|
273
|
-
)
|
|
274
|
-
response.raise_for_status()
|
|
275
|
-
success = response.status_code == 200
|
|
276
|
-
if success:
|
|
277
|
-
self.email = None
|
|
278
|
-
self.token = None
|
|
279
|
-
self.messages_count = 0
|
|
280
|
-
return success
|
|
281
|
-
except Exception:
|
|
282
|
-
return False
|
|
283
|
-
|
|
284
|
-
def get_account_info(self) -> Dict:
|
|
285
|
-
"""Get current account information"""
|
|
286
|
-
if not self.email or not self.token:
|
|
287
|
-
return {}
|
|
288
|
-
|
|
289
|
-
return {
|
|
290
|
-
'email': self.email,
|
|
291
|
-
'token': self.token
|
|
1
|
+
"""
|
|
2
|
+
TempMail.io Provider Implementation
|
|
3
|
+
Based on temp-mail.io API
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import aiohttp
|
|
7
|
+
import asyncio
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import List, Dict, Any, Optional, Union, Tuple, NoReturn
|
|
10
|
+
|
|
11
|
+
from .base import AsyncTempMailProvider, TempMailProvider, generate_random_string
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class DomainModel:
|
|
16
|
+
"""Domain model for TempMail.io API"""
|
|
17
|
+
name: str
|
|
18
|
+
type: str
|
|
19
|
+
forward_available: str
|
|
20
|
+
forward_max_seconds: str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class CreateEmailResponseModel:
|
|
25
|
+
"""Response model for email creation in TempMail.io API"""
|
|
26
|
+
email: str
|
|
27
|
+
token: str
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class MessageResponseModel:
|
|
32
|
+
"""Message model for TempMail.io API"""
|
|
33
|
+
attachments: Optional[List[Any]]
|
|
34
|
+
body_html: Optional[str]
|
|
35
|
+
body_text: Optional[str]
|
|
36
|
+
cc: Optional[str]
|
|
37
|
+
created_at: str
|
|
38
|
+
email_from: Optional[str]
|
|
39
|
+
id: str
|
|
40
|
+
subject: Optional[str]
|
|
41
|
+
email_to: Optional[str]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TempMailIOAsync(AsyncTempMailProvider):
|
|
45
|
+
"""
|
|
46
|
+
TempMail.io API client for temporary email services
|
|
47
|
+
Implements the AsyncTempMailProvider interface
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(self):
|
|
51
|
+
"""Initialize TempMail.io Async client"""
|
|
52
|
+
self._session = None
|
|
53
|
+
self.email = None
|
|
54
|
+
self.token = None
|
|
55
|
+
|
|
56
|
+
async def initialize(self):
|
|
57
|
+
"""Initialize the aiohttp session"""
|
|
58
|
+
self._session = aiohttp.ClientSession(
|
|
59
|
+
base_url="https://api.internal.temp-mail.io",
|
|
60
|
+
headers={
|
|
61
|
+
'Host': 'api.internal.temp-mail.io',
|
|
62
|
+
'User-Agent': 'okhttp/4.5.0',
|
|
63
|
+
'Connection': 'close'
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
return self
|
|
67
|
+
|
|
68
|
+
async def close(self) -> None:
|
|
69
|
+
"""Close the aiohttp session"""
|
|
70
|
+
if self._session and not self._session.closed:
|
|
71
|
+
await self._session.close()
|
|
72
|
+
self._session = None
|
|
73
|
+
|
|
74
|
+
async def __aenter__(self):
|
|
75
|
+
"""Context manager entry"""
|
|
76
|
+
return await self.initialize()
|
|
77
|
+
|
|
78
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
79
|
+
"""Context manager exit"""
|
|
80
|
+
await self.close()
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
async def get_domains(self) -> List[DomainModel]:
|
|
84
|
+
"""Get available domains"""
|
|
85
|
+
if not self._session:
|
|
86
|
+
await self.initialize()
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
async with self._session.get("/api/v3/domains") as response:
|
|
90
|
+
response_json = await response.json()
|
|
91
|
+
return [DomainModel(
|
|
92
|
+
domain['name'],
|
|
93
|
+
domain['type'],
|
|
94
|
+
domain['forward_available'],
|
|
95
|
+
domain['forward_max_seconds']
|
|
96
|
+
) for domain in response_json['domains']]
|
|
97
|
+
except Exception:
|
|
98
|
+
return []
|
|
99
|
+
|
|
100
|
+
async def create_email(self, alias: Optional[str] = None, domain: Optional[str] = None) -> Tuple[str, str]:
|
|
101
|
+
"""Create a new temporary email"""
|
|
102
|
+
if not self._session:
|
|
103
|
+
await self.initialize()
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
async with self._session.post(
|
|
107
|
+
"/api/v3/email/new",
|
|
108
|
+
data={'name': alias, 'domain': domain}
|
|
109
|
+
) as response:
|
|
110
|
+
response_json = await response.json()
|
|
111
|
+
self.email = response_json['email']
|
|
112
|
+
self.token = response_json['token']
|
|
113
|
+
return self.email, self.token
|
|
114
|
+
except Exception:
|
|
115
|
+
return "", ""
|
|
116
|
+
|
|
117
|
+
async def delete_email(self) -> bool:
|
|
118
|
+
"""Delete a temporary email"""
|
|
119
|
+
if not self._session or not self.email or not self.token:
|
|
120
|
+
return False
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
async with self._session.delete(
|
|
124
|
+
f"/api/v3/email/{self.email}",
|
|
125
|
+
data={'token': self.token}
|
|
126
|
+
) as response:
|
|
127
|
+
success = response.status == 200
|
|
128
|
+
if success:
|
|
129
|
+
self.email = None
|
|
130
|
+
self.token = None
|
|
131
|
+
return success
|
|
132
|
+
except Exception:
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
async def get_messages(self) -> List[Dict]:
|
|
136
|
+
"""Get messages for a temporary email"""
|
|
137
|
+
if not self._session or not self.email:
|
|
138
|
+
return []
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
async with self._session.get(f"/api/v3/email/{self.email}/messages") as response:
|
|
142
|
+
response_json = await response.json()
|
|
143
|
+
if len(response_json) == 0:
|
|
144
|
+
return []
|
|
145
|
+
|
|
146
|
+
messages = []
|
|
147
|
+
for message in response_json:
|
|
148
|
+
msg_dict = {
|
|
149
|
+
'msg_id': message['id'],
|
|
150
|
+
'from': message['from'],
|
|
151
|
+
'to': message['to'],
|
|
152
|
+
'subject': message['subject'] if 'subject' in message else "",
|
|
153
|
+
'body': message['body_text'] or message['body_html'],
|
|
154
|
+
'hasAttachments': bool(message['attachments'] and len(message['attachments']) > 0),
|
|
155
|
+
'createdAt': message['created_at']
|
|
156
|
+
}
|
|
157
|
+
messages.append(msg_dict)
|
|
158
|
+
return messages
|
|
159
|
+
except Exception:
|
|
160
|
+
return []
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class TempMailIO(TempMailProvider):
|
|
164
|
+
"""
|
|
165
|
+
Synchronous implementation for TempMail.io API
|
|
166
|
+
Implements the TempMailProvider interface
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
def __init__(self, auto_create=False):
|
|
170
|
+
"""
|
|
171
|
+
Initialize TempMail.io client
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
auto_create: Automatically create an email upon initialization
|
|
175
|
+
"""
|
|
176
|
+
import requests
|
|
177
|
+
self.session = requests.Session()
|
|
178
|
+
self.session.headers.update({
|
|
179
|
+
'Host': 'api.internal.temp-mail.io',
|
|
180
|
+
'User-Agent': 'okhttp/4.5.0',
|
|
181
|
+
'Connection': 'close'
|
|
182
|
+
})
|
|
183
|
+
self.base_url = "https://api.internal.temp-mail.io"
|
|
184
|
+
self.email = None
|
|
185
|
+
self.token = None
|
|
186
|
+
self.messages_count = 0
|
|
187
|
+
|
|
188
|
+
if auto_create:
|
|
189
|
+
self.create_account()
|
|
190
|
+
|
|
191
|
+
def get_domains(self) -> List[DomainModel]:
|
|
192
|
+
"""Get available domains"""
|
|
193
|
+
try:
|
|
194
|
+
response = self.session.get(f"{self.base_url}/api/v3/domains")
|
|
195
|
+
response.raise_for_status()
|
|
196
|
+
response_json = response.json()
|
|
197
|
+
return [DomainModel(
|
|
198
|
+
domain['name'],
|
|
199
|
+
domain['type'],
|
|
200
|
+
domain['forward_available'],
|
|
201
|
+
domain['forward_max_seconds']
|
|
202
|
+
) for domain in response_json['domains']]
|
|
203
|
+
except Exception:
|
|
204
|
+
return []
|
|
205
|
+
|
|
206
|
+
def create_account(self) -> bool:
|
|
207
|
+
"""Create a new temporary email account"""
|
|
208
|
+
try:
|
|
209
|
+
response = self.session.post(
|
|
210
|
+
f"{self.base_url}/api/v3/email/new",
|
|
211
|
+
data={}
|
|
212
|
+
)
|
|
213
|
+
response.raise_for_status()
|
|
214
|
+
response_json = response.json()
|
|
215
|
+
self.email = response_json['email']
|
|
216
|
+
self.token = response_json['token']
|
|
217
|
+
return True
|
|
218
|
+
except Exception:
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
def get_messages(self) -> List[Dict]:
|
|
222
|
+
"""Get all messages in the inbox"""
|
|
223
|
+
if not self.email:
|
|
224
|
+
return []
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
response = self.session.get(f"{self.base_url}/api/v3/email/{self.email}/messages")
|
|
228
|
+
response.raise_for_status()
|
|
229
|
+
response_json = response.json()
|
|
230
|
+
if len(response_json) == 0:
|
|
231
|
+
return []
|
|
232
|
+
|
|
233
|
+
messages = []
|
|
234
|
+
for message in response_json:
|
|
235
|
+
msg_dict = {
|
|
236
|
+
'msg_id': message['id'],
|
|
237
|
+
'from': message['from'] if 'from' in message else "",
|
|
238
|
+
'to': message['to'] if 'to' in message else "",
|
|
239
|
+
'subject': message['subject'] if 'subject' in message else "",
|
|
240
|
+
'body': message['body_text'] or message['body_html'] or "",
|
|
241
|
+
'hasAttachments': bool(message.get('attachments') and len(message['attachments']) > 0),
|
|
242
|
+
'createdAt': message['created_at']
|
|
243
|
+
}
|
|
244
|
+
messages.append(msg_dict)
|
|
245
|
+
return messages
|
|
246
|
+
except Exception:
|
|
247
|
+
return []
|
|
248
|
+
|
|
249
|
+
def check_new_messages(self) -> List[Dict]:
|
|
250
|
+
"""Check for new messages and return only the new ones"""
|
|
251
|
+
messages = self.get_messages()
|
|
252
|
+
if not messages:
|
|
253
|
+
return []
|
|
254
|
+
|
|
255
|
+
if len(messages) > self.messages_count:
|
|
256
|
+
new_msg_count = len(messages) - self.messages_count
|
|
257
|
+
new_messages = messages[:new_msg_count]
|
|
258
|
+
self.messages_count = len(messages)
|
|
259
|
+
return new_messages
|
|
260
|
+
|
|
261
|
+
self.messages_count = len(messages)
|
|
262
|
+
return []
|
|
263
|
+
|
|
264
|
+
def delete_account(self) -> bool:
|
|
265
|
+
"""Delete the current temporary email account"""
|
|
266
|
+
if not self.email or not self.token:
|
|
267
|
+
return False
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
response = self.session.delete(
|
|
271
|
+
f"{self.base_url}/api/v3/email/{self.email}",
|
|
272
|
+
data={'token': self.token}
|
|
273
|
+
)
|
|
274
|
+
response.raise_for_status()
|
|
275
|
+
success = response.status_code == 200
|
|
276
|
+
if success:
|
|
277
|
+
self.email = None
|
|
278
|
+
self.token = None
|
|
279
|
+
self.messages_count = 0
|
|
280
|
+
return success
|
|
281
|
+
except Exception:
|
|
282
|
+
return False
|
|
283
|
+
|
|
284
|
+
def get_account_info(self) -> Dict:
|
|
285
|
+
"""Get current account information"""
|
|
286
|
+
if not self.email or not self.token:
|
|
287
|
+
return {}
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
'email': self.email,
|
|
291
|
+
'token': self.token
|
|
292
292
|
}
|