Compare commits
10 Commits
818f5f5f10
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 9c14541b1a | |||
| a68896dd4e | |||
| a56d0c39e8 | |||
| 325a65a92e | |||
| e1c96bc045 | |||
| bdb3c6ddf4 | |||
| dc4c6d54f1 | |||
| b6b37753af | |||
| f9dafb795d | |||
| 50b0c16048 |
@ -1,9 +1,10 @@
|
||||
from .async_base_session import AsyncBaseSession
|
||||
from .base_data import BaseData
|
||||
from .base_session import BaseSession
|
||||
from .base_thon import BaseData, BaseThon
|
||||
from .base_thon import BaseThon
|
||||
from .json_async_converter import JsonAsyncConverter
|
||||
from .json_converter import JsonConverter
|
||||
from .models import BaseThonOptions, BaseThonSearchCodeOptions
|
||||
from .models import ThonOptions, ThonSearchCodeOptions
|
||||
|
||||
__all__ = [
|
||||
"BaseThon",
|
||||
@ -12,6 +13,6 @@ __all__ = [
|
||||
"BaseData",
|
||||
"JsonAsyncConverter",
|
||||
"AsyncBaseSession",
|
||||
"BaseThonOptions",
|
||||
"BaseThonSearchCodeOptions",
|
||||
"ThonOptions",
|
||||
"ThonSearchCodeOptions",
|
||||
]
|
||||
|
||||
@ -7,8 +7,11 @@ from jsoner.async_ import json_read
|
||||
class AsyncBaseSession:
|
||||
def __init__(self, base_dir: Path, errors_dir: Path, banned_dir: Path):
|
||||
self.base_dir = base_dir
|
||||
self.base_dir.mkdir(exist_ok=True)
|
||||
self.errors_dir = errors_dir
|
||||
self.errors_dir.mkdir(exist_ok=True)
|
||||
self.banned_dir = banned_dir
|
||||
self.banned_dir.mkdir(exist_ok=True)
|
||||
self.json_errors: set[Path] = set()
|
||||
|
||||
async def __aiter__(self) -> AsyncGenerator[tuple[Path, Path, dict], None]:
|
||||
|
||||
110
basethon/base_data.py
Normal file
110
basethon/base_data.py
Normal file
@ -0,0 +1,110 @@
|
||||
from telethon.sessions import StringSession
|
||||
|
||||
|
||||
class BaseData:
|
||||
def __init__(self, json_data: dict, raise_error: bool):
|
||||
self.__json_data, self.__raise_error = json_data, raise_error
|
||||
|
||||
@property
|
||||
def json_data(self) -> dict:
|
||||
return self.__json_data
|
||||
|
||||
def json_data_edit(self, key: str, value: str | int | bool | None):
|
||||
self.__json_data[key] = value
|
||||
|
||||
@property
|
||||
def session_file(self) -> str:
|
||||
if not (session_file := self.json_data.get("session_file")):
|
||||
if self.__raise_error:
|
||||
raise ValueError("ERROR_SESSION_FILE:BASE_THON")
|
||||
return ""
|
||||
return session_file
|
||||
|
||||
@property
|
||||
def string_session(self) -> StringSession:
|
||||
if not (string_session := self.json_data.get("string_session")):
|
||||
if self.__raise_error:
|
||||
raise ValueError("ERROR_STRING_SESSION:BASE_THON")
|
||||
return StringSession()
|
||||
return StringSession(string_session)
|
||||
|
||||
@property
|
||||
def app_id(self) -> int:
|
||||
"""Api Id"""
|
||||
if api_id := self.json_data.get("api_id"):
|
||||
return api_id
|
||||
if not (app_id := self.json_data.get("app_id")):
|
||||
raise ValueError("ERROR_APP_ID:BASE_THON")
|
||||
return app_id
|
||||
|
||||
@property
|
||||
def app_hash(self) -> str:
|
||||
"""Api Hash"""
|
||||
if api_hash := self.json_data.get("api_hash"):
|
||||
return api_hash
|
||||
if not (app_hash := self.json_data.get("app_hash")):
|
||||
raise ValueError("ERROR_APP_HASH:BASE_THON")
|
||||
return app_hash
|
||||
|
||||
@property
|
||||
def device(self) -> str:
|
||||
"""Device Model"""
|
||||
if device_model := self.json_data.get("device_model"):
|
||||
return device_model
|
||||
if not (device := self.json_data.get("device")):
|
||||
raise ValueError("ERROR_DEVICE:BASE_THON")
|
||||
return device
|
||||
|
||||
@property
|
||||
def sdk(self) -> str:
|
||||
"""System Version"""
|
||||
if system_version := self.json_data.get("system_version"):
|
||||
return system_version
|
||||
if not (sdk := self.json_data.get("sdk")):
|
||||
raise ValueError("ERROR_SDK:BASE_THON")
|
||||
return sdk
|
||||
|
||||
@property
|
||||
def app_version(self) -> str:
|
||||
"""App Version"""
|
||||
if not (app_version := self.json_data.get("app_version")):
|
||||
raise ValueError("ERROR_APP_VERSION:BASE_THON")
|
||||
return app_version
|
||||
|
||||
@property
|
||||
def lang_pack(self) -> str:
|
||||
"""Lang Pack"""
|
||||
if lang_code := self.json_data.get("lang_code"):
|
||||
return lang_code
|
||||
return self.json_data.get("lang_pack", "en")
|
||||
|
||||
@property
|
||||
def system_lang_code(self) -> str:
|
||||
"""System Lang Code"""
|
||||
if system_lang_code := self.json_data.get("system_lang_code"):
|
||||
return system_lang_code
|
||||
return self.json_data.get("system_lang_pack", "en-us")
|
||||
|
||||
@property
|
||||
def twostep(self) -> str | None:
|
||||
"""2FA"""
|
||||
if password := self.json_data.get("password"):
|
||||
return password
|
||||
if twofa := self.json_data.get("twoFA"):
|
||||
return twofa
|
||||
if twostep := self.json_data.get("twostep"):
|
||||
return twostep
|
||||
|
||||
@property
|
||||
def proxy(self) -> dict | tuple:
|
||||
if not (proxy := self.json_data.get("proxy")):
|
||||
if self.__raise_error:
|
||||
raise ValueError("ERROR_PROXY:BASE_THON")
|
||||
return {}
|
||||
return proxy
|
||||
|
||||
@property
|
||||
def tz_offset(self) -> int:
|
||||
if tz_offset := self.json_data.get("tz_offset", 0):
|
||||
return tz_offset
|
||||
return 0
|
||||
@ -7,135 +7,35 @@ from random import randint
|
||||
from typing import Self
|
||||
|
||||
from telethon import TelegramClient
|
||||
from telethon.sessions import StringSession
|
||||
from telethon.tl.functions.account import UpdateStatusRequest
|
||||
from telethon.tl.functions.help import GetCountriesListRequest, GetNearestDcRequest
|
||||
from telethon.tl.functions.langpack import GetLangPackRequest
|
||||
from telethon.types import JsonNumber, JsonObject, JsonObjectValue, JsonString
|
||||
from telethon.types import (
|
||||
InputPeerUser,
|
||||
JsonNumber,
|
||||
JsonObject,
|
||||
JsonObjectValue,
|
||||
JsonString,
|
||||
User,
|
||||
)
|
||||
|
||||
from basethon.models import BaseThonOptions, BaseThonSearchCodeOptions
|
||||
from basethon.base_data import BaseData
|
||||
from basethon.models import ThonOptions, ThonSearchCodeOptions
|
||||
|
||||
from .constants import API_PACKS
|
||||
from .exceptions import ThonBannedError
|
||||
|
||||
|
||||
class BaseData:
|
||||
def __init__(self, json_data: dict, raise_error: bool):
|
||||
self.__json_data, self.__raise_error = json_data, raise_error
|
||||
|
||||
@property
|
||||
def json_data(self) -> dict:
|
||||
return self.__json_data
|
||||
|
||||
def json_data_edit(self, key: str, value: str | int | bool | None):
|
||||
self.__json_data[key] = value
|
||||
|
||||
@property
|
||||
def session_file(self) -> str:
|
||||
if not (session_file := self.json_data.get("session_file")):
|
||||
if self.__raise_error:
|
||||
raise ValueError("ERROR_SESSION_FILE:BASE_THON")
|
||||
return ""
|
||||
return session_file
|
||||
|
||||
@property
|
||||
def string_session(self) -> StringSession:
|
||||
if not (string_session := self.json_data.get("string_session")):
|
||||
if self.__raise_error:
|
||||
raise ValueError("ERROR_STRING_SESSION:BASE_THON")
|
||||
return StringSession()
|
||||
return StringSession(string_session)
|
||||
|
||||
@property
|
||||
def app_id(self) -> int:
|
||||
"""Api Id"""
|
||||
if api_id := self.json_data.get("api_id"):
|
||||
return api_id
|
||||
if not (app_id := self.json_data.get("app_id")):
|
||||
raise ValueError("ERROR_APP_ID:BASE_THON")
|
||||
return app_id
|
||||
|
||||
@property
|
||||
def app_hash(self) -> str:
|
||||
"""Api Hash"""
|
||||
if api_hash := self.json_data.get("api_hash"):
|
||||
return api_hash
|
||||
if not (app_hash := self.json_data.get("app_hash")):
|
||||
raise ValueError("ERROR_APP_HASH:BASE_THON")
|
||||
return app_hash
|
||||
|
||||
@property
|
||||
def device(self) -> str:
|
||||
"""Device Model"""
|
||||
if device_model := self.json_data.get("device_model"):
|
||||
return device_model
|
||||
if not (device := self.json_data.get("device")):
|
||||
raise ValueError("ERROR_DEVICE:BASE_THON")
|
||||
return device
|
||||
|
||||
@property
|
||||
def sdk(self) -> str:
|
||||
"""System Version"""
|
||||
if system_version := self.json_data.get("system_version"):
|
||||
return system_version
|
||||
if not (sdk := self.json_data.get("sdk")):
|
||||
raise ValueError("ERROR_SDK:BASE_THON")
|
||||
return sdk
|
||||
|
||||
@property
|
||||
def app_version(self) -> str:
|
||||
"""App Version"""
|
||||
if not (app_version := self.json_data.get("app_version")):
|
||||
raise ValueError("ERROR_APP_VERSION:BASE_THON")
|
||||
return app_version
|
||||
|
||||
@property
|
||||
def lang_pack(self) -> str:
|
||||
"""Lang Pack"""
|
||||
if lang_code := self.json_data.get("lang_code"):
|
||||
return lang_code
|
||||
return self.json_data.get("lang_pack", "en")
|
||||
|
||||
@property
|
||||
def system_lang_code(self) -> str:
|
||||
"""System Lang Code"""
|
||||
if system_lang_code := self.json_data.get("system_lang_code"):
|
||||
return system_lang_code
|
||||
return self.json_data.get("system_lang_pack", "en-us")
|
||||
|
||||
@property
|
||||
def twostep(self) -> str | None:
|
||||
"""2FA"""
|
||||
if password := self.json_data.get("password"):
|
||||
return password
|
||||
if twofa := self.json_data.get("twoFA"):
|
||||
return twofa
|
||||
if twostep := self.json_data.get("twostep"):
|
||||
return twostep
|
||||
|
||||
@property
|
||||
def proxy(self) -> dict | tuple:
|
||||
if not (proxy := self.json_data.get("proxy")):
|
||||
if self.__raise_error:
|
||||
raise ValueError("ERROR_PROXY:BASE_THON")
|
||||
return {}
|
||||
return proxy
|
||||
|
||||
@property
|
||||
def tz_offset(self) -> int:
|
||||
if tz_offset := self.json_data.get("tz_offset", 0):
|
||||
return tz_offset
|
||||
return 0
|
||||
|
||||
|
||||
class BaseThon(BaseData):
|
||||
def __init__(self, options: BaseThonOptions):
|
||||
def __init__(self, options: ThonOptions):
|
||||
self.__item = options.item
|
||||
self.__retries = options.retries
|
||||
self.__timeout = options.timeout
|
||||
self._logger = logging.getLogger("basethon")
|
||||
self._async_check_timeout = options.async_check_timeout
|
||||
super().__init__(options.json_data, options.raise_error)
|
||||
self.__client = self.__get_client()
|
||||
self.me: User | InputPeerUser | None = None
|
||||
|
||||
@property
|
||||
def client(self) -> TelegramClient:
|
||||
@ -187,7 +87,7 @@ class BaseThon(BaseData):
|
||||
with contextlib.suppress(Exception):
|
||||
await self.client(GetCountriesListRequest(self.lang_pack, 0))
|
||||
|
||||
async def check(self) -> str:
|
||||
async def _check(self) -> str:
|
||||
try:
|
||||
await self.client.connect()
|
||||
if not await self.client.is_user_authorized():
|
||||
@ -195,6 +95,7 @@ class BaseThon(BaseData):
|
||||
await self.get_additional_data()
|
||||
with contextlib.suppress(Exception):
|
||||
await self.client(UpdateStatusRequest(offline=False))
|
||||
self.me = await self.client.get_me()
|
||||
return "OK"
|
||||
except ConnectionError:
|
||||
await self.disconnect()
|
||||
@ -207,7 +108,24 @@ class BaseThon(BaseData):
|
||||
self._logger.exception(e)
|
||||
return f"ERROR_AUTH:{e}"
|
||||
|
||||
async def search_code(self, options: BaseThonSearchCodeOptions) -> str:
|
||||
async def check(self) -> str:
|
||||
if not self._async_check_timeout:
|
||||
return await self._check()
|
||||
try:
|
||||
return await asyncio.wait_for(self._check(), self._async_check_timeout)
|
||||
except asyncio.TimeoutError:
|
||||
return "ERROR_AUTH:CONNECTION_ERROR:TIMEOUT"
|
||||
|
||||
@property
|
||||
def phone(self) -> str:
|
||||
if not self.me:
|
||||
return ""
|
||||
if isinstance(self.me, User):
|
||||
return self.me.phone or ""
|
||||
return ""
|
||||
|
||||
async def search_code(self, options: ThonSearchCodeOptions | None = None) -> str:
|
||||
options = options or ThonSearchCodeOptions()
|
||||
future = datetime.now() + timedelta(seconds=options.wait_time)
|
||||
while future > datetime.now():
|
||||
async for message in self.client.iter_messages(
|
||||
@ -217,7 +135,12 @@ class BaseThon(BaseData):
|
||||
if not message.date:
|
||||
continue
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
date = now - timedelta(minutes=options.date_delta)
|
||||
date = now - timedelta(seconds=options.date_delta)
|
||||
self._logger.debug(
|
||||
f"{self.__item} {message.text}\n\n"
|
||||
f"Current date: {message.date}\n"
|
||||
f"Delta date: {date}"
|
||||
)
|
||||
if message.date < date:
|
||||
continue
|
||||
if not (match := re.search(options.regexp, message.text)):
|
||||
|
||||
@ -11,7 +11,7 @@ from basethon.async_base_session import AsyncBaseSession
|
||||
from basethon.proxy_parser import ProxyParser
|
||||
|
||||
|
||||
class JsonAsyncConverter(AsyncBaseSession):
|
||||
class JsonAsyncConverter:
|
||||
def __init__(
|
||||
self,
|
||||
base_dir: Path,
|
||||
@ -28,7 +28,7 @@ class JsonAsyncConverter(AsyncBaseSession):
|
||||
proxy: прокси для подключения формат: http:ip:port:user:pswd
|
||||
json_write: записывать в json файл информацию о string_session + proxy?
|
||||
"""
|
||||
super().__init__(base_dir, errors_dir, banned_dir)
|
||||
self.__base_session = AsyncBaseSession(base_dir, errors_dir, banned_dir)
|
||||
self.__api_id, self.__api_hash = 2040, "b18441a1ff607e10a989891a5462e627"
|
||||
self.__json_write = json_write
|
||||
self.__proxy = ProxyParser(proxy).asdict_thon
|
||||
@ -71,7 +71,7 @@ class JsonAsyncConverter(AsyncBaseSession):
|
||||
string_session: str
|
||||
proxy: dict
|
||||
"""
|
||||
async for item, json_file, json_data in self:
|
||||
async for item, json_file, json_data in self.__base_session:
|
||||
_item, _json_file, _json_data = await self._main(item, json_file, json_data)
|
||||
yield _item, _json_file, _json_data
|
||||
|
||||
@ -82,7 +82,7 @@ class JsonAsyncConverter(AsyncBaseSession):
|
||||
"""
|
||||
count = 0
|
||||
self.__json_write = True
|
||||
async for item, json_file, json_data in self:
|
||||
async for item, json_file, json_data in self.__base_session:
|
||||
await self._main(item, json_file, json_data)
|
||||
count += 1
|
||||
return count
|
||||
|
||||
@ -11,7 +11,7 @@ from .base_session import BaseSession
|
||||
from .proxy_parser import ProxyParser
|
||||
|
||||
|
||||
class JsonConverter(BaseSession):
|
||||
class JsonConverter:
|
||||
def __init__(
|
||||
self,
|
||||
base_dir: Path,
|
||||
@ -28,7 +28,7 @@ class JsonConverter(BaseSession):
|
||||
proxy: прокси для подключения формат: http:ip:port:user:pswd
|
||||
json_write: записывать в json файл информацию о string_session + proxy?
|
||||
"""
|
||||
super().__init__(base_dir, errors_dir, banned_dir)
|
||||
self.__base_session = BaseSession(base_dir, errors_dir, banned_dir)
|
||||
self.__api_id, self.__api_hash = 2040, "b18441a1ff607e10a989891a5462e627"
|
||||
self.__json_write = json_write
|
||||
self.__proxy = ProxyParser(proxy).asdict_thon
|
||||
@ -82,7 +82,7 @@ class JsonConverter(BaseSession):
|
||||
"""
|
||||
count = 0
|
||||
self.__json_write = True
|
||||
for item, json_file, json_data in self:
|
||||
for item, json_file, json_data in self.__base_session:
|
||||
self._main(item, json_file, json_data)
|
||||
count += 1
|
||||
return count
|
||||
|
||||
@ -3,18 +3,23 @@ from pathlib import Path
|
||||
|
||||
|
||||
@dataclass
|
||||
class BaseThonOptions:
|
||||
class ThonOptions:
|
||||
item: Path | None
|
||||
json_data: dict
|
||||
retries: int = 10
|
||||
timeout: int = 10
|
||||
raise_error: bool = True
|
||||
async_check_timeout: int | None = 0
|
||||
|
||||
def __post_init__(self):
|
||||
if self.async_check_timeout == 0:
|
||||
self.async_check_timeout = self.retries * self.timeout
|
||||
|
||||
|
||||
@dataclass
|
||||
class BaseThonSearchCodeOptions:
|
||||
class ThonSearchCodeOptions:
|
||||
limit: int = 1
|
||||
date_delta: int = 60
|
||||
date_delta: int = 80
|
||||
wait_time: int = 300
|
||||
entity: int | str = 777000
|
||||
regexp: str = r"\b\d{5,6}\b"
|
||||
|
||||
30
poetry.lock
generated
30
poetry.lock
generated
@ -11,6 +11,17 @@ files = [
|
||||
{file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-timeout"
|
||||
version = "5.0.1"
|
||||
description = "Timeout context manager for asyncio programs"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"},
|
||||
{file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsoner"
|
||||
version = "0.1.0"
|
||||
@ -50,6 +61,23 @@ files = [
|
||||
{file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-socks"
|
||||
version = "2.1.1"
|
||||
description = "Core proxy (SOCKS4, SOCKS5, HTTP tunneling) functionality for Python"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "python-socks-2.1.1.tar.gz", hash = "sha256:3bb68964c97690d5a3eab6c12a772f415725f295b148cbe1ca8870cb47ebcb96"},
|
||||
{file = "python_socks-2.1.1-py3-none-any.whl", hash = "sha256:6174278b0e005bd36b5d43681a0a3d816922852c9bccc2eceb17c60f4c8d4048"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
anyio = ["anyio (>=3.3.4)"]
|
||||
asyncio = ["async-timeout (>=3.0.1)"]
|
||||
curio = ["curio (>=1.4)"]
|
||||
trio = ["trio (>=0.16.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "4.9.1"
|
||||
@ -85,4 +113,4 @@ cryptg = ["cryptg"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "d48b78dd5bc745693c770b4a2f96a8be461e21385bd8f84ae71f9906672cf433"
|
||||
content-hash = "0302bb04698ae890994aa82ee4ad64ef42193bd6f1d0f987d10a448540bf3bf5"
|
||||
|
||||
@ -9,6 +9,8 @@ readme = "README.md"
|
||||
python = "^3.12"
|
||||
telethon = "^1.37.0"
|
||||
jsoner = {git = "https://github.com/trojvn/jsoner.git"}
|
||||
async-timeout = "^5.0.1"
|
||||
python-socks = "2.1.1"
|
||||
|
||||
|
||||
[build-system]
|
||||
|
||||
Reference in New Issue
Block a user