diff --git a/basethon/__init__.py b/basethon/__init__.py index 4a970d9..7292f80 100644 --- a/basethon/__init__.py +++ b/basethon/__init__.py @@ -1,5 +1,14 @@ +from .async_base_session import AsyncBaseSession from .base_session import BaseSession from .base_thon import BaseData, BaseThon +from .json_async_converter import JsonAsyncConverter from .json_converter import JsonConverter -__all__ = ["BaseThon", "BaseSession", "JsonConverter", "BaseData"] +__all__ = [ + "BaseThon", + "BaseSession", + "JsonConverter", + "BaseData", + "JsonAsyncConverter", + "AsyncBaseSession", +] diff --git a/basethon/async_base_session.py b/basethon/async_base_session.py new file mode 100644 index 0000000..cc60ddc --- /dev/null +++ b/basethon/async_base_session.py @@ -0,0 +1,30 @@ +from pathlib import Path +from typing import AsyncGenerator + +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.errors_dir = errors_dir + self.banned_dir = banned_dir + self.json_errors: set[Path] = set() + + async def iter_sessions(self) -> AsyncGenerator[tuple[Path, Path, dict], None]: + """ + Поиск сессий в base_dir + Возвращает генератор с кортежами (item, json_path, json_data) + Если json_file не найден, то добавляет его (не существующий) в self.json_errors + Если json_data не найден, то добавляет его (не существующий) в self.json_errors + """ + for item in self.base_dir.glob("*.session"): + json_file = item.with_suffix(".json") + if not json_file.is_file(): + self.json_errors.add(json_file) + continue + + if not (json_data := await json_read(json_file)): + self.json_errors.add(json_file) + continue + yield item, json_file, json_data diff --git a/basethon/base_session.py b/basethon/base_session.py index 246f6cb..49e10ee 100644 --- a/basethon/base_session.py +++ b/basethon/base_session.py @@ -1,7 +1,7 @@ from pathlib import Path from typing import Generator -from jsoner import json_read_sync +from jsoner.sync import json_read class BaseSession: @@ -26,7 +26,7 @@ class BaseSession: if not json_file.is_file(): self.json_errors.add(json_file) continue - if not (json_data := json_read_sync(json_file)): + if not (json_data := json_read(json_file)): self.json_errors.add(json_file) continue yield item, json_file, json_data diff --git a/basethon/base_thon.py b/basethon/base_thon.py index e241094..6a4f109 100644 --- a/basethon/base_thon.py +++ b/basethon/base_thon.py @@ -14,7 +14,7 @@ from telethon.tl.functions.help import GetCountriesListRequest, GetNearestDcRequ from telethon.tl.functions.langpack import GetLangPackRequest from telethon.types import JsonNumber, JsonObject, JsonObjectValue, JsonString -from .consts import API_PACKS +from .constants import API_PACKS from .exceptions import ThonBannedError diff --git a/basethon/consts.py b/basethon/constants.py similarity index 100% rename from basethon/consts.py rename to basethon/constants.py diff --git a/basethon/json_async_converter.py b/basethon/json_async_converter.py new file mode 100644 index 0000000..1286046 --- /dev/null +++ b/basethon/json_async_converter.py @@ -0,0 +1,88 @@ +import asyncio +import contextlib +from pathlib import Path +from typing import AsyncGenerator + +from jsoner import json_write_async +from telethon import TelegramClient +from telethon.sessions import StringSession + +from basethon.async_base_session import AsyncBaseSession +from basethon.proxy_parser import ProxyParser + + +class JsonAsyncConverter(AsyncBaseSession): + def __init__( + self, + base_dir: Path, + errors_dir: Path, + banned_dir: Path, + proxy: str, + json_write: bool = True, + ): + """ + Конвертер сессий в json + base_dir: директория с сессиями + errors_dir: директория куда перемещать сессии с ошибками + banned_dir: директория куда перемещать забаненные сессии + proxy: прокси для подключения формат: http:ip:port:user:pswd + json_write: записывать в json файл информацию о string_session + proxy? + """ + super().__init__(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 + + async def _main( + self, + item: Path, + json_file: Path, + json_data: dict, + ) -> tuple[Path, Path, dict]: + """ + Конвертация сессии в json (string_session) + Возвращает кортеж (item, json_file, json_data) + """ + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + client = TelegramClient(str(item), self.__api_id, self.__api_hash) + ss = StringSession() + ss._server_address = client.session.server_address # type: ignore + ss._takeout_id = client.session.takeout_id # type: ignore + ss._auth_key = client.session.auth_key # type: ignore + ss._dc_id = client.session.dc_id # type: ignore + ss._port = client.session.port # type: ignore + string_session = ss.save() + with contextlib.suppress(Exception): + await client.disconnect() # type: ignore + del client, ss + loop.close() + json_data["proxy"] = self.__proxy + json_data["string_session"] = string_session + if self.__json_write: + await json_write_async(json_file, json_data) + return item, json_file, json_data + + async def iter(self) -> AsyncGenerator[tuple[Path, Path, dict], None]: + """ + Поиск сессий в base_dir + конвертация сессии в json (string_session) + Возвращает генератор с кортежами (item, json_file, json_data) + json_data содержит: + string_session: str + proxy: dict + """ + async for item, json_file, json_data in self.iter_sessions(): + _item, _json_file, _json_data = await self._main(item, json_file, json_data) + yield _item, _json_file, _json_data + + async def main(self) -> int: + """ + Основная функция для записи сессий в json файлы + Возвращает количество записанных сессий + """ + count = 0 + self.__json_write = True + async for item, json_file, json_data in self.iter_sessions(): + await self._main(item, json_file, json_data) + count += 1 + return count