├── database
├── __init__.py
├── sessions.db
├── on_startup.py
└── actions.py
├── core
├── __init__.py
├── headers.py
├── create_sessions.py
└── start_farming.py
├── utils
├── __init__.py
├── eval_js.py
├── monkeypatching.py
└── read_session_json_file.py
├── exceptions
└── __init__.py
├── data
├── proxies.txt
└── config.py
├── requirements.txt
├── README.md
└── main.py
/database/__init__.py:
--------------------------------------------------------------------------------
1 | from .on_startup import on_startup_database
2 |
--------------------------------------------------------------------------------
/database/sessions.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nazavod777/notcoin_bot/HEAD/database/sessions.db
--------------------------------------------------------------------------------
/core/__init__.py:
--------------------------------------------------------------------------------
1 | from .create_sessions import create_sessions
2 | from .start_farming import start_farming
3 |
--------------------------------------------------------------------------------
/utils/__init__.py:
--------------------------------------------------------------------------------
1 | from .eval_js import eval_js
2 | from .read_session_json_file import read_session_json_file
3 |
--------------------------------------------------------------------------------
/exceptions/__init__.py:
--------------------------------------------------------------------------------
1 | class InvalidSession(BaseException):
2 | pass
3 |
4 |
5 | class TurboExpired(BaseException):
6 | pass
7 |
--------------------------------------------------------------------------------
/data/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
6 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohttp>=3.8.6
2 | TGConvertor>=0.0.7
3 | loguru>=0.7.2
4 | pyuseragents>=1.0.5
5 | Telethon>=1.32.1
6 | Pyrogram>=2.0.106
7 | aiosqlite>=0.17.0
8 | better-proxy>=0.2.2
9 | aiohttp-proxy>=0.1.2
10 |
11 | pythonmonkey>=0.2.3
12 | opentele>=1.15.1
13 | aiofiles>=23.2.1
14 |
--------------------------------------------------------------------------------
/core/headers.py:
--------------------------------------------------------------------------------
1 | headers: dict = {
2 | 'accept': 'application/json',
3 | 'accept-language': 'ru,en-GB;q=0.9,en-US;q=0.8,en;q=0.7',
4 | 'auth': '1',
5 | 'content-type': 'application/json',
6 | 'origin': 'https://clicker.joincommunity.xyz',
7 | 'referer': 'https://clicker.joincommunity.xyz/'
8 | }
9 |
--------------------------------------------------------------------------------
/database/on_startup.py:
--------------------------------------------------------------------------------
1 | import aiosqlite
2 |
3 |
4 | async def on_startup_database() -> None:
5 | async with aiosqlite.connect(database='database/sessions.db') as db:
6 | await db.execute(sql="""
7 | CREATE TABLE IF NOT EXISTS sessions (
8 | id INTEGER PRIMARY KEY,
9 | session_name TEXT,
10 | session_proxy TEXT
11 | );
12 | """)
13 | await db.commit()
14 |
--------------------------------------------------------------------------------
/utils/eval_js.py:
--------------------------------------------------------------------------------
1 | from pythonmonkey import eval as js_eval
2 |
3 |
4 | def eval_js(function: str) -> int | None:
5 | match function:
6 | case 'document.querySelectorAll(\'body\').length':
7 | return 1
8 |
9 | case 'window.location.host == \'clicker.joincommunity.xyz\' ? 129 : 578':
10 | return 129
11 |
12 | try:
13 | return int(js_eval(function))
14 |
15 | except Exception:
16 | return None
17 |
--------------------------------------------------------------------------------
/data/config.py:
--------------------------------------------------------------------------------
1 | API_ID: int = 6
2 | API_HASH: str = 'eb06d4abfb49dc3eeb1aeb98ae0f581e'
3 | MIN_CLICKS_COUNT: int = 1
4 | AUTO_BUY_ENERGY_BOOST: bool = False
5 | AUTO_BUY_SPEED_BOOST: bool = True
6 | AUTO_BUY_CLICK_BOOST: bool = True
7 | USE_PROXY_FROM_FILE: bool = True
8 | SLEEP_BETWEEN_CLICK: list[int] = [10, 15]
9 | SLEEP_BEFORE_BUY_MERGE: list[int] = [10, 15]
10 | SLEEP_BEFORE_ACTIVATE_FREE_BUFFS: list[int] = [10, 15]
11 | SLEEP_BEFORE_ACTIVATE_TURBO: list[int] = [10, 15]
12 |
--------------------------------------------------------------------------------
/database/actions.py:
--------------------------------------------------------------------------------
1 | import aiosqlite
2 |
3 |
4 | async def add_session(session_name: str,
5 | session_proxy: str = '') -> None:
6 | async with aiosqlite.connect(database='database/sessions.db') as db:
7 | await db.execute(sql='INSERT INTO sessions (session_name, session_proxy) VALUES (?, ?)',
8 | parameters=(session_name, session_proxy))
9 | await db.commit()
10 |
11 |
12 | async def get_session_proxy_by_name(session_name: str) -> str | None:
13 | async with aiosqlite.connect(database='database/sessions.db') as db:
14 | async with db.execute(sql='SELECT session_proxy FROM sessions WHERE session_name = ?',
15 | parameters=(session_name,)) as cursor:
16 | result = await cursor.fetchone()
17 | return result[0] if result else None
18 |
--------------------------------------------------------------------------------
/utils/monkeypatching.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | import aiosqlite
4 | from TGConvertor.manager.sessions.pyro import PyroSession
5 |
6 |
7 | async def new_validate(cls, path: Path) -> bool:
8 | try:
9 | async with aiosqlite.connect(path) as db:
10 | db.row_factory = aiosqlite.Row
11 | sql = "SELECT name FROM sqlite_master WHERE type='table'"
12 | async with db.execute(sql) as cursor:
13 | tables = {row["name"] for row in await cursor.fetchall()}
14 |
15 | if tables != set(cls.TABLES.keys()):
16 | return False
17 |
18 | for table, session_columns in cls.TABLES.items():
19 | sql = f'pragma table_info("{table}")'
20 | async with db.execute(sql) as cur:
21 | columns = {row["name"] for row in await cur.fetchall()}
22 | if "api_id" in columns:
23 | columns.remove("api_id")
24 | if session_columns != columns:
25 | return False
26 |
27 | except aiosqlite.DatabaseError:
28 | return False
29 |
30 | return True
31 |
32 |
33 | PyroSession.validate = classmethod(new_validate)
34 |
--------------------------------------------------------------------------------
/utils/read_session_json_file.py:
--------------------------------------------------------------------------------
1 | from json import loads
2 |
3 | import aiofiles
4 | from aiofiles.ospath import exists
5 | from loguru import logger
6 |
7 |
8 | def get_value(file_json: dict,
9 | *keys) -> str | None:
10 | for key in keys:
11 | if key in file_json:
12 | return file_json[key]
13 | return None
14 |
15 |
16 | async def read_session_json_file(session_name: str) -> dict:
17 | file_path: str = f'sessions/{session_name}.json'
18 | result_dict: dict = {}
19 |
20 | try:
21 | if not await exists(file_path):
22 | return result_dict
23 |
24 | async with aiofiles.open(file=file_path,
25 | mode='r',
26 | encoding='utf-8') as file:
27 | file_json: dict = loads(await file.read())
28 |
29 | result_dict: dict = {
30 | 'api_id': get_value(file_json, 'api_id', 'app_id', 'apiId', 'appId'),
31 | 'api_hash': get_value(file_json, 'api_hash', 'app_hash', 'apiHash', 'appHash'),
32 | 'device_model': get_value(file_json, 'deviceModel', 'device'),
33 | 'system_version': get_value(file_json, 'systemVersion', 'system_version', 'appVersion', 'app_version'),
34 | 'app_version': get_value(file_json, 'appVersion', 'app_version'),
35 | 'lang_code': get_value(file_json, 'lang_pack', 'langCode', 'lang'),
36 | 'system_lang_code': get_value(file_json, 'system_lang_pack', 'systemLangCode', 'systemLangPack')
37 | }
38 |
39 | except Exception as error:
40 | logger.error(f'{session_name} | Ошибка при чтении .json файла: {error}')
41 |
42 | return result_dict
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://t.me/n4z4v0d)
2 | [](https://www.python.org/downloads/release/python-3116/)
3 | [](https://github.com/nikku/works-on-my-machine)
4 |
5 | 
6 |
7 | ### Функционал
8 | + _Многопоточность_
9 | + _Привязка прокси к сессии_
10 | + _Авто-покупка предметов при наличии денег (enery boost, speed boost, click boost)_
11 | + _Рандомное время сна между кликами_
12 | + _Рандомное количество кликов за запрос_
13 | + _Поддержка tdata / pyrogram .session / telethon .session_
14 |
15 | ### data/config.py
16 | _**API_ID / API_HASH** - Данные платформы, с которой запускать сессию Telegram (сток - Android)
17 | **MIN_CLICKS_COUNT** - Минимальное количество кликов за один запрос (считается без множителя, т.е напр. при множителе x9: 1 клик будет равнятся 9 монетам, а не одной)
18 | **AUTO_BUY_ENERGY_BOOST** - Автоматическая покупка Energy Boost при достижении баланса (True / False)
19 | **AUTO_BUY_SPEED_BOOST** - Автоматическая покупка Speed Boost при достижении баланса (True / False)
20 | **AUTO_BUY_CLICK_BOOST** - Автоматическая покупка Click Boost при достижении баланса (True / False)
21 | **USE_PROXY_FROM_FILE** - Использовать-ли Proxy из файла data/proxies.txt для аккаунтов, к которм не привязаны Proxy (True / False)
22 | **SLEEP_BETWEEN_CLICK** - Диапазон задержки между кликами (в секундах)
23 | **SLEEP_BEFORE_BUY_MERGE** - Диапазон задержки перед покупкой бустов (в секундах)
24 | **SLEEP_BEFORE_ACTIVATE_FREE_BUFFS** - Диапазон задержки перед активацией ежедневных бустов (в секундах)
25 | **SLEEP_BEFORE_ACTIVATE_TURBO** - Диапазон задержки перед активацией Turbo (в секундах)_
26 |
27 | # DONATE (_any evm_) - 0xDEADf12DE9A24b47Da0a43E1bA70B8972F5296F2
28 | # DONATE (_sol_) - 2Fw2wh1pN77ELg6sWnn5cZrTDCK5ibfnKymTuCXL8sPX
29 |
--------------------------------------------------------------------------------
/core/create_sessions.py:
--------------------------------------------------------------------------------
1 | import pyrogram
2 | from better_proxy import Proxy
3 | from loguru import logger
4 |
5 | from data import config
6 | from database import actions as db_actions
7 |
8 |
9 | async def create_sessions() -> None:
10 | while True:
11 | session_name: str = input('\nВведите название сессии (для выхода нажмите Enter): ')
12 |
13 | if not session_name:
14 | return
15 |
16 | while True:
17 | proxy_str: str = input('Введите Proxy (type://user:pass@ip:port // type://ip:port, для использования без '
18 | 'Proxy нажмите Enter): ').replace('https://', 'http://')
19 |
20 | if proxy_str:
21 | try:
22 | proxy: Proxy = Proxy.from_str(
23 | proxy=proxy_str
24 | )
25 |
26 | proxy_dict: dict = {
27 | 'scheme': proxy.protocol,
28 | 'hostname': proxy.host,
29 | 'port': proxy.port,
30 | 'username': proxy.login,
31 | 'password': proxy.password
32 | }
33 |
34 | except ValueError:
35 | logger.error(f'Неверно указан Proxy, повторите попытку ввода')
36 |
37 | else:
38 | break
39 |
40 | else:
41 | proxy: None = None
42 | proxy_dict: None = None
43 | break
44 |
45 | session: pyrogram.Client = pyrogram.Client(
46 | api_id=config.API_ID,
47 | api_hash=config.API_HASH,
48 | name=session_name,
49 | workdir='sessions',
50 | proxy=proxy_dict
51 | )
52 |
53 | async with session:
54 | user_data = await session.get_me()
55 |
56 | logger.success(f'Успешно добавлена сессия {user_data.username} | {user_data.first_name} {user_data.last_name}')
57 |
58 | await db_actions.add_session(session_name=session_name,
59 | session_proxy=proxy.as_url if proxy else '')
60 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | from itertools import cycle
2 | from better_proxy import Proxy
3 | from os.path import isdir
4 | import asyncio
5 | from os import listdir
6 | from os import mkdir
7 | from os.path import exists
8 | from sys import stderr
9 |
10 | from loguru import logger
11 |
12 | from core import create_sessions, start_farming
13 | from database import on_startup_database
14 | from utils import monkeypatching
15 |
16 | logger.remove()
17 | logger.add(stderr, format='{time:HH:mm:ss}'
18 | ' | {level: <8}'
19 | ' | {line}'
20 | ' - {message}')
21 |
22 |
23 | async def main() -> None:
24 | await on_startup_database()
25 |
26 | match user_action:
27 | case 1:
28 | await create_sessions()
29 |
30 | logger.success('Сессии успешно добавлены')
31 |
32 | case 2:
33 | tasks: list = [
34 | asyncio.create_task(coro=start_farming(session_name=current_session_name,
35 | proxy=next(proxies_cycled) if proxies_cycled else None))
36 | for current_session_name in session_files
37 | ]
38 |
39 | await asyncio.gather(*tasks)
40 |
41 | case _:
42 | logger.error('Действие выбрано некорректно')
43 |
44 |
45 | if __name__ == '__main__':
46 | if not exists(path='sessions'):
47 | mkdir(path='sessions')
48 |
49 | with open(file='data/proxies.txt',
50 | mode='r',
51 | encoding='utf-8-sig') as file:
52 | proxies: list[str] = [Proxy.from_str(proxy=row.strip()).as_url for row in file]
53 |
54 | if proxies:
55 | proxies_cycled: cycle = cycle(proxies)
56 |
57 | else:
58 | proxies_cycled: None = None
59 |
60 | session_files: list[str] = [current_file[:-8] if current_file.endswith('.session')
61 | else current_file for current_file in listdir(path='sessions')
62 | if current_file.endswith('.session') or isdir(s=f'sessions/{current_file}')]
63 |
64 | logger.info(f'Обнаружено {len(session_files)} сессий / {len(proxies)} прокси')
65 |
66 | user_action: int = int(input('\n1. Создать сессию'
67 | '\n2. Запустить бота с существующих сессий'
68 | '\nВыберите ваше действие: '))
69 | print()
70 |
71 | try:
72 | import uvloop
73 |
74 | uvloop.run(main())
75 |
76 | except ModuleNotFoundError:
77 | asyncio.run(main())
78 |
79 | input('\n\nPress Enter to Exit..')
80 |
--------------------------------------------------------------------------------
/core/start_farming.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | from base64 import b64decode
3 | from math import floor
4 | from pathlib import Path
5 | from random import randint
6 | from time import time
7 | from urllib.parse import unquote
8 |
9 | import aiohttp
10 | from TGConvertor.manager.exceptions import ValidationError
11 | from TGConvertor.manager.manager import SessionManager
12 | from aiohttp_proxy import ProxyConnector
13 | from better_proxy import Proxy
14 | from loguru import logger
15 | from opentele.exception import TFileNotFound, OpenTeleException
16 | from pyuseragents import random as random_useragent
17 | from telethon import TelegramClient
18 | from telethon import functions
19 | from telethon.sessions import StringSession
20 |
21 | from data import config
22 | from database import actions as db_actions
23 | from exceptions import InvalidSession, TurboExpired
24 | from utils import eval_js, read_session_json_file
25 | from .headers import headers
26 |
27 |
28 | class Farming:
29 | def __init__(self,
30 | session_name: str):
31 | self.session_name: str = session_name
32 |
33 | async def get_access_token(self,
34 | client: aiohttp.ClientSession,
35 | tg_web_data: str) -> str:
36 | r: None = None
37 |
38 | while True:
39 | try:
40 | r: aiohttp.ClientResponse = await client.post(url='https://clicker-api.joincommunity.xyz/auth/'
41 | 'webapp-session',
42 | json={
43 | 'webAppData': tg_web_data
44 | },
45 | verify_ssl=False)
46 |
47 | return (await r.json(content_type=None))['data']['accessToken']
48 |
49 | except Exception as error:
50 | if r:
51 | logger.error(f'{self.session_name} | Неизвестная ошибка при получении Access Token: {error}, '
52 | f'ответ: {await r.text()}')
53 |
54 | else:
55 | logger.error(f'{self.session_name} | Неизвестная ошибка при получении Access Token: {error}')
56 |
57 | async def get_tg_web_data(self,
58 | session_proxy: str | None) -> str | None:
59 | while True:
60 | try:
61 | if session_proxy:
62 | try:
63 | proxy: Proxy = Proxy.from_str(
64 | proxy=session_proxy
65 | )
66 |
67 | proxy_dict: dict = {
68 | 'proxy_type': proxy.protocol,
69 | 'addr': proxy.host,
70 | 'port': proxy.port,
71 | 'username': proxy.login,
72 | 'password': proxy.password
73 | }
74 |
75 | except ValueError:
76 | proxy_dict: None = None
77 |
78 | else:
79 | proxy_dict: None = None
80 |
81 | session: any = None
82 |
83 | try:
84 | session = SessionManager.from_tdata_folder(folder=Path(f'sessions/{self.session_name}'))
85 |
86 | except (ValidationError, FileNotFoundError, TFileNotFound, OpenTeleException):
87 | pass
88 |
89 | if not session:
90 | for action in [SessionManager.from_pyrogram_file, SessionManager.from_telethon_file]:
91 | try:
92 | # noinspection PyArgumentList
93 | session = await action(file=Path(f'sessions/{self.session_name}.session'))
94 |
95 | except (ValidationError, FileNotFoundError, TFileNotFound, OpenTeleException):
96 | pass
97 |
98 | else:
99 | break
100 |
101 | if not session:
102 | raise InvalidSession(self.session_name)
103 |
104 | telethon_string: str = session.to_telethon_string()
105 | platform_data: dict = await read_session_json_file(session_name=self.session_name)
106 |
107 | client = TelegramClient(session=StringSession(string=telethon_string),
108 | api_id=platform_data.get('api_id', config.API_ID),
109 | api_hash=platform_data.get('api_hash', config.API_HASH),
110 | device_model=platform_data.get('device_model', None),
111 | system_version=platform_data.get('system_version', None),
112 | app_version=platform_data.get('app_version', None),
113 | lang_code=platform_data.get('lang_code', 'en'),
114 | system_lang_code=platform_data.get('system_lang_code', 'en'),
115 | proxy=proxy_dict)
116 |
117 | try:
118 | await client.connect()
119 |
120 | if not await client.is_user_authorized():
121 | raise InvalidSession(self.session_name)
122 |
123 | except InvalidSession as error:
124 | raise error
125 |
126 | except Exception as error:
127 | raise error
128 |
129 | finally:
130 | await client.disconnect()
131 |
132 | async with TelegramClient(session=StringSession(string=telethon_string),
133 | api_id=platform_data.get('api_id', config.API_ID),
134 | api_hash=platform_data.get('api_hash', config.API_HASH),
135 | device_model=platform_data.get('device_model', None),
136 | system_version=platform_data.get('system_version', None),
137 | app_version=platform_data.get('app_version', None),
138 | lang_code=platform_data.get('lang_code', 'en'),
139 | system_lang_code=platform_data.get('system_lang_code', 'en'),
140 | proxy=proxy_dict) as client:
141 | await client.send_message(entity='notcoin_bot',
142 | message='/start r_577441_3319074')
143 | # noinspection PyTypeChecker
144 | result = await client(functions.messages.RequestWebViewRequest(
145 | peer='notcoin_bot',
146 | bot='notcoin_bot',
147 | platform='android',
148 | from_bot_menu=False,
149 | url='https://clicker.joincommunity.xyz/clicker',
150 | ))
151 | auth_url: str = result.url
152 |
153 | tg_web_data: str = unquote(string=unquote(
154 | string=auth_url.split(sep='tgWebAppData=',
155 | maxsplit=1)[1].split(sep='&tgWebAppVersion',
156 | maxsplit=1)[0]
157 | ))
158 |
159 | return tg_web_data
160 |
161 | except InvalidSession as error:
162 | raise error
163 |
164 | except Exception as error:
165 | logger.error(f'{self.session_name} | Неизвестная ошибка при авторизации: {error}')
166 |
167 | async def get_profile_data(self,
168 | client: aiohttp.ClientSession) -> dict:
169 | while True:
170 | try:
171 | r: aiohttp.ClientResponse = await client.get(
172 | url='https://clicker-api.joincommunity.xyz/clicker/profile',
173 | verify_ssl=False)
174 |
175 | if not (await r.json(content_type=None)).get('ok'):
176 | logger.error(f'{self.session_name} | Неизвестный ответ при получении данных профиля, '
177 | f'ответ: {await r.text()}')
178 | continue
179 |
180 | return await r.json(content_type=None)
181 |
182 | except Exception as error:
183 | logger.error(f'{self.session_name} | Неизвестная ошибка при получении данных профиля: {error}')
184 |
185 | async def send_clicks(self,
186 | client: aiohttp.ClientSession,
187 | clicks_count: int,
188 | tg_web_data: str,
189 | balance: int,
190 | total_coins: str | int,
191 | click_hash: str | None = None,
192 | turbo: bool | None = None) -> tuple[int | None, str | None, bool | None]:
193 | while True:
194 | try:
195 | json_data: dict = {
196 | 'count': clicks_count,
197 | 'webAppData': tg_web_data
198 | }
199 |
200 | if click_hash:
201 | json_data['hash']: str = click_hash
202 |
203 | if turbo:
204 | json_data['turbo']: bool = True
205 |
206 | r: aiohttp.ClientResponse = await client.post(
207 | url='https://clicker-api.joincommunity.xyz/clicker/core/click',
208 | json=json_data,
209 | verify_ssl=False)
210 |
211 | if (await r.json(content_type=None)).get('data') \
212 | and isinstance((await r.json(content_type=None))['data'], dict) \
213 | and (await r.json(content_type=None))['data'].get('message', '') == 'Turbo mode is expired':
214 | raise TurboExpired()
215 |
216 | if (await r.json(content_type=None)).get('data') \
217 | and isinstance((await r.json(content_type=None))['data'], dict) \
218 | and (await r.json(content_type=None))['data'].get('message', '') == 'Try later':
219 | await asyncio.sleep(delay=1)
220 | continue
221 |
222 | if (await r.json(content_type=None)).get('ok'):
223 | logger.success(f'{self.session_name} | Успешно сделал Click | Balance: '
224 | f'{balance + clicks_count} (+{clicks_count}) | Total Coins: {total_coins}')
225 |
226 | next_hash: str | None = eval_js(
227 | function=b64decode(s=(await r.json())['data'][0]['hash'][0]).decode())
228 |
229 | return balance + clicks_count, next_hash, (await r.json())['data'][0]['turboTimes'] > 0
230 |
231 | logger.error(f'{self.session_name} | Не удалось сделать Click, ответ: {await r.text()}')
232 | return None, None, None
233 |
234 | except Exception as error:
235 | logger.error(f'{self.session_name} | Неизвестная ошибка при попытке сделать Click: {error}')
236 |
237 | async def get_merged_list(self,
238 | client: aiohttp.ClientSession) -> dict | None:
239 | r: None = None
240 |
241 | try:
242 | r: aiohttp.ClientResponse = await client.get(
243 | url='https://clicker-api.joincommunity.xyz/clicker/store/merged')
244 |
245 | if (await r.json(content_type=None)).get('ok'):
246 | return await r.json(content_type=None)
247 |
248 | logger.error(f'{self.session_name} | Не удалось получить список товаров, ответ: {await r.text()}')
249 |
250 | return
251 |
252 | except Exception as error:
253 | if r:
254 | logger.error(f'{self.session_name} | Неизвестная ошибка при получении списка товаров: {error}, '
255 | f'ответ: {await r.text()}')
256 |
257 | else:
258 | logger.error(f'{self.session_name} | Неизвестная ошибка при получении списка товаров: {error}')
259 |
260 | async def buy_item(self,
261 | client: aiohttp.ClientSession,
262 | item_id: int | str) -> bool:
263 | r: None = None
264 |
265 | try:
266 | r: aiohttp.ClientResponse = await client.post(url=f'https://clicker-api.joincommunity.xyz/clicker/store/'
267 | f'buy/{item_id}',
268 | headers={
269 | 'accept-language': 'ru-RU,ru;q=0.9',
270 | },
271 | json=False)
272 |
273 | if (await r.json(content_type=None)).get('ok'):
274 | return True
275 |
276 | logger.error(f'{self.session_name} | Неизвестный ответ при покупке в магазине: {await r.text()}')
277 |
278 | return False
279 |
280 | except Exception as error:
281 | if r:
282 | logger.error(f'{self.session_name} | Неизвестная ошибка при покупке в магазине: {error}, '
283 | f'ответ: {await r.text()}')
284 |
285 | else:
286 | logger.error(f'{self.session_name} | Неизвестная ошибка при покупке в магазине: {error}')
287 |
288 | return False
289 |
290 | async def activate_turbo(self,
291 | client: aiohttp.ClientSession) -> int | None:
292 | r: None = None
293 |
294 | try:
295 | r: aiohttp.ClientResponse = await client.post(url=f'https://clicker-api.joincommunity.xyz/clicker/core/'
296 | 'active-turbo',
297 | headers={
298 | 'accept-language': 'ru-RU,ru;q=0.9',
299 | },
300 | json=False)
301 |
302 | return (await r.json(content_type=None))['data'][0].get('multiple', 1)
303 |
304 | except Exception as error:
305 | if r:
306 | logger.error(f'{self.session_name} | Неизвестная ошибка при активации Turbo: {error}, '
307 | f'ответ: {await r.text()}')
308 |
309 | else:
310 | logger.error(f'{self.session_name} | Неизвестная ошибка при активации Turbo: {error}')
311 |
312 | return
313 |
314 | async def activate_task(self,
315 | client: aiohttp.ClientSession,
316 | task_id: int | str) -> bool | None:
317 | r: None = None
318 |
319 | try:
320 | r: aiohttp.ClientResponse = await client.post(url=f'https://clicker-api.joincommunity.xyz/clicker/task/'
321 | f'{task_id}',
322 | headers={
323 | 'accept-language': 'ru-RU,ru;q=0.9',
324 | },
325 | json=False)
326 |
327 | if (await r.json(content_type=None)).get('ok'):
328 | return True
329 |
330 | logger.error(f'{self.session_name} | Неизвестный ответ при активации Task {task_id}: {await r.text()}')
331 |
332 | return False
333 |
334 | except Exception as error:
335 | if r:
336 | logger.error(f'{self.session_name} | Неизвестная ошибка при активации Task {task_id}: {error}, '
337 | f'ответ: {await r.text()}')
338 |
339 | else:
340 | logger.error(f'{self.session_name} | Неизвестная ошибка при активации Task {task_id}: {error}')
341 |
342 | return False
343 |
344 | async def get_free_buffs_data(self,
345 | client: aiohttp.ClientSession) -> tuple[bool, bool]:
346 | r: None = None
347 | max_turbo_times: int = 3
348 | max_full_energy_times: int = 3
349 |
350 | turbo_times_count: int = 0
351 | full_energy_times_count: int = 0
352 |
353 | try:
354 | r: aiohttp.ClientResponse = await client.get(url=f'https://clicker-api.joincommunity.xyz/clicker/task/'
355 | 'combine-completed')
356 |
357 | for current_buff in (await r.json(content_type=None))['data']:
358 | match current_buff['taskId']:
359 | case 3:
360 | max_turbo_times: int = current_buff['task']['max']
361 |
362 | if current_buff['task']['status'] == 'active':
363 | turbo_times_count += 1
364 |
365 | case 2:
366 | max_full_energy_times: int = current_buff['task']['max']
367 |
368 | if current_buff['task']['status'] == 'active':
369 | full_energy_times_count += 1
370 |
371 | return max_turbo_times > turbo_times_count, max_full_energy_times > full_energy_times_count
372 |
373 | except Exception as error:
374 | if r:
375 | logger.error(f'{self.session_name} | Неизвестная ошибка при получении статуса бесплатных баффов: '
376 | f'{error}, ответ: {await r.text()}')
377 |
378 | else:
379 | logger.error(f'{self.session_name} | Неизвестная ошибка при получении статуса бесплатных баффов: '
380 | f'{error}')
381 |
382 | return False, False
383 |
384 | async def start_farming(self,
385 | proxy: str | None = None):
386 | session_proxy: str = await db_actions.get_session_proxy_by_name(session_name=self.session_name)
387 |
388 | if not session_proxy and config.USE_PROXY_FROM_FILE:
389 | session_proxy: str = proxy
390 |
391 | access_token_created_time: float = 0
392 | click_hash: None | str = None
393 | active_turbo: bool = False
394 | turbo_multiplier: int = 1
395 |
396 | while True:
397 | try:
398 | async with aiohttp.ClientSession(
399 | connector=ProxyConnector.from_url(url=session_proxy) if session_proxy else None,
400 | headers={
401 | **headers,
402 | 'user-agent': random_useragent()
403 | }) as client:
404 | while True:
405 | try:
406 | if time() - access_token_created_time >= 1800:
407 | tg_web_data: str = await self.get_tg_web_data(session_proxy=session_proxy)
408 |
409 | access_token: str = await self.get_access_token(client=client,
410 | tg_web_data=tg_web_data)
411 | client.headers['Authorization']: str = f'Bearer {access_token}'
412 | access_token_created_time: float = time()
413 |
414 | profile_data: dict = await self.get_profile_data(client=client)
415 |
416 | if not active_turbo:
417 | if config.MIN_CLICKS_COUNT > floor(profile_data['data'][0]['availableCoins'] \
418 | / profile_data['data'][0]['multipleClicks']):
419 | logger.info(f'{self.session_name} | Недостаточно монет для клика')
420 | continue
421 |
422 | if floor(profile_data['data'][0]['availableCoins'] \
423 | / profile_data['data'][0]['multipleClicks']) < 160:
424 | max_clicks_count: int = floor(profile_data['data'][0]['availableCoins'] \
425 | / profile_data['data'][0]['multipleClicks'])
426 |
427 | else:
428 | max_clicks_count: int = 160
429 |
430 | clicks_count: int = randint(a=config.MIN_CLICKS_COUNT,
431 | b=max_clicks_count) \
432 | * profile_data['data'][0]['multipleClicks'] * turbo_multiplier
433 |
434 | try:
435 | new_balance, click_hash, have_turbo = await self.send_clicks(client=client,
436 | clicks_count=clicks_count,
437 | tg_web_data=tg_web_data,
438 | balance=
439 | profile_data['data'][0][
440 | 'balanceCoins'],
441 | total_coins=
442 | profile_data['data'][0][
443 | 'totalCoins'],
444 | click_hash=click_hash,
445 | turbo=active_turbo)
446 |
447 | except TurboExpired:
448 | active_turbo: bool = False
449 | turbo_multiplier: int = 1
450 | continue
451 |
452 | if have_turbo:
453 | random_sleep_time: int = randint(a=config.SLEEP_BEFORE_ACTIVATE_TURBO[0],
454 | b=config.SLEEP_BEFORE_ACTIVATE_TURBO[1])
455 |
456 | logger.info(f'{self.session_name} | Сплю {random_sleep_time} перед активацией '
457 | f'Turbo')
458 |
459 | await asyncio.sleep(delay=random_sleep_time)
460 |
461 | turbo_multiplier: int | None = await self.activate_turbo(client=client)
462 |
463 | if turbo_multiplier:
464 | logger.success(f'{self.session_name} | Успешно активировал Turbo: '
465 | f'x{turbo_multiplier}')
466 | active_turbo: bool = True
467 | continue
468 |
469 | else:
470 | turbo_multiplier: int = 1
471 |
472 | if new_balance:
473 | merged_data: dict | None = await self.get_merged_list(client=client)
474 |
475 | if merged_data:
476 | for current_merge in merged_data['data']:
477 | match current_merge['id']:
478 | case 1:
479 | if not config.AUTO_BUY_ENERGY_BOOST:
480 | continue
481 |
482 | energy_price: int | None = current_merge['price']
483 |
484 | if new_balance >= energy_price \
485 | and current_merge['max'] > current_merge['count']:
486 | sleep_before_buy_merge: int = randint(
487 | a=config.SLEEP_BEFORE_BUY_MERGE[0],
488 | b=config.SLEEP_BEFORE_BUY_MERGE[1]
489 | )
490 | logger.info(f'{self.session_name} | Сплю {sleep_before_buy_merge} '
491 | f'сек. перед покупкой Energy Boost')
492 |
493 | await asyncio.sleep(delay=sleep_before_buy_merge)
494 |
495 | if await self.buy_item(client=client,
496 | item_id=1):
497 | logger.success(f'{self.session_name} | Успешно купил Energy '
498 | 'Boost')
499 | continue
500 |
501 | case 2:
502 | if not config.AUTO_BUY_SPEED_BOOST:
503 | continue
504 |
505 | speed_price: int | None = current_merge['price']
506 |
507 | if new_balance >= speed_price \
508 | and current_merge['max'] > current_merge['count']:
509 | sleep_before_buy_merge: int = randint(
510 | a=config.SLEEP_BEFORE_BUY_MERGE[0],
511 | b=config.SLEEP_BEFORE_BUY_MERGE[1]
512 | )
513 | logger.info(f'{self.session_name} | Сплю {sleep_before_buy_merge} '
514 | 'сек. перед покупкой Speed Boost')
515 |
516 | await asyncio.sleep(delay=sleep_before_buy_merge)
517 |
518 | if await self.buy_item(client=client,
519 | item_id=2):
520 | logger.success(
521 | f'{self.session_name} | Успешно купил Speed Boost')
522 | continue
523 |
524 | case 3:
525 | if not config.AUTO_BUY_CLICK_BOOST:
526 | continue
527 |
528 | click_price: int | None = current_merge['price']
529 |
530 | if new_balance >= click_price \
531 | and current_merge['max'] > current_merge['count']:
532 | sleep_before_buy_merge: int = randint(
533 | a=config.SLEEP_BEFORE_BUY_MERGE[0],
534 | b=config.SLEEP_BEFORE_BUY_MERGE[1])
535 | logger.info(
536 | f'{self.session_name} | Сплю {sleep_before_buy_merge} сек. '
537 | f'перед покупкой Speed Boost')
538 |
539 | await asyncio.sleep(delay=sleep_before_buy_merge)
540 |
541 | if await self.buy_item(client=client,
542 | item_id=3):
543 | logger.success(
544 | f'{self.session_name} | Успешно купил Click Boost')
545 | continue
546 |
547 | case 4:
548 | pass
549 |
550 | free_daily_turbo, free_daily_full_energy = await self.get_free_buffs_data(client=client)
551 |
552 | if free_daily_turbo:
553 | random_sleep_time: int = randint(a=config.SLEEP_BEFORE_ACTIVATE_FREE_BUFFS[0],
554 | b=config.SLEEP_BEFORE_ACTIVATE_FREE_BUFFS[1])
555 |
556 | logger.info(f'{self.session_name} | Сплю {random_sleep_time} перед запросом '
557 | f'ежедневного Turbo')
558 |
559 | await asyncio.sleep(delay=random_sleep_time)
560 |
561 | if await self.activate_task(client=client,
562 | task_id=3):
563 | logger.success(f'{self.session_name} | Успешно запросил ежедневное Turbo')
564 |
565 | random_sleep_time: int = randint(a=config.SLEEP_BEFORE_ACTIVATE_TURBO[0],
566 | b=config.SLEEP_BEFORE_ACTIVATE_TURBO[1])
567 |
568 | logger.info(f'{self.session_name} | Сплю {random_sleep_time} перед активацией '
569 | f'Turbo')
570 |
571 | await asyncio.sleep(delay=random_sleep_time)
572 |
573 | turbo_multiplier: int | None = await self.activate_turbo(client=client)
574 |
575 | if turbo_multiplier:
576 | logger.success(f'{self.session_name} | Успешно активировал Turbo: '
577 | f'x{turbo_multiplier}')
578 | active_turbo: bool = True
579 | continue
580 |
581 | else:
582 | turbo_multiplier: int = 1
583 |
584 | elif free_daily_full_energy:
585 | random_sleep_time: int = randint(a=config.SLEEP_BEFORE_ACTIVATE_FREE_BUFFS[0],
586 | b=config.SLEEP_BEFORE_ACTIVATE_FREE_BUFFS[1])
587 |
588 | logger.info(f'{self.session_name} | Сплю {random_sleep_time} перед активацией '
589 | f'ежедневного Full Energy')
590 |
591 | await asyncio.sleep(delay=random_sleep_time)
592 |
593 | if await self.activate_task(client=client,
594 | task_id=2):
595 | logger.success(f'{self.session_name} | Успешно запросил ежедневный Full Energy')
596 |
597 | except InvalidSession as error:
598 | raise error
599 |
600 | except Exception as error:
601 | logger.error(f'{self.session_name} | Неизвестная ошибка: {error}')
602 |
603 | random_sleep_time: int = randint(a=config.SLEEP_BETWEEN_CLICK[0],
604 | b=config.SLEEP_BETWEEN_CLICK[1])
605 |
606 | logger.info(f'{self.session_name} | Сплю {random_sleep_time} сек.')
607 | await asyncio.sleep(delay=random_sleep_time)
608 |
609 | else:
610 | random_sleep_time: int = randint(a=config.SLEEP_BETWEEN_CLICK[0],
611 | b=config.SLEEP_BETWEEN_CLICK[1])
612 |
613 | logger.info(f'{self.session_name} | Сплю {random_sleep_time} сек.')
614 | await asyncio.sleep(delay=random_sleep_time)
615 |
616 | except InvalidSession as error:
617 | raise error
618 |
619 | except Exception as error:
620 | logger.error(f'{self.session_name} | Неизвестная ошибка: {error}')
621 |
622 |
623 | async def start_farming(session_name: str,
624 | proxy: str | None = None) -> None:
625 | try:
626 | await Farming(session_name=session_name).start_farming(proxy=proxy)
627 |
628 | except InvalidSession:
629 | logger.error(f'{session_name} | Invalid Session')
630 |
--------------------------------------------------------------------------------