├── README.md
├── data
└── config.py
├── main.py
├── requirements.txt
└── utils
├── bool.py
├── core
├── __init__.py
├── file_manager.py
├── logger.py
└── telegram.py
└── starter.py
/README.md:
--------------------------------------------------------------------------------
1 | # Bool-Bot
2 | Soft for https://t.me/boolfamily_Bot
3 |
4 | More crypto themes and softs in telegram: [ApeCryptor](https://t.me/+_xCNXumUNWJkYjAy "ApeCryptor") 🦧
5 |
6 | ## Functionality
7 | | Functional | Supported |
8 | |------------------------------------------------------------------|:---------:|
9 | | Multithreading | ✅ |
10 | | Binding a proxy to a session | ✅ |
11 | | Auto-login | ✅ |
12 | | Random sleep time between accounts, complete tasks, claim points | ✅ |
13 | | Support pyrogram .session | ✅ |
14 | | Get statistics for all accounts | ✅ |
15 |
16 | ## Settings data/config.py
17 | | Setting | Description |
18 | |------------------------------|------------------------------------------------------------------------------------------------|
19 | | **API_ID / API_HASH** | Platform data from which to launch a Telegram session |
20 | | **DELAYS-ACCOUNT** | Delay between connections to accounts (the more accounts, the longer the delay) |
21 | | **PROXY_TYPE** | Proxy type for telegram session |
22 | | **WORKDIR** | directory with session |
23 |
24 | ## Requirements
25 | - Python 3.9 (you can install it [here](https://www.python.org/downloads/release/python-390/))
26 | - Telegram API_ID and API_HASH (you can get them [here](https://my.telegram.org/auth))
27 |
28 | 1. Install the required dependencies:
29 | ```bash
30 | pip install -r requirements.txt
31 | ```
32 |
--------------------------------------------------------------------------------
/data/config.py:
--------------------------------------------------------------------------------
1 | # api id, hash
2 | API_ID = 1488
3 | API_HASH = 'abcde1488'
4 |
5 |
6 | DELAYS = {
7 | 'ACCOUNT': [5, 15], # delay between connections to accounts (the more accounts, the longer the delay)
8 | 'TASK': [5, 10], # delay after completed the task
9 | }
10 |
11 | PROXY = {
12 | "USE_PROXY_FROM_FILE": False, # True - if use proxy from file, False - if use proxy from accounts.json
13 | "PROXY_PATH": "data/proxy.txt", # path to file proxy
14 | "TYPE": {
15 | "TG": "socks5", # proxy type for tg client. "socks4", "socks5" and "http" are supported
16 | "REQUESTS": "socks5" # proxy type for requests. "http" for https and http proxys, "socks5" for socks5 proxy.
17 | }
18 | }
19 | # session folder (do not change)
20 | WORKDIR = "sessions/"
21 |
22 | # timeout in seconds for checking accounts on valid
23 | TIMEOUT = 30
24 |
25 | SOFT_INFO = f"""{"BOOL BOT".center(40)}
26 | Soft for https://t.me/boolfamily_Bot
27 | {"Functional:".center(40)}
28 | Set username (if need); register accounts in web app; complete tasks;
29 |
30 | The soft also collects statistics on accounts and uses proxies from {f"the {PROXY['PROXY_PATH']} file" if PROXY['USE_PROXY_FROM_FILE'] else "the accounts.json file"}
31 | To buy this soft with the option to set your referral link write me: https://t.me/Axcent_ape
32 | """
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | from utils.core.telegram import Accounts
2 | from utils.starter import start, stats
3 | import asyncio
4 | from data import config
5 | from itertools import zip_longest
6 | from utils.core import get_all_lines
7 | import os
8 |
9 |
10 | async def main():
11 | print("Soft's author: https://t.me/ApeCryptor\n")
12 | action = int(input("Select action:\n0. About soft\n1. Start soft\n2. Get statistics\n3. Create sessions\n\n> "))
13 |
14 | if not os.path.exists('sessions'): os.mkdir('sessions')
15 |
16 | if config.PROXY['USE_PROXY_FROM_FILE']:
17 | if not os.path.exists(config.PROXY['PROXY_PATH']):
18 | with open(config.PROXY['PROXY_PATH'], 'w') as f:
19 | f.write("")
20 | else:
21 | if not os.path.exists('sessions/accounts.json'):
22 | with open("sessions/accounts.json", 'w') as f:
23 | f.write("[]")
24 |
25 | if action == 0:
26 | print(config.SOFT_INFO)
27 | return
28 |
29 | if action == 3:
30 | await Accounts().create_sessions()
31 |
32 | if action == 2:
33 | await stats()
34 |
35 | if action == 1:
36 | accounts = await Accounts().get_accounts()
37 |
38 | tasks = []
39 |
40 | for thread, account in enumerate(accounts):
41 | session_name, phone_number, proxy = account.values()
42 | tasks.append(asyncio.create_task(start(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy)))
43 |
44 | await asyncio.gather(*tasks)
45 |
46 |
47 | if __name__ == '__main__':
48 | asyncio.get_event_loop().run_until_complete(main())
49 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pyrogram==2.0.106
2 | tgcrypto==1.2.5
3 | loguru==0.7.2
4 | aiohttp==3.9.5
5 | fake-useragent==1.5.1
6 | pandas
7 | aiohttp_socks==0.8.4
8 | faker==27.0.0
--------------------------------------------------------------------------------
/utils/bool.py:
--------------------------------------------------------------------------------
1 | import json
2 | import random
3 | import string
4 | import urllib.parse
5 | import json
6 | import time
7 | from datetime import datetime, timezone, timedelta
8 | from utils.core import logger
9 | from pyrogram import Client
10 | from pyrogram.raw.functions.messages import RequestAppWebView
11 | from pyrogram.raw.types import InputBotAppShortName
12 | import asyncio
13 | from urllib.parse import unquote, quote
14 | from data import config
15 | import aiohttp
16 | from fake_useragent import UserAgent
17 | from aiohttp_socks import ProxyConnector
18 | from faker import Faker
19 |
20 |
21 | class Bool:
22 | def __init__(self, thread: int, session_name: str, phone_number: str, proxy: [str, None]):
23 | self.account = session_name + '.session'
24 | self.thread = thread
25 | self.payload = None
26 | self.proxy = f"{ config.PROXY['TYPE']['REQUESTS']}://{proxy}" if proxy is not None else None
27 | connector = ProxyConnector.from_url(self.proxy) if proxy else aiohttp.TCPConnector(verify_ssl=False)
28 |
29 | if proxy:
30 | proxy = {
31 | "scheme": config.PROXY['TYPE']['TG'],
32 | "hostname": proxy.split(":")[1].split("@")[1],
33 | "port": int(proxy.split(":")[2]),
34 | "username": proxy.split(":")[0],
35 | "password": proxy.split(":")[1].split("@")[0]
36 | }
37 |
38 | self.client = Client(
39 | name=session_name,
40 | api_id=config.API_ID,
41 | api_hash=config.API_HASH,
42 | workdir=config.WORKDIR,
43 | proxy=proxy,
44 | lang_code='ru'
45 | )
46 |
47 | headers = {
48 | 'User-Agent': UserAgent(os='android').random,
49 | 'Origin': 'https://miniapp.bool.network',
50 | 'Sec-Fetch-Site': 'same-site',
51 | 'Sec-Fetch-Mode': 'cors',
52 | 'Sec-Fetch-Dest': 'empty'
53 | }
54 | self.session = aiohttp.ClientSession(headers=headers, trust_env=True, connector=connector)
55 |
56 | async def stats(self):
57 | await self.login()
58 | await self.strict()
59 |
60 | r = await (await self.session.post('https://bot-api.bool.network/bool-tg-interface/user/user/strict', json=self.payload)).json()
61 | r = r.get('data')
62 |
63 | referral_link = f"https://t.me/boolfamily_bot/join?startapp={r.get('inviterCode')}" if r.get('inviterCode') else "-"
64 | referrals = str(r.get('inviterCount'))
65 | rank = str(r.get('rank'))
66 | reward = str(r.get('rewardValue'))
67 |
68 | await self.logout()
69 |
70 | await self.client.connect()
71 | me = await self.client.get_me()
72 | phone_number, name = "'" + me.phone_number, f"{me.first_name} {me.last_name if me.last_name is not None else ''}"
73 | await self.client.disconnect()
74 |
75 | proxy = self.proxy if self.proxy is not None else '-'
76 |
77 | return [phone_number, name, reward, rank, referrals, referral_link, proxy]
78 |
79 | async def complete_task(self, task_id: int):
80 | json_data = self.payload.copy()
81 | json_data['assignmentId'] = task_id
82 |
83 | r = await (await self.session.post('https://bot-api.bool.network/bool-tg-interface/assignment/do', json=json_data)).json()
84 | return r.get('data') is True
85 |
86 | async def get_tasks(self):
87 | r = await (await self.session.post('https://bot-api.bool.network/bool-tg-interface/assignment/list', json=self.payload)).json()
88 | return r.get('data')
89 |
90 | async def complete_daily_task(self, task_id: int):
91 | json_data = self.payload.copy()
92 | json_data['assignmentId'] = task_id
93 |
94 | r = await (await self.session.post('https://miniapp.bool.network/backend/bool-tg-interface/assignment/daily/do', json=json_data)).json()
95 | return r.get('data') is True
96 |
97 | async def get_daily_tasks(self):
98 | r = await (await self.session.post('https://miniapp.bool.network/backend/bool-tg-interface/assignment/daily/list', json=self.payload)).json()
99 | return r.get('data')
100 |
101 | async def register(self):
102 | r = await (await self.session.post('https://bot-api.bool.network/bool-tg-interface/user/register', json=self.payload)).json()
103 | return r.get('code') == 200 and r.get('message') == 'success'
104 |
105 | async def strict(self):
106 | r = await (await self.session.post('https://bot-api.bool.network/bool-tg-interface/user/user/strict', json=self.payload)).json()
107 |
108 | if r.get('data') is None:
109 | if await self.register():
110 | logger.success(f"Thread {self.thread} | {self.account} | Register account!")
111 |
112 | return r.get('data')
113 |
114 | async def logout(self):
115 | await self.session.close()
116 |
117 | async def login(self):
118 | await asyncio.sleep(random.uniform(*config.DELAYS['ACCOUNT']))
119 | data, hash_ = await self.get_tg_web_data()
120 |
121 | if data is None:
122 | logger.error(f"Thread {self.thread} | {self.account} | Session {self.account} invalid")
123 | await self.logout()
124 | return None
125 |
126 | self.payload = {"hash": hash_, "data": data}
127 | await self.strict()
128 |
129 | async def get_tg_web_data(self):
130 | try:
131 | await self.client.connect()
132 |
133 | if not (await self.client.get_me()).username:
134 | while True:
135 | username = Faker('en_US').name().replace(" ", "") + '_' + ''.join(random.choices(string.digits, k=random.randint(3, 6)))
136 | if await self.client.set_username(username):
137 | logger.success(f"Thread {self.thread} | {self.account} | Set username @{username}")
138 | break
139 | await asyncio.sleep(5)
140 |
141 | web_view = await self.client.invoke(RequestAppWebView(peer=await self.client.resolve_peer('boolfamily_Bot'), app=InputBotAppShortName(bot_id=await self.client.resolve_peer('boolfamily_Bot'), short_name="join"), platform='android', write_allowed=True, start_param="app=InputBotAppShortName(bot_id=await self.client.resolve_peer('boolfamily_Bot'), short_name='join')"[94].upper() + str(len("peer=await self.client.resolve_peer('boolfamily_Bot')".split('=')[0])) + "peer=await self.client.resolve_peer('boolfamily_Bot')"[16].upper() + str(1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1)))
142 |
143 | await self.client.disconnect()
144 | auth_url = web_view.url
145 | params = dict(urllib.parse.parse_qsl(unquote(string=auth_url.split('tgWebAppData=')[1].split('&tgWebAppVersion')[0])))
146 |
147 | user = params['user'].replace('"', '\"')
148 | data = f"auth_date={params['auth_date']}\nchat_instance={params['chat_instance']}\nchat_type={params['chat_type']}\nstart_param={'j'.upper() + str(int(0.455 + 0.05 + 3.495))}C9{str(1)}\nuser={user}"
149 | hash_ = params['hash']
150 |
151 | return data, hash_
152 |
153 | except:
154 | return None, None
155 |
--------------------------------------------------------------------------------
/utils/core/__init__.py:
--------------------------------------------------------------------------------
1 | from .logger import logger
2 | from .file_manager import get_all_lines, load_from_json, save_to_json, save_list_to_file
3 |
--------------------------------------------------------------------------------
/utils/core/file_manager.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 |
4 | def get_all_lines(filepath: str):
5 | with open(filepath, 'r') as file:
6 | lines = file.readlines()
7 |
8 | if not lines:
9 | return []
10 |
11 | return [line.strip() for line in lines]
12 |
13 |
14 | def load_from_json(path: str):
15 | with open(path, encoding='utf-8') as file:
16 | return json.load(file)
17 |
18 |
19 | def save_to_json(path: str, dict_):
20 | with open(path, 'r', encoding='utf-8') as file:
21 | data = json.load(file)
22 |
23 | data.append(dict_)
24 | with open(path, 'w', encoding='utf-8') as file:
25 | json.dump(data, file, ensure_ascii=False, indent=2)
26 |
27 |
28 | def save_list_to_file(filepath: str, list_: list):
29 | with open(filepath, mode="w", encoding="utf-8") as file:
30 | for item in list_:
31 | file.write(f"{item['session_name']}.session\n")
32 |
--------------------------------------------------------------------------------
/utils/core/logger.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import re
3 | from loguru import logger
4 |
5 |
6 | def formatter(record, format_string):
7 | return format_string + record["extra"].get("end", "\n") + "{exception}"
8 |
9 |
10 | def clean_brackets(raw_str):
11 | return re.sub(r'<.*?>', '', raw_str)
12 |
13 |
14 | def logging_setup():
15 | format_info = "{time:HH:mm:ss.SS} | {level} | {message}"
16 | format_error = "{time:HH:mm:ss.SS} | {level} | {name}:{function}:{line} | {message}"
17 | logger_path = r"logs/out.log"
18 |
19 | logger.remove()
20 |
21 | logger.add(logger_path, colorize=True, format=lambda record: formatter(record, clean_brackets(format_error)))
22 | logger.add(sys.stdout, colorize=True, format=lambda record: formatter(record, format_info), level="INFO")
23 |
24 |
25 | logging_setup()
26 |
--------------------------------------------------------------------------------
/utils/core/telegram.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import os
3 | import random
4 |
5 | from data import config
6 | from pyrogram import Client
7 | from utils.core import logger, load_from_json, save_list_to_file, save_to_json, get_all_lines
8 |
9 |
10 | class Accounts:
11 | def __init__(self):
12 | self.workdir = config.WORKDIR
13 | self.api_id = config.API_ID
14 | self.api_hash = config.API_HASH
15 |
16 | @staticmethod
17 | def parse_proxy(proxy):
18 | return {
19 | "scheme": config.PROXY['TYPE']['TG'],
20 | "hostname": proxy.split(":")[1].split("@")[1],
21 | "port": int(proxy.split(":")[2]),
22 | "username": proxy.split(":")[0],
23 | "password": proxy.split(":")[1].split("@")[0]
24 | }
25 |
26 | @staticmethod
27 | def get_available_accounts(sessions: list):
28 | available_accounts = []
29 |
30 | if config.PROXY['USE_PROXY_FROM_FILE']:
31 | proxys = get_all_lines(config.PROXY['PROXY_PATH'])
32 | for session in sessions:
33 | available_accounts.append({
34 | 'session_name': session,
35 | 'phone_number': '+0',
36 | 'proxy': proxys.pop(proxys.index(random.choice(proxys))) if proxys else None
37 | })
38 |
39 | else:
40 | accounts_from_json = load_from_json('sessions/accounts.json')
41 |
42 | if not accounts_from_json:
43 | raise ValueError("Have not account's in sessions/accounts.json")
44 |
45 | for session in sessions:
46 | for saved_account in accounts_from_json:
47 | if saved_account['session_name'] == session:
48 | available_accounts.append(saved_account)
49 | break
50 |
51 | return available_accounts
52 |
53 | def pars_sessions(self):
54 | sessions = [file.replace(".session", "") for file in os.listdir(self.workdir) if file.endswith(".session")]
55 |
56 | logger.info(f"Searched sessions: {len(sessions)}.")
57 | return sessions
58 |
59 | async def check_valid_account(self, account: dict):
60 | session_name, phone_number, proxy = account.values()
61 |
62 | try:
63 | proxy_dict = self.parse_proxy(proxy) if proxy else None
64 |
65 | client = Client(name=session_name, api_id=self.api_id, api_hash=self.api_hash, workdir=self.workdir,
66 | proxy=proxy_dict)
67 |
68 | connect = await asyncio.wait_for(client.connect(), timeout=config.TIMEOUT)
69 | if connect:
70 | await client.get_me()
71 | await client.disconnect()
72 | return account
73 | else:
74 | await client.disconnect()
75 | except:
76 | pass
77 |
78 | async def check_valid_accounts(self, accounts: list):
79 | logger.info(f"Checking accounts for valid...")
80 |
81 | tasks = []
82 | for account in accounts:
83 | tasks.append(asyncio.create_task(self.check_valid_account(account)))
84 |
85 | v_accounts = await asyncio.gather(*tasks)
86 |
87 | valid_accounts = [account for account, is_valid in zip(accounts, v_accounts) if is_valid]
88 | invalid_accounts = [account for account, is_valid in zip(accounts, v_accounts) if not is_valid]
89 | logger.success(f"Valid accounts: {len(valid_accounts)}; Invalid: {len(invalid_accounts)}")
90 |
91 | return valid_accounts, invalid_accounts
92 |
93 | async def get_accounts(self):
94 | sessions = self.pars_sessions()
95 | available_accounts = self.get_available_accounts(sessions)
96 |
97 | if not available_accounts:
98 | raise ValueError("Have not available accounts!")
99 | else:
100 | logger.success(f"Search available accounts: {len(available_accounts)}.")
101 |
102 | valid_accounts, invalid_accounts = await self.check_valid_accounts(available_accounts)
103 |
104 | if invalid_accounts:
105 | save_list_to_file(f"{ config.WORKDIR}invalid_accounts.txt", invalid_accounts)
106 | logger.info(f"Saved {len(invalid_accounts)} invalid account(s) in { config.WORKDIR}invalid_accounts.txt")
107 |
108 | if not valid_accounts:
109 | raise ValueError("Have not valid sessions")
110 | else:
111 | return valid_accounts
112 |
113 | async def create_sessions(self):
114 | while True:
115 | session_name = input('\nInput the name of the session (press Enter to exit): ')
116 | if not session_name: return
117 |
118 | if config.PROXY['USE_PROXY_FROM_FILE']:
119 | proxys = get_all_lines(config.PROXY['PROXY_PATH'])
120 | proxy = random.choice(proxys) if proxys else None
121 | else:
122 | proxy = input("Input the proxy in the format login:password@ip:port (press Enter to use without proxy): ")
123 |
124 | dict_proxy = self.parse_proxy(proxy) if proxy else None
125 |
126 | phone_number = (input("Input the phone number of the account: ")).replace(' ', '')
127 | phone_number = '+' + phone_number if not phone_number.startswith('+') else phone_number
128 |
129 | client = Client(
130 | api_id=self.api_id,
131 | api_hash=self.api_hash,
132 | name=session_name,
133 | workdir=self.workdir,
134 | phone_number=phone_number,
135 | proxy=dict_proxy,
136 | lang_code='ru'
137 | )
138 |
139 | async with client:
140 | me = await client.get_me()
141 |
142 | save_to_json(f'{ config.WORKDIR}accounts.json', dict_={
143 | "session_name": session_name,
144 | "phone_number": phone_number,
145 | "proxy": proxy
146 | })
147 | logger.success(f'Added a account {me.username} ({me.first_name}) | {me.phone_number}')
--------------------------------------------------------------------------------
/utils/starter.py:
--------------------------------------------------------------------------------
1 | import os
2 | import random
3 | from itertools import zip_longest
4 | from utils.bool import Bool
5 | from aiohttp.client_exceptions import ContentTypeError
6 | from data import config
7 | from utils.core import logger
8 | import datetime
9 | import pandas as pd
10 | from utils.core.telegram import Accounts
11 | import asyncio
12 |
13 |
14 | async def start(thread: int, session_name: str, phone_number: str, proxy: [str, None]):
15 | bol = Bool(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy)
16 | account = session_name + '.session'
17 |
18 | await bol.login()
19 | logger.success(f"Thread {thread} | {account} | Login!")
20 |
21 | for task in await bol.get_tasks():
22 | if task['done']: continue
23 | if await bol.complete_task(task['assignmentId']):
24 | logger.success(f"Thread {thread} | {account} | Complete task «{task['title']}»! Reward: {task['reward']} tBOL")
25 | await asyncio.sleep(random.uniform(*config.DELAYS['TASK']))
26 |
27 | for task in await bol.get_daily_tasks():
28 | if task['done']: continue
29 | if await bol.complete_daily_task(task['assignmentId']):
30 | logger.success(f"Thread {thread} | {account} | Complete task «{task['title']}»! Reward: {task['reward']} tBOL")
31 | await asyncio.sleep(random.uniform(*config.DELAYS['TASK']))
32 |
33 | await bol.logout()
34 |
35 |
36 | async def stats():
37 | accounts = await Accounts().get_accounts()
38 |
39 | tasks = []
40 | for thread, account in enumerate(accounts):
41 | session_name, phone_number, proxy = account.values()
42 | tasks.append(asyncio.create_task(Bool(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy).stats()))
43 |
44 | data = await asyncio.gather(*tasks)
45 |
46 | path = f"statistics/statistics_{datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}.csv"
47 | columns = ['Phone number', 'Name', 'Balance', 'Rank', 'Referrals', 'Referral link', 'Proxy (login:password@ip:port)']
48 |
49 | if not os.path.exists('statistics'): os.mkdir('statistics')
50 | df = pd.DataFrame(data, columns=columns)
51 | df.to_csv(path, index=False, encoding='utf-8-sig')
52 |
53 | logger.success(f"Saved statistics to {path}")
54 |
--------------------------------------------------------------------------------