├── .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 | 
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 | 
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
--------------------------------------------------------------------------------