webscout 8.2.6__py3-none-any.whl → 8.2.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.
- webscout/AIutel.py +97 -87
- webscout/version.py +1 -1
- {webscout-8.2.6.dist-info → webscout-8.2.7.dist-info}/METADATA +2 -15
- webscout-8.2.7.dist-info/RECORD +26 -0
- {webscout-8.2.6.dist-info → webscout-8.2.7.dist-info}/WHEEL +1 -1
- webscout-8.2.7.dist-info/entry_points.txt +3 -0
- webscout-8.2.7.dist-info/top_level.txt +1 -0
- webscout/Extra/GitToolkit/__init__.py +0 -10
- webscout/Extra/GitToolkit/gitapi/__init__.py +0 -12
- webscout/Extra/GitToolkit/gitapi/repository.py +0 -195
- webscout/Extra/GitToolkit/gitapi/user.py +0 -96
- webscout/Extra/GitToolkit/gitapi/utils.py +0 -62
- webscout/Extra/YTToolkit/YTdownloader.py +0 -957
- webscout/Extra/YTToolkit/__init__.py +0 -3
- webscout/Extra/YTToolkit/transcriber.py +0 -476
- webscout/Extra/YTToolkit/ytapi/__init__.py +0 -6
- webscout/Extra/YTToolkit/ytapi/channel.py +0 -307
- webscout/Extra/YTToolkit/ytapi/errors.py +0 -13
- webscout/Extra/YTToolkit/ytapi/extras.py +0 -45
- webscout/Extra/YTToolkit/ytapi/https.py +0 -88
- webscout/Extra/YTToolkit/ytapi/patterns.py +0 -61
- webscout/Extra/YTToolkit/ytapi/playlist.py +0 -59
- webscout/Extra/YTToolkit/ytapi/pool.py +0 -8
- webscout/Extra/YTToolkit/ytapi/query.py +0 -40
- webscout/Extra/YTToolkit/ytapi/stream.py +0 -63
- webscout/Extra/YTToolkit/ytapi/utils.py +0 -62
- webscout/Extra/YTToolkit/ytapi/video.py +0 -232
- webscout/Extra/__init__.py +0 -7
- webscout/Extra/autocoder/__init__.py +0 -9
- webscout/Extra/autocoder/autocoder.py +0 -910
- webscout/Extra/autocoder/autocoder_utiles.py +0 -332
- webscout/Extra/gguf.py +0 -684
- webscout/Extra/tempmail/__init__.py +0 -28
- webscout/Extra/tempmail/async_utils.py +0 -141
- webscout/Extra/tempmail/base.py +0 -161
- webscout/Extra/tempmail/cli.py +0 -187
- webscout/Extra/tempmail/emailnator.py +0 -84
- webscout/Extra/tempmail/mail_tm.py +0 -361
- webscout/Extra/tempmail/temp_mail_io.py +0 -292
- webscout/Extra/weather.py +0 -194
- webscout/Extra/weather_ascii.py +0 -76
- webscout/Litlogger/__init__.py +0 -67
- webscout/Litlogger/core/__init__.py +0 -6
- webscout/Litlogger/core/level.py +0 -23
- webscout/Litlogger/core/logger.py +0 -165
- webscout/Litlogger/handlers/__init__.py +0 -12
- webscout/Litlogger/handlers/console.py +0 -33
- webscout/Litlogger/handlers/file.py +0 -143
- webscout/Litlogger/handlers/network.py +0 -173
- webscout/Litlogger/styles/__init__.py +0 -7
- webscout/Litlogger/styles/colors.py +0 -249
- webscout/Litlogger/styles/formats.py +0 -458
- webscout/Litlogger/styles/text.py +0 -87
- webscout/Litlogger/utils/__init__.py +0 -6
- webscout/Litlogger/utils/detectors.py +0 -153
- webscout/Litlogger/utils/formatters.py +0 -200
- webscout/Provider/AI21.py +0 -177
- webscout/Provider/AISEARCH/DeepFind.py +0 -250
- webscout/Provider/AISEARCH/ISou.py +0 -256
- webscout/Provider/AISEARCH/Perplexity.py +0 -359
- webscout/Provider/AISEARCH/__init__.py +0 -10
- webscout/Provider/AISEARCH/felo_search.py +0 -228
- webscout/Provider/AISEARCH/genspark_search.py +0 -208
- webscout/Provider/AISEARCH/hika_search.py +0 -198
- webscout/Provider/AISEARCH/iask_search.py +0 -436
- webscout/Provider/AISEARCH/monica_search.py +0 -246
- webscout/Provider/AISEARCH/scira_search.py +0 -322
- webscout/Provider/AISEARCH/webpilotai_search.py +0 -281
- webscout/Provider/Aitopia.py +0 -316
- webscout/Provider/AllenAI.py +0 -447
- webscout/Provider/Andi.py +0 -228
- webscout/Provider/Blackboxai.py +0 -229
- webscout/Provider/ChatGPTClone.py +0 -237
- webscout/Provider/ChatGPTGratis.py +0 -194
- webscout/Provider/ChatSandbox.py +0 -342
- webscout/Provider/Cloudflare.py +0 -325
- webscout/Provider/Cohere.py +0 -208
- webscout/Provider/Deepinfra.py +0 -338
- webscout/Provider/ElectronHub.py +0 -773
- webscout/Provider/ExaAI.py +0 -261
- webscout/Provider/ExaChat.py +0 -358
- webscout/Provider/Free2GPT.py +0 -241
- webscout/Provider/GPTWeb.py +0 -249
- webscout/Provider/Gemini.py +0 -169
- webscout/Provider/GithubChat.py +0 -370
- webscout/Provider/GizAI.py +0 -285
- webscout/Provider/Glider.py +0 -222
- webscout/Provider/Groq.py +0 -801
- webscout/Provider/HF_space/__init__.py +0 -0
- webscout/Provider/HF_space/qwen_qwen2.py +0 -206
- webscout/Provider/HeckAI.py +0 -257
- webscout/Provider/HuggingFaceChat.py +0 -469
- webscout/Provider/Hunyuan.py +0 -283
- webscout/Provider/Jadve.py +0 -291
- webscout/Provider/Koboldai.py +0 -381
- webscout/Provider/LambdaChat.py +0 -411
- webscout/Provider/Llama3.py +0 -259
- webscout/Provider/MCPCore.py +0 -315
- webscout/Provider/Marcus.py +0 -206
- webscout/Provider/Nemotron.py +0 -218
- webscout/Provider/Netwrck.py +0 -270
- webscout/Provider/OLLAMA.py +0 -396
- webscout/Provider/OPENAI/__init__.py +0 -28
- webscout/Provider/OPENAI/ai4chat.py +0 -286
- webscout/Provider/OPENAI/base.py +0 -46
- webscout/Provider/OPENAI/c4ai.py +0 -367
- webscout/Provider/OPENAI/chatgpt.py +0 -549
- webscout/Provider/OPENAI/chatgptclone.py +0 -481
- webscout/Provider/OPENAI/deepinfra.py +0 -309
- webscout/Provider/OPENAI/e2b.py +0 -1350
- webscout/Provider/OPENAI/exaai.py +0 -404
- webscout/Provider/OPENAI/exachat.py +0 -437
- webscout/Provider/OPENAI/freeaichat.py +0 -352
- webscout/Provider/OPENAI/glider.py +0 -316
- webscout/Provider/OPENAI/groq.py +0 -354
- webscout/Provider/OPENAI/heckai.py +0 -341
- webscout/Provider/OPENAI/llmchatco.py +0 -327
- webscout/Provider/OPENAI/mcpcore.py +0 -376
- webscout/Provider/OPENAI/multichat.py +0 -368
- webscout/Provider/OPENAI/netwrck.py +0 -350
- webscout/Provider/OPENAI/opkfc.py +0 -488
- webscout/Provider/OPENAI/scirachat.py +0 -462
- webscout/Provider/OPENAI/sonus.py +0 -294
- webscout/Provider/OPENAI/standardinput.py +0 -425
- webscout/Provider/OPENAI/textpollinations.py +0 -329
- webscout/Provider/OPENAI/toolbaz.py +0 -406
- webscout/Provider/OPENAI/typegpt.py +0 -346
- webscout/Provider/OPENAI/uncovrAI.py +0 -455
- webscout/Provider/OPENAI/utils.py +0 -211
- webscout/Provider/OPENAI/venice.py +0 -413
- webscout/Provider/OPENAI/wisecat.py +0 -381
- webscout/Provider/OPENAI/writecream.py +0 -156
- webscout/Provider/OPENAI/x0gpt.py +0 -371
- webscout/Provider/OPENAI/yep.py +0 -327
- webscout/Provider/OpenGPT.py +0 -209
- webscout/Provider/Openai.py +0 -496
- webscout/Provider/PI.py +0 -429
- webscout/Provider/Perplexitylabs.py +0 -415
- webscout/Provider/QwenLM.py +0 -254
- webscout/Provider/Reka.py +0 -214
- webscout/Provider/StandardInput.py +0 -290
- webscout/Provider/TTI/AiForce/__init__.py +0 -22
- webscout/Provider/TTI/AiForce/async_aiforce.py +0 -224
- webscout/Provider/TTI/AiForce/sync_aiforce.py +0 -245
- webscout/Provider/TTI/FreeAIPlayground/__init__.py +0 -9
- webscout/Provider/TTI/FreeAIPlayground/async_freeaiplayground.py +0 -181
- webscout/Provider/TTI/FreeAIPlayground/sync_freeaiplayground.py +0 -180
- webscout/Provider/TTI/ImgSys/__init__.py +0 -23
- webscout/Provider/TTI/ImgSys/async_imgsys.py +0 -202
- webscout/Provider/TTI/ImgSys/sync_imgsys.py +0 -195
- webscout/Provider/TTI/MagicStudio/__init__.py +0 -2
- webscout/Provider/TTI/MagicStudio/async_magicstudio.py +0 -111
- webscout/Provider/TTI/MagicStudio/sync_magicstudio.py +0 -109
- webscout/Provider/TTI/Nexra/__init__.py +0 -22
- webscout/Provider/TTI/Nexra/async_nexra.py +0 -286
- webscout/Provider/TTI/Nexra/sync_nexra.py +0 -258
- webscout/Provider/TTI/PollinationsAI/__init__.py +0 -23
- webscout/Provider/TTI/PollinationsAI/async_pollinations.py +0 -311
- webscout/Provider/TTI/PollinationsAI/sync_pollinations.py +0 -265
- webscout/Provider/TTI/__init__.py +0 -12
- webscout/Provider/TTI/aiarta/__init__.py +0 -2
- webscout/Provider/TTI/aiarta/async_aiarta.py +0 -482
- webscout/Provider/TTI/aiarta/sync_aiarta.py +0 -440
- webscout/Provider/TTI/artbit/__init__.py +0 -22
- webscout/Provider/TTI/artbit/async_artbit.py +0 -155
- webscout/Provider/TTI/artbit/sync_artbit.py +0 -148
- webscout/Provider/TTI/fastflux/__init__.py +0 -22
- webscout/Provider/TTI/fastflux/async_fastflux.py +0 -261
- webscout/Provider/TTI/fastflux/sync_fastflux.py +0 -252
- webscout/Provider/TTI/huggingface/__init__.py +0 -22
- webscout/Provider/TTI/huggingface/async_huggingface.py +0 -199
- webscout/Provider/TTI/huggingface/sync_huggingface.py +0 -195
- webscout/Provider/TTI/piclumen/__init__.py +0 -23
- webscout/Provider/TTI/piclumen/async_piclumen.py +0 -268
- webscout/Provider/TTI/piclumen/sync_piclumen.py +0 -233
- webscout/Provider/TTI/pixelmuse/__init__.py +0 -4
- webscout/Provider/TTI/pixelmuse/async_pixelmuse.py +0 -249
- webscout/Provider/TTI/pixelmuse/sync_pixelmuse.py +0 -182
- webscout/Provider/TTI/talkai/__init__.py +0 -4
- webscout/Provider/TTI/talkai/async_talkai.py +0 -229
- webscout/Provider/TTI/talkai/sync_talkai.py +0 -207
- webscout/Provider/TTS/__init__.py +0 -8
- webscout/Provider/TTS/base.py +0 -159
- webscout/Provider/TTS/deepgram.py +0 -156
- webscout/Provider/TTS/elevenlabs.py +0 -111
- webscout/Provider/TTS/gesserit.py +0 -128
- webscout/Provider/TTS/murfai.py +0 -113
- webscout/Provider/TTS/parler.py +0 -111
- webscout/Provider/TTS/speechma.py +0 -180
- webscout/Provider/TTS/streamElements.py +0 -333
- webscout/Provider/TTS/utils.py +0 -280
- webscout/Provider/TeachAnything.py +0 -233
- webscout/Provider/TextPollinationsAI.py +0 -306
- webscout/Provider/TwoAI.py +0 -280
- webscout/Provider/TypliAI.py +0 -305
- webscout/Provider/Venice.py +0 -258
- webscout/Provider/VercelAI.py +0 -253
- webscout/Provider/WiseCat.py +0 -233
- webscout/Provider/WrDoChat.py +0 -370
- webscout/Provider/Writecream.py +0 -237
- webscout/Provider/WritingMate.py +0 -269
- webscout/Provider/Youchat.py +0 -330
- webscout/Provider/__init__.py +0 -178
- webscout/Provider/ai4chat.py +0 -203
- webscout/Provider/aimathgpt.py +0 -189
- webscout/Provider/akashgpt.py +0 -335
- webscout/Provider/asksteve.py +0 -212
- webscout/Provider/bagoodex.py +0 -145
- webscout/Provider/cerebras.py +0 -288
- webscout/Provider/chatglm.py +0 -215
- webscout/Provider/cleeai.py +0 -213
- webscout/Provider/copilot.py +0 -425
- webscout/Provider/elmo.py +0 -283
- webscout/Provider/freeaichat.py +0 -285
- webscout/Provider/geminiapi.py +0 -208
- webscout/Provider/geminiprorealtime.py +0 -160
- webscout/Provider/granite.py +0 -235
- webscout/Provider/hermes.py +0 -266
- webscout/Provider/julius.py +0 -223
- webscout/Provider/koala.py +0 -268
- webscout/Provider/learnfastai.py +0 -325
- webscout/Provider/llama3mitril.py +0 -215
- webscout/Provider/llmchat.py +0 -255
- webscout/Provider/llmchatco.py +0 -306
- webscout/Provider/meta.py +0 -798
- webscout/Provider/multichat.py +0 -364
- webscout/Provider/scira_chat.py +0 -297
- webscout/Provider/scnet.py +0 -243
- webscout/Provider/searchchat.py +0 -292
- webscout/Provider/sonus.py +0 -258
- webscout/Provider/talkai.py +0 -194
- webscout/Provider/toolbaz.py +0 -353
- webscout/Provider/turboseek.py +0 -266
- webscout/Provider/typefully.py +0 -330
- webscout/Provider/typegpt.py +0 -289
- webscout/Provider/uncovr.py +0 -368
- webscout/Provider/x0gpt.py +0 -299
- webscout/Provider/yep.py +0 -389
- webscout/litagent/__init__.py +0 -29
- webscout/litagent/agent.py +0 -455
- webscout/litagent/constants.py +0 -60
- webscout/litprinter/__init__.py +0 -59
- webscout/scout/__init__.py +0 -8
- webscout/scout/core/__init__.py +0 -7
- webscout/scout/core/crawler.py +0 -140
- webscout/scout/core/scout.py +0 -568
- webscout/scout/core/search_result.py +0 -96
- webscout/scout/core/text_analyzer.py +0 -63
- webscout/scout/core/text_utils.py +0 -277
- webscout/scout/core/web_analyzer.py +0 -52
- webscout/scout/core.py +0 -881
- webscout/scout/element.py +0 -460
- webscout/scout/parsers/__init__.py +0 -69
- webscout/scout/parsers/html5lib_parser.py +0 -172
- webscout/scout/parsers/html_parser.py +0 -236
- webscout/scout/parsers/lxml_parser.py +0 -178
- webscout/scout/utils.py +0 -37
- webscout/swiftcli/__init__.py +0 -95
- webscout/swiftcli/core/__init__.py +0 -7
- webscout/swiftcli/core/cli.py +0 -297
- webscout/swiftcli/core/context.py +0 -104
- webscout/swiftcli/core/group.py +0 -241
- webscout/swiftcli/decorators/__init__.py +0 -28
- webscout/swiftcli/decorators/command.py +0 -221
- webscout/swiftcli/decorators/options.py +0 -220
- webscout/swiftcli/decorators/output.py +0 -252
- webscout/swiftcli/exceptions.py +0 -21
- webscout/swiftcli/plugins/__init__.py +0 -9
- webscout/swiftcli/plugins/base.py +0 -135
- webscout/swiftcli/plugins/manager.py +0 -262
- webscout/swiftcli/utils/__init__.py +0 -59
- webscout/swiftcli/utils/formatting.py +0 -252
- webscout/swiftcli/utils/parsing.py +0 -267
- webscout/zeroart/__init__.py +0 -55
- webscout/zeroart/base.py +0 -60
- webscout/zeroart/effects.py +0 -99
- webscout/zeroart/fonts.py +0 -816
- webscout-8.2.6.dist-info/RECORD +0 -307
- webscout-8.2.6.dist-info/entry_points.txt +0 -3
- webscout-8.2.6.dist-info/top_level.txt +0 -2
- webstoken/__init__.py +0 -30
- webstoken/classifier.py +0 -189
- webstoken/keywords.py +0 -216
- webstoken/language.py +0 -128
- webstoken/ner.py +0 -164
- webstoken/normalizer.py +0 -35
- webstoken/processor.py +0 -77
- webstoken/sentiment.py +0 -206
- webstoken/stemmer.py +0 -73
- webstoken/tagger.py +0 -60
- webstoken/tokenizer.py +0 -158
- {webscout-8.2.6.dist-info → webscout-8.2.7.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -1,361 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Mail.TM Provider Implementation
|
|
3
|
-
Based on mail.tm and mail.gw APIs
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import string
|
|
7
|
-
import requests
|
|
8
|
-
import json
|
|
9
|
-
import random
|
|
10
|
-
import time
|
|
11
|
-
import asyncio
|
|
12
|
-
from typing import List, Dict, Any, Optional, Union, Tuple
|
|
13
|
-
|
|
14
|
-
from ...scout import Scout
|
|
15
|
-
from .base import TempMailProvider, AsyncTempMailProvider, EMAIL_LENGTH, PASSWORD_LENGTH, generate_random_string
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class MailTM(TempMailProvider):
|
|
19
|
-
"""
|
|
20
|
-
Mail.TM API client for temporary email services
|
|
21
|
-
Implements the synchronous TempMailProvider interface
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
def __init__(self, auto_create=False):
|
|
25
|
-
"""
|
|
26
|
-
Initialize MailTM client
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
auto_create (bool): Automatically create an email upon initialization
|
|
30
|
-
"""
|
|
31
|
-
self.url_bases = ['https://api.mail.tm', 'https://api.mail.gw']
|
|
32
|
-
self.url_base = self.url_bases[random.randrange(2)]
|
|
33
|
-
self.url_accounts = f"{self.url_base}/accounts"
|
|
34
|
-
self.url_me = f"{self.url_base}/me"
|
|
35
|
-
self.url_domain = f"{self.url_base}/domains"
|
|
36
|
-
self.url_msg = f"{self.url_base}/messages"
|
|
37
|
-
self.url_token = f"{self.url_base}/token"
|
|
38
|
-
|
|
39
|
-
self.email = None
|
|
40
|
-
self.password = None
|
|
41
|
-
self.token = None
|
|
42
|
-
self.account_id = None
|
|
43
|
-
self.header = None
|
|
44
|
-
self.messages_count = 0
|
|
45
|
-
|
|
46
|
-
if auto_create:
|
|
47
|
-
self.create_account()
|
|
48
|
-
|
|
49
|
-
def get_domain(self) -> str:
|
|
50
|
-
"""Get available domain for email creation"""
|
|
51
|
-
try:
|
|
52
|
-
resp = requests.get(f"{self.url_domain}?page=1")
|
|
53
|
-
resp.raise_for_status()
|
|
54
|
-
ans = json.loads(str(resp.text))
|
|
55
|
-
return ans['hydra:member'][0]['domain']
|
|
56
|
-
except requests.exceptions.HTTPError:
|
|
57
|
-
return ""
|
|
58
|
-
|
|
59
|
-
def create_account(self) -> bool:
|
|
60
|
-
"""Create a new temporary email account"""
|
|
61
|
-
domain = self.get_domain()
|
|
62
|
-
if not domain:
|
|
63
|
-
return False
|
|
64
|
-
|
|
65
|
-
# Generate random email and password
|
|
66
|
-
self.email = generate_random_string(EMAIL_LENGTH) + '@' + domain
|
|
67
|
-
self.password = generate_random_string(PASSWORD_LENGTH, include_digits=True)
|
|
68
|
-
|
|
69
|
-
# Register the account
|
|
70
|
-
myobj = {'address': self.email, "password": self.password}
|
|
71
|
-
try:
|
|
72
|
-
resp = requests.post(self.url_accounts, json=myobj)
|
|
73
|
-
resp.raise_for_status()
|
|
74
|
-
ans = json.loads(str(resp.text))
|
|
75
|
-
self.account_id = ans['id']
|
|
76
|
-
|
|
77
|
-
# Get token
|
|
78
|
-
self.get_token()
|
|
79
|
-
return True if self.token else False
|
|
80
|
-
|
|
81
|
-
except requests.exceptions.HTTPError:
|
|
82
|
-
return False
|
|
83
|
-
|
|
84
|
-
def get_token(self) -> str:
|
|
85
|
-
"""Get authentication token"""
|
|
86
|
-
if not self.email or not self.password:
|
|
87
|
-
return ""
|
|
88
|
-
|
|
89
|
-
myobj = {'address': self.email, "password": self.password}
|
|
90
|
-
try:
|
|
91
|
-
resp = requests.post(self.url_token, json=myobj)
|
|
92
|
-
resp.raise_for_status()
|
|
93
|
-
ans = json.loads(str(resp.text))
|
|
94
|
-
self.token = ans['token']
|
|
95
|
-
self.header = {'Authorization': 'Bearer ' + self.token}
|
|
96
|
-
return self.token
|
|
97
|
-
except requests.exceptions.HTTPError:
|
|
98
|
-
return ""
|
|
99
|
-
|
|
100
|
-
def get_message_detail(self, msg_id: str) -> str:
|
|
101
|
-
"""Get detailed content of a message"""
|
|
102
|
-
if not self.header:
|
|
103
|
-
return ""
|
|
104
|
-
|
|
105
|
-
try:
|
|
106
|
-
resp = requests.get(f"{self.url_msg}/{msg_id}", headers=self.header)
|
|
107
|
-
resp.raise_for_status()
|
|
108
|
-
ans = json.loads(str(resp.text))
|
|
109
|
-
|
|
110
|
-
# Use Scout instead of BeautifulSoup for HTML parsing
|
|
111
|
-
scout = Scout(ans['text'])
|
|
112
|
-
|
|
113
|
-
# Extract text with Scout's get_text method
|
|
114
|
-
return scout.get_text(strip=True)
|
|
115
|
-
|
|
116
|
-
except requests.exceptions.HTTPError:
|
|
117
|
-
return ""
|
|
118
|
-
|
|
119
|
-
def get_messages(self) -> List[Dict]:
|
|
120
|
-
"""Get messages from the inbox"""
|
|
121
|
-
if not self.header:
|
|
122
|
-
return []
|
|
123
|
-
|
|
124
|
-
try:
|
|
125
|
-
resp = requests.get(f"{self.url_msg}?page=1", headers=self.header)
|
|
126
|
-
resp.raise_for_status()
|
|
127
|
-
ans = json.loads(str(resp.text))
|
|
128
|
-
|
|
129
|
-
messages = []
|
|
130
|
-
if ans['hydra:totalItems'] > 0:
|
|
131
|
-
for x in ans['hydra:member']:
|
|
132
|
-
msg_dict = {
|
|
133
|
-
'msg_id': x['id'],
|
|
134
|
-
'from': x['from']['address'],
|
|
135
|
-
'subject': x['subject'],
|
|
136
|
-
'intro': x['intro'],
|
|
137
|
-
'hasAttachments': x['hasAttachments'],
|
|
138
|
-
'createdAt': x['createdAt'],
|
|
139
|
-
'body': self.get_message_detail(x['id'])
|
|
140
|
-
}
|
|
141
|
-
messages.append(msg_dict)
|
|
142
|
-
return messages
|
|
143
|
-
except requests.exceptions.HTTPError:
|
|
144
|
-
return []
|
|
145
|
-
|
|
146
|
-
def check_new_messages(self) -> List[Dict]:
|
|
147
|
-
"""Check for new messages and return only the new ones"""
|
|
148
|
-
messages = self.get_messages()
|
|
149
|
-
if not messages:
|
|
150
|
-
return []
|
|
151
|
-
|
|
152
|
-
if len(messages) > self.messages_count:
|
|
153
|
-
new_msg_count = len(messages) - self.messages_count
|
|
154
|
-
new_messages = messages[:new_msg_count]
|
|
155
|
-
self.messages_count = len(messages)
|
|
156
|
-
return new_messages
|
|
157
|
-
|
|
158
|
-
self.messages_count = len(messages)
|
|
159
|
-
return []
|
|
160
|
-
|
|
161
|
-
def delete_account(self) -> bool:
|
|
162
|
-
"""Delete the current temporary email account"""
|
|
163
|
-
if not self.header or not self.account_id:
|
|
164
|
-
return False
|
|
165
|
-
|
|
166
|
-
try:
|
|
167
|
-
resp = requests.delete(f"{self.url_accounts}/{self.account_id}", headers=self.header)
|
|
168
|
-
resp.raise_for_status()
|
|
169
|
-
self.email = None
|
|
170
|
-
self.password = None
|
|
171
|
-
self.token = None
|
|
172
|
-
self.account_id = None
|
|
173
|
-
self.header = None
|
|
174
|
-
self.messages_count = 0
|
|
175
|
-
return True
|
|
176
|
-
except requests.exceptions.HTTPError:
|
|
177
|
-
return False
|
|
178
|
-
|
|
179
|
-
def get_account_info(self) -> Dict:
|
|
180
|
-
"""Get current account information"""
|
|
181
|
-
if not self.header:
|
|
182
|
-
return {}
|
|
183
|
-
|
|
184
|
-
try:
|
|
185
|
-
resp = requests.get(self.url_me, headers=self.header)
|
|
186
|
-
resp.raise_for_status()
|
|
187
|
-
return json.loads(str(resp.text))
|
|
188
|
-
except requests.exceptions.HTTPError:
|
|
189
|
-
return {}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
class MailTMAsync(AsyncTempMailProvider):
|
|
193
|
-
"""
|
|
194
|
-
Asynchronous Mail.TM API client for temporary email services
|
|
195
|
-
Implements the AsyncTempMailProvider interface
|
|
196
|
-
"""
|
|
197
|
-
|
|
198
|
-
def __init__(self):
|
|
199
|
-
"""Initialize MailTM Async client"""
|
|
200
|
-
self.url_bases = ['https://api.mail.tm', 'https://api.mail.gw']
|
|
201
|
-
self.url_base = self.url_bases[random.randrange(2)]
|
|
202
|
-
self.url_accounts = f"{self.url_base}/accounts"
|
|
203
|
-
self.url_me = f"{self.url_base}/me"
|
|
204
|
-
self.url_domain = f"{self.url_base}/domains"
|
|
205
|
-
self.url_msg = f"{self.url_base}/messages"
|
|
206
|
-
self.url_token = f"{self.url_base}/token"
|
|
207
|
-
|
|
208
|
-
self.session = None
|
|
209
|
-
self.email = None
|
|
210
|
-
self.password = None
|
|
211
|
-
self.token = None
|
|
212
|
-
self.account_id = None
|
|
213
|
-
self.header = None
|
|
214
|
-
|
|
215
|
-
async def initialize(self):
|
|
216
|
-
"""Initialize the session"""
|
|
217
|
-
import aiohttp
|
|
218
|
-
self.session = aiohttp.ClientSession()
|
|
219
|
-
return self
|
|
220
|
-
|
|
221
|
-
async def close(self) -> None:
|
|
222
|
-
"""Close the session"""
|
|
223
|
-
if self.session:
|
|
224
|
-
await self.session.close()
|
|
225
|
-
self.session = None
|
|
226
|
-
|
|
227
|
-
async def __aenter__(self):
|
|
228
|
-
"""Context manager entry"""
|
|
229
|
-
return await self.initialize()
|
|
230
|
-
|
|
231
|
-
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
232
|
-
"""Context manager exit"""
|
|
233
|
-
await self.close()
|
|
234
|
-
|
|
235
|
-
async def get_domain(self) -> str:
|
|
236
|
-
"""Get available domain for email creation"""
|
|
237
|
-
if not self.session:
|
|
238
|
-
await self.initialize()
|
|
239
|
-
|
|
240
|
-
try:
|
|
241
|
-
async with self.session.get(f"{self.url_domain}?page=1") as resp:
|
|
242
|
-
resp.raise_for_status()
|
|
243
|
-
ans = await resp.json()
|
|
244
|
-
return ans['hydra:member'][0]['domain']
|
|
245
|
-
except Exception:
|
|
246
|
-
return ""
|
|
247
|
-
|
|
248
|
-
async def create_email(self, alias: Optional[str] = None, domain: Optional[str] = None) -> Tuple[str, str]:
|
|
249
|
-
"""Create a new email account"""
|
|
250
|
-
if not self.session:
|
|
251
|
-
await self.initialize()
|
|
252
|
-
|
|
253
|
-
if not domain:
|
|
254
|
-
domain = await self.get_domain()
|
|
255
|
-
if not domain:
|
|
256
|
-
return "", ""
|
|
257
|
-
|
|
258
|
-
# Generate random email address or use alias
|
|
259
|
-
if alias:
|
|
260
|
-
self.email = f"{alias}@{domain}"
|
|
261
|
-
else:
|
|
262
|
-
self.email = f"{generate_random_string(EMAIL_LENGTH)}@{domain}"
|
|
263
|
-
|
|
264
|
-
# Generate password
|
|
265
|
-
self.password = generate_random_string(PASSWORD_LENGTH, include_digits=True)
|
|
266
|
-
|
|
267
|
-
# Register account
|
|
268
|
-
data = {'address': self.email, 'password': self.password}
|
|
269
|
-
try:
|
|
270
|
-
async with self.session.post(self.url_accounts, json=data) as resp:
|
|
271
|
-
resp.raise_for_status()
|
|
272
|
-
ans = await resp.json()
|
|
273
|
-
self.account_id = ans['id']
|
|
274
|
-
|
|
275
|
-
# Get token
|
|
276
|
-
token = await self._get_token()
|
|
277
|
-
return self.email, token
|
|
278
|
-
|
|
279
|
-
except Exception:
|
|
280
|
-
return "", ""
|
|
281
|
-
|
|
282
|
-
async def _get_token(self) -> str:
|
|
283
|
-
"""Get authentication token"""
|
|
284
|
-
if not self.email or not self.password:
|
|
285
|
-
return ""
|
|
286
|
-
|
|
287
|
-
data = {'address': self.email, 'password': self.password}
|
|
288
|
-
try:
|
|
289
|
-
async with self.session.post(self.url_token, json=data) as resp:
|
|
290
|
-
resp.raise_for_status()
|
|
291
|
-
ans = await resp.json()
|
|
292
|
-
self.token = ans['token']
|
|
293
|
-
self.header = {'Authorization': f'Bearer {self.token}'}
|
|
294
|
-
return self.token
|
|
295
|
-
except Exception:
|
|
296
|
-
return ""
|
|
297
|
-
|
|
298
|
-
async def get_message_detail(self, msg_id: str) -> str:
|
|
299
|
-
"""Get detailed content of a message"""
|
|
300
|
-
if not self.header:
|
|
301
|
-
return ""
|
|
302
|
-
|
|
303
|
-
try:
|
|
304
|
-
async with self.session.get(f"{self.url_msg}/{msg_id}", headers=self.header) as resp:
|
|
305
|
-
resp.raise_for_status()
|
|
306
|
-
ans = await resp.json()
|
|
307
|
-
|
|
308
|
-
# Use Scout instead of BeautifulSoup for HTML parsing
|
|
309
|
-
scout = Scout(ans['text'])
|
|
310
|
-
|
|
311
|
-
# Extract text with Scout's get_text method with improved options
|
|
312
|
-
# Strip whitespace for cleaner output
|
|
313
|
-
return scout.get_text(separator=' ', strip=True)
|
|
314
|
-
|
|
315
|
-
except Exception:
|
|
316
|
-
return ""
|
|
317
|
-
|
|
318
|
-
async def get_messages(self) -> List[Dict]:
|
|
319
|
-
"""Get messages for a temporary email"""
|
|
320
|
-
if not self.header:
|
|
321
|
-
return []
|
|
322
|
-
|
|
323
|
-
try:
|
|
324
|
-
async with self.session.get(f"{self.url_msg}?page=1", headers=self.header) as resp:
|
|
325
|
-
resp.raise_for_status()
|
|
326
|
-
ans = await resp.json()
|
|
327
|
-
|
|
328
|
-
messages = []
|
|
329
|
-
if ans['hydra:totalItems'] > 0:
|
|
330
|
-
for x in ans['hydra:member']:
|
|
331
|
-
detail = await self.get_message_detail(x['id'])
|
|
332
|
-
msg_dict = {
|
|
333
|
-
'msg_id': x['id'],
|
|
334
|
-
'from': x['from']['address'],
|
|
335
|
-
'subject': x['subject'],
|
|
336
|
-
'intro': x['intro'],
|
|
337
|
-
'hasAttachments': x['hasAttachments'],
|
|
338
|
-
'createdAt': x['createdAt'],
|
|
339
|
-
'body': detail
|
|
340
|
-
}
|
|
341
|
-
messages.append(msg_dict)
|
|
342
|
-
return messages
|
|
343
|
-
except Exception:
|
|
344
|
-
return []
|
|
345
|
-
|
|
346
|
-
async def delete_email(self) -> bool:
|
|
347
|
-
"""Delete a temporary email"""
|
|
348
|
-
if not self.header or not self.account_id:
|
|
349
|
-
return False
|
|
350
|
-
|
|
351
|
-
try:
|
|
352
|
-
async with self.session.delete(f"{self.url_accounts}/{self.account_id}", headers=self.header) as resp:
|
|
353
|
-
resp.raise_for_status()
|
|
354
|
-
self.email = None
|
|
355
|
-
self.password = None
|
|
356
|
-
self.token = None
|
|
357
|
-
self.account_id = None
|
|
358
|
-
self.header = None
|
|
359
|
-
return True
|
|
360
|
-
except Exception:
|
|
361
|
-
return False
|
|
@@ -1,292 +0,0 @@
|
|
|
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
|
-
}
|