├── .env-example ├── .github └── images │ └── demo.png ├── .gitignore ├── Dockerfile ├── README-FA.md ├── README.md ├── bot ├── __init__.py ├── config │ ├── __init__.py │ ├── config.py │ └── proxies.txt ├── core │ ├── __init__.py │ ├── claimer.py │ ├── headers.py │ └── registrator.py ├── exceptions │ └── __init__.py └── utils │ ├── __init__.py │ ├── launcher.py │ └── logger.py ├── docker-compose.yml ├── main.py └── requirements.txt /.env-example: -------------------------------------------------------------------------------- 1 | API_ID= 2 | API_HASH= 3 | 4 | CLAIM_RETRY= 5 | SLEEP_BETWEEN_CLAIM= 6 | 7 | AUTO_UPGRADE_FARM= 8 | MAX_UPGRADE_LEVEL= 9 | 10 | USE_PROXY_FROM_FILE= -------------------------------------------------------------------------------- /.github/images/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SudoLite/TimeFarmBot/b0689add447f5407e55a91759467868c30cb58b8/.github/images/demo.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # DB 65 | sessions/ 66 | 67 | # Flask stuff: 68 | instance/ 69 | .webassets-cache 70 | 71 | # Scrapy stuff: 72 | .scrapy 73 | 74 | # Sphinx documentation 75 | docs/_build/ 76 | 77 | # PyBuilder 78 | .pybuilder/ 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # pyenv 89 | # For a library or package, you might want to ignore these files since the code is 90 | # intended to run in multiple environments; otherwise, check them in: 91 | # .python-version 92 | 93 | # pipenv 94 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 95 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 96 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 97 | # install all needed dependencies. 98 | #Pipfile.lock 99 | 100 | # poetry 101 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 102 | # This is especially recommended for binary packages to ensure reproducibility, and is more 103 | # commonly ignored for libraries. 104 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 105 | #poetry.lock 106 | 107 | # pdm 108 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 109 | #pdm.lock 110 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 111 | # in version control. 112 | # https://pdm.fming.dev/#use-with-ide 113 | .pdm.toml 114 | 115 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 116 | __pypackages__/ 117 | 118 | # Celery stuff 119 | celerybeat-schedule 120 | celerybeat.pid 121 | 122 | # SageMath parsed files 123 | *.sage.py 124 | 125 | # Environments 126 | .env 127 | .venv 128 | env/ 129 | venv/ 130 | ENV/ 131 | env.bak/ 132 | venv.bak/ 133 | 134 | # Spyder project settings 135 | .spyderproject 136 | .spyproject 137 | 138 | # Rope project settings 139 | .ropeproject 140 | 141 | # mkdocs documentation 142 | /site 143 | 144 | # mypy 145 | .mypy_cache/ 146 | .dmypy.json 147 | dmypy.json 148 | 149 | # Pyre type checker 150 | .pyre/ 151 | 152 | # pytype static type analyzer 153 | .pytype/ 154 | 155 | # Cython debug symbols 156 | cython_debug/ 157 | 158 | # PyCharm 159 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 160 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 161 | # and can be added to the global gitignore or merged into this file. For a more nuclear 162 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 163 | .idea/ 164 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10.11-alpine3.18 2 | 3 | WORKDIR app/ 4 | 5 | COPY requirements.txt requirements.txt 6 | 7 | RUN pip3 install --upgrade pip setuptools wheel 8 | RUN pip3 install --no-warn-script-location --no-cache-dir -r requirements.txt 9 | 10 | COPY . . 11 | 12 | CMD ["python3", "main.py", "-a", "2"] -------------------------------------------------------------------------------- /README-FA.md: -------------------------------------------------------------------------------- 1 | 2 | [](https://t.me/SudoLite) 3 | 4 | ![img1](.github/images/demo.png) 5 | 6 | ## عملکرد 7 | | عملکرد | پشتیبانی شده | 8 | |---------------------------------------------------------------|:------------:| 9 | | چند نخی | ✅ | 10 | | اتصال پروکسی به جلسه | ✅ | 11 | | دریافت خودکار تمام وظایف به جز وظایف تلگرام | ✅ | 12 | | ارتقاء خودکار سطح برای سرعت بیشتر در جمع آوری | ✅ | 13 | | تکرار درخواست در هر دریافت | ✅ | 14 | | پشتیبانی از tdata / pyrogram .session / telethon .session | ✅ | 15 | 16 | ## [تنظیمات](https://github.com/SudoLite/TimeFarmBot/blob/main/.env-example) 17 | | تنظیمات | توضیحات | 18 | |----------------------------|------------------------------------------------------------------------------| 19 | | **API_ID / API_HASH** | داده‌های پلتفرم برای شروع یک جلسه تلگرام (پیش‌فرض - اندروید) | 20 | | **CLAIM_RETRY** | تعداد تلاش‌ها در صورت ناموفق بودن **دریافت ها** _(مثال: 3)_ | 21 | | **SLEEP_BETWEEN_CLAIM** | تأخیر بین **دریافت ها** به دقیقه _(مثال: 180)_ | 22 | | **AUTO_UPGRADE_FARM** | باید افزایش سطح را انجام بدهم _(True / False)_ | 23 | | **MAX_UPGRADE_LEVEL** | سظح آخر شما _(up to 4)_ | 24 | | **USE_PROXY_FROM_FILE** | آیا از پروکسی از فایل `bot/config/proxies.txt` استفاده شود (True / False) | 25 | 26 | ## نصب 27 | می‌توانید [**مخزن**](https://github.com/SudoLite/TimeFarmBot) را با کلون کردن به سیستم خود دانلود کرده و وابستگی‌های لازم را نصب کنید: 28 | ```shell 29 | ~ >>> git clone https://github.com/SudoLite/TimeFarmBot.git 30 | ~ >>> cd TimeFarmBot 31 | 32 | # اگر از جلسات Telethon استفاده می‌کنید، شاخه "converter" را کلون کنید 33 | ~ >>> git clone https://github.com/SudoLite/TimeFarmBot.git -b converter 34 | ~ >>> cd TimeFarmBot 35 | 36 | #لینوکس 37 | ~/TimeFarmBot >>> python3 -m venv venv 38 | ~/TimeFarmBot >>> source venv/bin/activate 39 | ~/TimeFarmBot >>> pip3 install -r requirements.txt 40 | ~/TimeFarmBot >>> cp .env-example .env 41 | ~/TimeFarmBot >>> nano .env # در اینجا باید API_ID و API_HASH خود را مشخص کنید، بقیه به طور پیش‌فرض گرفته می‌شوند 42 | ~/TimeFarmBot >>> python3 main.py 43 | 44 | #ویندوز 45 | ~/TimeFarmBot >>> python -m venv venv 46 | ~/TimeFarmBot >>> venv\Scripts\activate 47 | ~/TimeFarmBot >>> pip install -r requirements.txt 48 | ~/TimeFarmBot >>> copy .env-example .env 49 | ~/TimeFarmBot >>> # API_ID و API_HASH خود را مشخص کنید، بقیه به طور پیش‌فرض گرفته می‌شوند 50 | ~/TimeFarmBot >>> python main.py 51 | ``` 52 | 53 | همچنین برای راه‌اندازی سریع می‌توانید از آرگومان‌ها استفاده کنید، به عنوان مثال: 54 | ```shell 55 | ~/TimeFarmBot >>> python3 main.py --action (1/2) 56 | # یا 57 | ~/TimeFarmBot >>> python3 main.py -a (1/2) 58 | 59 | #1 - ایجاد جلسه 60 | #2 - اجرای کلیکر 61 | ``` 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [](https://t.me/SudoLite) 3 | 4 | ![img1](.github/images/demo.png) 5 | 6 | > 🇮🇷 README available in Persian [here](README-FA.md) 7 | 8 | > Special Thanks [shamhi](https://github.com/shamhi) 9 | 10 | ## Functionality 11 | | Functional | Supported | 12 | |----------------------------------------------------------------|:---------:| 13 | | Multithreading | ✅ | 14 | | Binding a proxy to a session | ✅ | 15 | | Auto get all tasks except telegram tasks | ✅ | 16 | | Auto upgrade level for boost farming | ✅ | 17 | | Retry request per claim | ✅ | 18 | | Support tdata / pyrogram .session / telethon .session | ✅ | 19 | 20 | ## [Settings](https://github.com/SudoLite/TimeFarmBot/blob/main/.env-example) 21 | | Setting | Description | 22 | |---------------------------|-------------------------------------------------------------------------------| 23 | | **API_ID / API_HASH** | Platform data from which to launch a Telegram session (stock - Android) | 24 | | **CLAIM_RETRY** | Number of tries if **Claim** is unsuccessful _(e.g., 3)_ | 25 | | **SLEEP_BETWEEN_CLAIM** | Delay between **Claim** in minutes _(e.g., 180)_ | 26 | | **AUTO_UPGRADE_FARM** | Should I improve farmer level _(True / False)_ | 27 | | **MAX_UPGRADE_LEVEL** | Maximum level of farmer _(up to 4)_ | 28 | | **USE_PROXY_FROM_FILE** | Whether to use proxy from the `bot/config/proxies.txt` file (True / False) | 29 | 30 | ## Installation 31 | You can download the [**Repository**](https://github.com/SudoLite/TimeFarmBot) by cloning it to your system and installing the necessary dependencies: 32 | ```shell 33 | ~ >>> git clone https://github.com/SudoLite/TimeFarmBot.git 34 | ~ >>> cd TimeFarmBot 35 | 36 | # If you are using Telethon sessions, then clone the "converter" branch 37 | ~ >>> git clone https://github.com/SudoLite/TimeFarmBot.git -b converter 38 | ~ >>> cd TimeFarmBot 39 | 40 | #Linux 41 | ~/TimeFarmBot >>> python3 -m venv venv 42 | ~/TimeFarmBot >>> source venv/bin/activate 43 | ~/TimeFarmBot >>> pip3 install -r requirements.txt 44 | ~/TimeFarmBot >>> cp .env-example .env 45 | ~/TimeFarmBot >>> nano .env # Here you must specify your API_ID and API_HASH, the rest is taken by default 46 | ~/TimeFarmBot >>> python3 main.py 47 | 48 | #Windows 49 | ~/TimeFarmBot >>> python -m venv venv 50 | ~/TimeFarmBot >>> venv\Scripts\activate 51 | ~/TimeFarmBot >>> pip install -r requirements.txt 52 | ~/TimeFarmBot >>> copy .env-example .env 53 | ~/TimeFarmBot >>> # Specify your API_ID and API_HASH, the rest is taken by default 54 | ~/TimeFarmBot >>> python main.py 55 | ``` 56 | 57 | Also, for a quick launch, you can use arguments, for example: 58 | ```shell 59 | ~/TimeFarmBot >>> python3 main.py --action (1/2) 60 | # Or 61 | ~/TimeFarmBot >>> python3 main.py -a (1/2) 62 | 63 | #1 - Create session 64 | #2 - Run clicker 65 | ``` -------------------------------------------------------------------------------- /bot/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '1.1' 2 | -------------------------------------------------------------------------------- /bot/config/__init__.py: -------------------------------------------------------------------------------- 1 | from .config import settings 2 | -------------------------------------------------------------------------------- /bot/config/config.py: -------------------------------------------------------------------------------- 1 | from pydantic_settings import BaseSettings, SettingsConfigDict 2 | 3 | 4 | class Settings(BaseSettings): 5 | model_config = SettingsConfigDict(env_file=".env", env_ignore_empty=True) 6 | 7 | API_ID: int 8 | API_HASH: str 9 | 10 | CLAIM_RETRY: int = 1 11 | SLEEP_BETWEEN_CLAIM: int = 240 12 | 13 | AUTO_UPGRADE_FARM: bool = True 14 | MAX_UPGRADE_LEVEL: int = 6 15 | 16 | USE_PROXY_FROM_FILE: bool = False 17 | 18 | 19 | settings = Settings() 20 | -------------------------------------------------------------------------------- /bot/config/proxies.txt: -------------------------------------------------------------------------------- 1 | type://user:pass@ip:port 2 | type://user:pass:ip:port 3 | type://ip:port:user:pass 4 | type://ip:port@user:pass 5 | type://ip:port -------------------------------------------------------------------------------- /bot/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SudoLite/TimeFarmBot/b0689add447f5407e55a91759467868c30cb58b8/bot/core/__init__.py -------------------------------------------------------------------------------- /bot/core/claimer.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from time import time 3 | from datetime import datetime 4 | from urllib.parse import unquote 5 | 6 | import aiohttp 7 | from aiohttp_proxy import ProxyConnector 8 | from better_proxy import Proxy 9 | from pyrogram import Client 10 | from pyrogram.errors import Unauthorized, UserDeactivated, AuthKeyUnregistered 11 | from pyrogram.raw.functions.messages import RequestWebView 12 | 13 | from bot.config import settings 14 | from bot.utils import logger 15 | from bot.exceptions import InvalidSession 16 | from .headers import headers 17 | 18 | 19 | class Claimer: 20 | def __init__(self, tg_client: Client): 21 | self.session_name = tg_client.name 22 | self.tg_client = tg_client 23 | 24 | async def get_tg_web_data(self, proxy: str | None) -> str: 25 | if proxy: 26 | proxy = Proxy.from_str(proxy) 27 | proxy_dict = dict( 28 | scheme=proxy.protocol, 29 | hostname=proxy.host, 30 | port=proxy.port, 31 | username=proxy.login, 32 | password=proxy.password 33 | ) 34 | else: 35 | proxy_dict = None 36 | 37 | self.tg_client.proxy = proxy_dict 38 | 39 | try: 40 | if not self.tg_client.is_connected: 41 | try: 42 | await self.tg_client.connect() 43 | except (Unauthorized, UserDeactivated, AuthKeyUnregistered): 44 | raise InvalidSession(self.session_name) 45 | 46 | web_view = await self.tg_client.invoke(RequestWebView( 47 | peer=await self.tg_client.resolve_peer('TimeFarmCryptoBot'), 48 | bot=await self.tg_client.resolve_peer('TimeFarmCryptoBot'), 49 | platform='android', 50 | from_bot_menu=False, 51 | url='https://tg-tap-miniapp.laborx.io/' 52 | )) 53 | 54 | auth_url = web_view.url 55 | tg_web_data = unquote( 56 | string=auth_url.split('tgWebAppData=', maxsplit=1)[1].split('&tgWebAppVersion', maxsplit=1)[0]) 57 | 58 | if self.tg_client.is_connected: 59 | await self.tg_client.disconnect() 60 | 61 | return tg_web_data 62 | 63 | except InvalidSession as error: 64 | raise error 65 | 66 | except Exception as error: 67 | logger.error(f"{self.session_name} | Unknown error during Authorization: {error}") 68 | await asyncio.sleep(delay=3) 69 | 70 | async def login(self, http_client: aiohttp.ClientSession, tg_web_data: dict[str]) -> dict[str]: 71 | try: 72 | response = await http_client.post(url='https://tg-bot-tap.laborx.io/api/v1/auth/validate-init/v2', data={"initData":tg_web_data,"platform":"android"}) 73 | response.raise_for_status() 74 | 75 | response_json = await response.json() 76 | 77 | json_data = { 78 | 'token': response_json['token'], 79 | 'level': response_json['info']['level'], 80 | 'levelDescriptions': response_json['levelDescriptions'] 81 | } 82 | 83 | return json_data 84 | except Exception as error: 85 | logger.error(f"{self.session_name} | Unknown error while getting Access Token: {error}") 86 | await asyncio.sleep(delay=3) 87 | 88 | async def get_mining_data(self, http_client: aiohttp.ClientSession) -> dict[str]: 89 | try: 90 | response = await http_client.get('https://tg-bot-tap.laborx.io/api/v1/farming/info') 91 | response.raise_for_status() 92 | 93 | response_json = await response.json() 94 | 95 | return response_json 96 | except Exception as error: 97 | logger.error(f"{self.session_name} | Unknown error when getting Profile Data: {error}") 98 | await asyncio.sleep(delay=3) 99 | 100 | async def get_tasks_list(self, http_client: aiohttp.ClientSession) -> dict[str]: 101 | try: 102 | response = await http_client.get('https://tg-bot-tap.laborx.io/api/v1/tasks') 103 | response.raise_for_status() 104 | 105 | response_json = await response.json() 106 | 107 | return response_json 108 | except Exception as error: 109 | logger.error(f"{self.session_name} | Unknown error when getting Tasks Data: {error}") 110 | await asyncio.sleep(delay=3) 111 | 112 | async def get_task_data(self, http_client: aiohttp.ClientSession, task_id: str) -> dict[str]: 113 | try: 114 | response = await http_client.get(f'https://tg-bot-tap.laborx.io/api/v1/tasks/{task_id}') 115 | response.raise_for_status() 116 | 117 | response_json = await response.json() 118 | 119 | return response_json 120 | except Exception as error: 121 | logger.error(f"{self.session_name} | Unknown error when getting Task Data: {error}") 122 | await asyncio.sleep(delay=3) 123 | 124 | async def upgrade_level(self, http_client: aiohttp.ClientSession) -> dict[str]: 125 | try: 126 | response = await http_client.post(url=f'https://tg-bot-tap.laborx.io/api/v1/me/level/upgrade', json={}) 127 | response.raise_for_status() 128 | 129 | response_json = await response.json() 130 | 131 | return response_json 132 | 133 | except Exception as error: 134 | logger.error(f"{self.session_name} | Unknown error while Upgrade Level: {error}") 135 | await asyncio.sleep(delay=3) 136 | 137 | async def task_claim(self, http_client: aiohttp.ClientSession, task_id: str) -> str: 138 | try: 139 | response = await http_client.post(url=f'https://tg-bot-tap.laborx.io/api/v1/tasks/{task_id}/claims', json={}) 140 | response.raise_for_status() 141 | 142 | return response.text 143 | 144 | except Exception as error: 145 | #logger.error(f"{self.session_name} | Unknown error while claim task: {error}") 146 | await asyncio.sleep(delay=3) 147 | 148 | async def task_submiss(self, http_client: aiohttp.ClientSession, task_id: str) -> str: 149 | try: 150 | response = await http_client.post(url=f'https://tg-bot-tap.laborx.io/api/v1/tasks/{task_id}/submissions', json={}) 151 | response.raise_for_status() 152 | 153 | return response.text 154 | 155 | except Exception as error: 156 | #logger.error(f"{self.session_name} | Unknown error while submissions task: {error}") 157 | await asyncio.sleep(delay=3) 158 | 159 | async def start_mine(self, http_client: aiohttp.ClientSession) -> dict[str]: 160 | try: 161 | response = await http_client.post('https://tg-bot-tap.laborx.io/api/v1/farming/start', json={}) 162 | response.raise_for_status() 163 | 164 | if response.status == 200: 165 | return { 166 | 'ok': True, 167 | 'code': 200 168 | } 169 | 170 | except Exception as error: 171 | #logger.error(f"{self.session_name} | Unknown error when start miner: {error}") 172 | await asyncio.sleep(delay=3) 173 | 174 | return { 175 | 'ok': True, 176 | 'code': response.status 177 | } 178 | 179 | async def finish_mine(self, http_client: aiohttp.ClientSession) -> dict[str]: 180 | try: 181 | response = await http_client.post('https://tg-bot-tap.laborx.io/api/v1/farming/finish', json={}) 182 | response.raise_for_status() 183 | 184 | response_json = await response.json() 185 | 186 | if response.status == 200: 187 | return { 188 | 'ok': True, 189 | 'code': 200, 190 | 'balance': int(response_json['balance']) 191 | } 192 | 193 | except Exception as error: 194 | #logger.error(f"{self.session_name} | Unknown error when Claiming: {error}") 195 | await asyncio.sleep(delay=3) 196 | 197 | return { 198 | 'ok': True, 199 | 'code': response.status 200 | } 201 | 202 | async def check_proxy(self, http_client: aiohttp.ClientSession, proxy: Proxy) -> None: 203 | try: 204 | response = await http_client.get(url='https://httpbin.org/ip', timeout=aiohttp.ClientTimeout(5)) 205 | ip = (await response.json()).get('origin') 206 | logger.info(f"{self.session_name} | Proxy IP: {ip}") 207 | except Exception as error: 208 | logger.error(f"{self.session_name} | Proxy: {proxy} | Error: {error}") 209 | 210 | async def run(self, proxy: str | None) -> None: 211 | access_token_created_time = 0 212 | available = False 213 | 214 | proxy_conn = ProxyConnector().from_url(proxy) if proxy else None 215 | 216 | async with aiohttp.ClientSession(headers=headers, connector=proxy_conn) as http_client: 217 | if proxy: 218 | await self.check_proxy(http_client=http_client, proxy=proxy) 219 | 220 | while True: 221 | try: 222 | if time() - access_token_created_time >= 3600: 223 | tg_web_data = await self.get_tg_web_data(proxy=proxy) 224 | login_data = await self.login(http_client=http_client, tg_web_data=tg_web_data) 225 | 226 | http_client.headers["Authorization"] = f"Bearer {login_data['token']}" 227 | headers["Authorization"] = f"Bearer {login_data['token']}" 228 | 229 | level_num = int(login_data['level']) 230 | levelDescriptions = login_data['levelDescriptions'] 231 | 232 | access_token_created_time = time() 233 | 234 | tasks_data = await self.get_tasks_list(http_client=http_client) 235 | 236 | for task in tasks_data: 237 | task_id = task["id"] 238 | task_title = task["title"] 239 | task_type = task["type"] 240 | if "submission" in task.keys(): 241 | status = task["submission"]["status"] 242 | if status == "CLAIMED": 243 | continue 244 | 245 | if status == "COMPLETED": 246 | task_data_claim = await self.task_claim(http_client=http_client, task_id=task_id) 247 | if task_data_claim == "OK": 248 | logger.success(f"{self.session_name} | Successful claim | " 249 | f"Task Title: {task_title}") 250 | continue 251 | 252 | if task_type == "TELEGRAM": 253 | continue 254 | 255 | task_data_submiss = await self.task_submiss(http_client=http_client, task_id=task_id) 256 | if task_data_submiss != "OK": 257 | #logger.error(f"{self.session_name} | Failed Send Submission Task: {task_title}") 258 | continue 259 | 260 | task_data_x = await self.get_task_data(http_client=http_client, task_id=task_id) 261 | status = task_data_x["submission"]["status"] 262 | if status != "COMPLETED": 263 | logger.error(f"{self.session_name} | Task is not completed: {task_title}") 264 | continue 265 | 266 | task_data_claim_x = await self.task_claim(http_client=http_client, task_id=task_id) 267 | if task_data_claim_x == "OK": 268 | logger.success(f"{self.session_name} | Successful claim | " 269 | f"Task Title: {task_title}") 270 | continue 271 | 272 | 273 | mining_data = await self.get_mining_data(http_client=http_client) 274 | 275 | balance = int(float(mining_data['balance'])) 276 | farmingReward = int(mining_data['farmingReward']) 277 | farmingDurationInSec = int(mining_data['farmingDurationInSec']) 278 | 279 | if mining_data['activeFarmingStartedAt'] != None: 280 | available = True 281 | 282 | if int(farmingDurationInSec / 60) != settings.SLEEP_BETWEEN_CLAIM: 283 | settings.SLEEP_BETWEEN_CLAIM = int(farmingDurationInSec / 60) 284 | 285 | logger.info(f"{self.session_name} | Balance: {balance} | " 286 | f"Earning: {available} | " 287 | f"Speed: x{(level_num + 1)}") 288 | 289 | if available == False: 290 | status_start = await self.start_mine(http_client=http_client) 291 | if status_start['ok'] and status_start['code'] == 200: 292 | logger.success(f"{self.session_name} | Successful Mine Started | " 293 | f"Balance: {balance} | " 294 | f"Speed: Farming (x{(level_num + 1)})") 295 | 296 | if available: 297 | retry = 1 298 | while retry <= settings.CLAIM_RETRY: 299 | status = await self.finish_mine(http_client=http_client) 300 | if status['ok'] and status['code'] == 200: 301 | mining_data = await self.get_mining_data(http_client=http_client) 302 | new_balance = int(float(mining_data['balance'])) 303 | balance = new_balance 304 | 305 | if(new_balance == int(status['balance'])): 306 | status_start = await self.start_mine(http_client=http_client) 307 | if status_start['ok'] and status_start['code'] == 200: 308 | logger.success(f"{self.session_name} | Successful claim | " 309 | f"Balance: {new_balance} (+{farmingReward})") 310 | logger.info(f"Next claim in {settings.SLEEP_BETWEEN_CLAIM}min") 311 | break 312 | elif status['code'] == 403: 313 | break 314 | 315 | logger.info(f"{self.session_name} | Retry {retry} of {settings.CLAIM_RETRY}") 316 | retry += 1 317 | 318 | available = False 319 | 320 | if (settings.AUTO_UPGRADE_FARM is True and level_num < settings.MAX_UPGRADE_LEVEL): 321 | next_level = level_num + 1 322 | max_level_bot = len(levelDescriptions) - 1 323 | if next_level <= max_level_bot: 324 | for level_data in levelDescriptions: 325 | lvl_dt_num = int(level_data['level']) 326 | if next_level == lvl_dt_num: 327 | lvl_price = int(level_data['price']) 328 | if lvl_price <= balance: 329 | logger.info(f"{self.session_name} | Sleep 5s before upgrade level farming to {next_level} lvl") 330 | await asyncio.sleep(delay=5) 331 | 332 | out_data = await self.upgrade_level(http_client=http_client) 333 | if out_data['balance']: 334 | logger.success(f"{self.session_name} | Level farming upgraded to {next_level} lvl | " 335 | f"Balance: {out_data['balance']} | " 336 | f"Speed: x{level_data['farmMultiplicator']}") 337 | 338 | await asyncio.sleep(delay=1) 339 | 340 | 341 | except InvalidSession as error: 342 | raise error 343 | 344 | except Exception as error: 345 | logger.error(f"{self.session_name} | Unknown error: {error}") 346 | await asyncio.sleep(delay=3) 347 | 348 | else: 349 | logger.info(f"Sleep 1min") 350 | await asyncio.sleep(delay=60) 351 | 352 | 353 | async def run_claimer(tg_client: Client, proxy: str | None): 354 | try: 355 | await Claimer(tg_client=tg_client).run(proxy=proxy) 356 | except InvalidSession: 357 | logger.error(f"{tg_client.name} | Invalid Session") 358 | -------------------------------------------------------------------------------- /bot/core/headers.py: -------------------------------------------------------------------------------- 1 | headers = { 2 | 'Accept': '*/*', 3 | 'Accept-Language': 'ru,en;q=0.9,en-GB;q=0.8,en-US;q=0.7', 4 | 'Connection': 'keep-alive', 5 | 'Origin': 'https://tg-tap-miniapp.laborx.io', 6 | 'Referer': 'https://tg-tap-miniapp.laborx.io/', 7 | 'Sec-Fetch-Dest': 'empty', 8 | 'Priority': 'u=1, i', 9 | 'Sec-Fetch-Mode': 'cors', 10 | 'Sec-Fetch-Site': 'same-site', 11 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0', 12 | 'sec-ch-ua': '"Microsoft Edge";v="123", "Not:A-Brand";v="8", "Chromium";v="123", "Microsoft Edge WebView2";v="123"', 13 | 'sec-ch-ua-mobile': '?0', 14 | 'sec-ch-ua-platform': '"Windows"', 15 | } 16 | -------------------------------------------------------------------------------- /bot/core/registrator.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client 2 | 3 | from bot.config import settings 4 | from bot.utils import logger 5 | 6 | 7 | async def register_sessions() -> None: 8 | API_ID = settings.API_ID 9 | API_HASH = settings.API_HASH 10 | 11 | if not API_ID or not API_HASH: 12 | raise ValueError("API_ID and API_HASH not found in the .env file.") 13 | 14 | session_name = input('\nEnter the session name (press Enter to exit): ') 15 | 16 | if not session_name: 17 | return None 18 | 19 | session = Client( 20 | name=session_name, 21 | api_id=API_ID, 22 | api_hash=API_HASH, 23 | workdir="sessions/" 24 | ) 25 | 26 | async with session: 27 | user_data = await session.get_me() 28 | 29 | logger.success(f'Session added successfully @{user_data.username} | {user_data.first_name} {user_data.last_name}') 30 | -------------------------------------------------------------------------------- /bot/exceptions/__init__.py: -------------------------------------------------------------------------------- 1 | class InvalidSession(BaseException): 2 | ... 3 | -------------------------------------------------------------------------------- /bot/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .logger import logger 2 | from . import launcher 3 | 4 | 5 | import os 6 | 7 | if not os.path.exists(path='sessions'): 8 | os.mkdir(path='sessions') 9 | -------------------------------------------------------------------------------- /bot/utils/launcher.py: -------------------------------------------------------------------------------- 1 | import os 2 | import glob 3 | import asyncio 4 | import argparse 5 | from itertools import cycle 6 | 7 | from pyrogram import Client 8 | from better_proxy import Proxy 9 | 10 | from bot.config import settings 11 | from bot.utils import logger 12 | from bot.core.claimer import run_claimer 13 | from bot.core.registrator import register_sessions 14 | 15 | 16 | start_text = """ 17 | 88888888888 d8b 8888888888 888888b. 888 18 | 888 Y8P 888 888 "88b 888 19 | 888 888 888 .88P 888 20 | 888 888 88888b.d88b. .d88b. 8888888 8888b. 888d888 88888b.d88b. 8888888K. .d88b. 888888 21 | 888 888 888 "888 "88b d8P Y8b 888 "88b 888P" 888 "888 "88b 888 "Y88b d88""88b 888 22 | 888 888 888 888 888 88888888 888 .d888888 888 888 888 888 888 888 888 888 888 23 | 888 888 888 888 888 Y8b. 888 888 888 888 888 888 888 888 d88P Y88..88P Y88b. 24 | 888 888 888 888 888 "Y8888 888 "Y888888 888 888 888 888 8888888P" "Y88P" "Y888 25 | 26 | 27 | || Created By Sudolite || 28 | 29 | Select an action: 30 | 31 | 1. Create session 32 | 2. Run claimer 33 | """ 34 | 35 | 36 | def get_session_names() -> list[str]: 37 | session_names = glob.glob('sessions/*.session') 38 | session_names = [os.path.splitext(os.path.basename(file))[0] for file in session_names] 39 | 40 | return session_names 41 | 42 | 43 | def get_proxies() -> list[Proxy]: 44 | if settings.USE_PROXY_FROM_FILE: 45 | with open(file='bot/config/proxies.txt', encoding='utf-8-sig') as file: 46 | proxies = [Proxy.from_str(proxy=row.strip()).as_url for row in file] 47 | else: 48 | proxies = [] 49 | 50 | return proxies 51 | 52 | 53 | async def get_tg_clients() -> list[Client]: 54 | session_names = get_session_names() 55 | 56 | if not session_names: 57 | raise FileNotFoundError("Not found session files") 58 | 59 | if not settings.API_ID or not settings.API_HASH: 60 | raise ValueError("API_ID and API_HASH not found in the .env file.") 61 | 62 | tg_clients = [Client( 63 | name=session_name, 64 | api_id=settings.API_ID, 65 | api_hash=settings.API_HASH, 66 | workdir='sessions/', 67 | plugins=dict(root='bot/plugins') 68 | ) for session_name in session_names] 69 | 70 | return tg_clients 71 | 72 | 73 | async def process() -> None: 74 | parser = argparse.ArgumentParser() 75 | parser.add_argument('-a', '--action', type=int, help='Action to perform') 76 | 77 | logger.info(f"Detected {len(get_session_names())} sessions | {len(get_proxies())} proxies") 78 | 79 | action = parser.parse_args().action 80 | 81 | if not action: 82 | print(start_text) 83 | 84 | while True: 85 | action = input("> ") 86 | 87 | if not action.isdigit(): 88 | logger.warning("Action must be number") 89 | elif action not in ['1', '2']: 90 | logger.warning("Action must be 1 or 2") 91 | else: 92 | action = int(action) 93 | break 94 | 95 | if action == 1: 96 | await register_sessions() 97 | elif action == 2: 98 | tg_clients = await get_tg_clients() 99 | 100 | await run_tasks(tg_clients=tg_clients) 101 | 102 | 103 | async def run_tasks(tg_clients: list[Client]): 104 | proxies = get_proxies() 105 | proxies_cycle = cycle(proxies) if proxies else None 106 | tasks = [asyncio.create_task(run_claimer(tg_client=tg_client, proxy=next(proxies_cycle) if proxies_cycle else None)) 107 | for tg_client in tg_clients] 108 | 109 | await asyncio.gather(*tasks) 110 | -------------------------------------------------------------------------------- /bot/utils/logger.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from loguru import logger 3 | 4 | 5 | logger.remove() 6 | logger.add(sink=sys.stdout, format="{time:YYYY-MM-DD HH:mm:ss}" 7 | " | {level: <8}" 8 | " | {line}" 9 | " - {message}") 10 | logger = logger.opt(colors=True) 11 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | bot: 4 | container_name: 'TimeFarmBot' 5 | build: 6 | context: . 7 | stop_signal: SIGINT 8 | restart: unless-stopped 9 | command: "python3 main.py -a 2" 10 | volumes: 11 | - .:/app -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from contextlib import suppress 3 | 4 | from bot.utils.launcher import process 5 | 6 | 7 | async def main(): 8 | await process() 9 | 10 | 11 | if __name__ == '__main__': 12 | with suppress(KeyboardInterrupt): 13 | asyncio.run(main()) 14 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SudoLite/TimeFarmBot/b0689add447f5407e55a91759467868c30cb58b8/requirements.txt --------------------------------------------------------------------------------