yasir68 commited on
Commit
e26cd2e
1 Parent(s): 8cf68d6

Upload folder using huggingface_hub (#1)

Browse files

- Upload folder using huggingface_hub (8cdbae16faff85fffba37495fe3b42c5176e2b69)

Files changed (48) hide show
  1. .env +15 -0
  2. .env-example +13 -0
  3. Dockerfile +13 -0
  4. INSTALL.bat +11 -0
  5. INSTALL.sh +48 -0
  6. START.bat +9 -0
  7. START.sh +10 -0
  8. bot/__init__.py +0 -0
  9. bot/__pycache__/__init__.cpython-310.pyc +0 -0
  10. bot/__pycache__/launcher.cpython-310.pyc +0 -0
  11. bot/__pycache__/utils.cpython-310.pyc +0 -0
  12. bot/config/__init__.py +0 -0
  13. bot/config/__pycache__/__init__.cpython-310.pyc +0 -0
  14. bot/config/__pycache__/headers.cpython-310.pyc +0 -0
  15. bot/config/__pycache__/logger.cpython-310.pyc +0 -0
  16. bot/config/__pycache__/settings.cpython-310.pyc +0 -0
  17. bot/config/headers.py +12 -0
  18. bot/config/logger.py +15 -0
  19. bot/config/settings.py +79 -0
  20. bot/core/__init__.py +0 -0
  21. bot/core/__pycache__/__init__.cpython-310.pyc +0 -0
  22. bot/core/__pycache__/api.cpython-310.pyc +0 -0
  23. bot/core/__pycache__/bot.cpython-310.pyc +0 -0
  24. bot/core/__pycache__/errors.cpython-310.pyc +0 -0
  25. bot/core/__pycache__/models.cpython-310.pyc +0 -0
  26. bot/core/__pycache__/utils.cpython-310.pyc +0 -0
  27. bot/core/api.py +320 -0
  28. bot/core/api_js_helpers/__init__.py +0 -0
  29. bot/core/api_js_helpers/__pycache__/__init__.cpython-310.pyc +0 -0
  30. bot/core/api_js_helpers/__pycache__/bet_counter.cpython-310.pyc +0 -0
  31. bot/core/api_js_helpers/__pycache__/upgrader.cpython-310.pyc +0 -0
  32. bot/core/api_js_helpers/bet_counter.py +48 -0
  33. bot/core/api_js_helpers/upgrader.py +90 -0
  34. bot/core/bot.py +427 -0
  35. bot/core/errors.py +3 -0
  36. bot/core/models.py +219 -0
  37. bot/core/utils.py +24 -0
  38. bot/helper/__pycache__/utils.cpython-310.pyc +0 -0
  39. bot/helper/utils.py +89 -0
  40. bot/launcher.py +129 -0
  41. bot/utils.py +34 -0
  42. data.json +0 -0
  43. docker-compose.yml +14 -0
  44. main.py +15 -0
  45. proxies.txt +5 -0
  46. requirements.txt +11 -0
  47. sessions/yasir.session +0 -0
  48. youtube.json +25 -0
.env ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ API_ID=25514329
3
+ API_HASH=2b15eb2dd52e935d6b091432b71cfc78
4
+
5
+ TAPS_ENABLED=True
6
+ TAPS_PER_SECOND=[20, 30]
7
+ PVP_ENABLED=False
8
+ PVP_LEAGUE=
9
+ PVP_STRATEGY=aggressive
10
+ PVP_COUNT=10
11
+ SLEEP_BETWEEN_START=
12
+ ERRORS_BEFORE_STOP=
13
+ USE_PROXY_FROM_FILE=
14
+ REF_ID=hero5413217144
15
+ MONEY_TO_SAVE=100
.env-example ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ API_ID=
2
+ API_HASH=
3
+
4
+ TAPS_ENABLED=
5
+ TAPS_PER_SECOND=
6
+ PVP_ENABLED=
7
+ PVP_LEAGUE=
8
+ PVP_STRATEGY=
9
+ PVP_COUNT=
10
+ SLEEP_BETWEEN_START=
11
+ ERRORS_BEFORE_STOP=
12
+ USE_PROXY_FROM_FILE=
13
+ REF_ID=
Dockerfile ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10
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
+ ENTRYPOINT ["python3", "main.py"]
13
+ CMD ["-a", "2"]
INSTALL.bat ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @echo off
2
+ echo Creating virtual environment...
3
+ python -m venv venv
4
+ echo Activating virtual environment...
5
+ call venv\Scripts\activate
6
+ echo Installing dependencies...
7
+ pip install -r requirements.txt
8
+ echo Copying .env-example to .env...
9
+ copy .env-example .env
10
+ echo Please edit the .env file to add your API_ID and API_HASH.
11
+ pause
INSTALL.sh ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ install_python() {
4
+ echo "Select the Python version to install:"
5
+ echo "1) Python 3.10"
6
+ echo "2) Python 3.11"
7
+ echo "3) Python 3.12"
8
+ read -p "Enter the number of your choice: " choice
9
+
10
+ case $choice in
11
+ 1) version="3.10" ;;
12
+ 2) version="3.11" ;;
13
+ 3) version="3.12" ;;
14
+ *) echo "Invalid choice"; exit 1 ;;
15
+ esac
16
+
17
+ if command -v apt-get &> /dev/null; then
18
+ sudo apt-get update
19
+ sudo apt-get install -y python$version python$version-venv python$version-pip
20
+ elif command -v yum &> /dev/null; then
21
+ sudo yum install -y https://repo.ius.io/ius-release-el$(rpm -E %{rhel}).rpm
22
+ sudo yum install -y python$version python$version-venv python$version-pip
23
+ elif command -v dnf &> /dev/null; then
24
+ sudo dnf install -y python$version python$version-venv python$version-pip
25
+ else
26
+ echo "Package manager not supported. Please install Python manually."
27
+ exit 1
28
+ fi
29
+ }
30
+
31
+ if ! command -v python3 &> /dev/null; then
32
+ install_python
33
+ fi
34
+
35
+ echo "Creating virtual environment..."
36
+ python3 -m venv venv
37
+
38
+ echo "Activating virtual environment..."
39
+ source venv/bin/activate
40
+
41
+ echo "Installing dependencies..."
42
+ pip install -r requirements.txt
43
+
44
+ echo "Copying .env-example to .env..."
45
+ cp .env-example .env
46
+
47
+ echo "Please edit the .env file to add your API_ID and API_HASH."
48
+ read -p "Press any key to continue..."
START.bat ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ @echo off
2
+ echo Activating virtual environment...
3
+ title MuskEmpire
4
+ call venv\Scripts\activate
5
+ echo Starting git pull
6
+ git pull
7
+ echo Starting the bot...
8
+ python main.py -a 2
9
+ pause
START.sh ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ echo "Activating virtual environment..."
4
+ source venv/bin/activate
5
+
6
+ echo "Starting the bot..."
7
+ python main.py
8
+
9
+ echo "Press any key to continue..."
10
+ read -n 1 -s
bot/__init__.py ADDED
File without changes
bot/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (131 Bytes). View file
 
bot/__pycache__/launcher.cpython-310.pyc ADDED
Binary file (4.55 kB). View file
 
bot/__pycache__/utils.cpython-310.pyc ADDED
Binary file (1.4 kB). View file
 
bot/config/__init__.py ADDED
File without changes
bot/config/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (138 Bytes). View file
 
bot/config/__pycache__/headers.cpython-310.pyc ADDED
Binary file (647 Bytes). View file
 
bot/config/__pycache__/logger.cpython-310.pyc ADDED
Binary file (539 Bytes). View file
 
bot/config/__pycache__/settings.cpython-310.pyc ADDED
Binary file (3.54 kB). View file
 
bot/config/headers.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ headers = {
2
+ "Accept": "*/*",
3
+ "Accept-Language": "ru,ru-RU;q=0.9,en-US;q=0.8,en;q=0.7",
4
+ "Content-Type": "application/json",
5
+ "Origin": "https://game.xempire.io",
6
+ "Referer": "https://game.xempire.io/",
7
+ "Sec-Fetch-Dest": "empty",
8
+ "Sec-Fetch-Mode": "cors",
9
+ "Sec-Fetch-Site": "same-site",
10
+ "User-Agent": "Mozilla/5.0 (Linux; Android 9; SM-N971N Build/PQ3B.190801.07101020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/124.0.6367.82 Safari/537.36",
11
+ "X-Requested-With": "org.telegram.messenger.web",
12
+ }
bot/config/logger.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+
3
+ from loguru import logger
4
+
5
+ logger.remove()
6
+
7
+ logger_str_format = (
8
+ "<white>{time:YYYY-MM-DD HH:mm:ss}</white> | "
9
+ "<level>{level: <8}</level> | "
10
+ "<c><b>{line: <5}</b></c>| "
11
+ "<c><b>{extra[session_name]: <7}</b></c> | "
12
+ "<white><b>{message}</b></white>"
13
+ )
14
+ logger.add(sink=sys.stdout, format=logger_str_format, colorize=True)
15
+ log = logger.bind(session_name="GLOBAL").opt(colors=True)
bot/config/settings.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+
3
+ from pydantic import Field
4
+ from pydantic_settings import BaseSettings, SettingsConfigDict
5
+
6
+ logo = """
7
+
8
+ ███ ███ ██ ██ ███████ ██ ██ ███████ ███ ███ ██████ ██ ██████ ███████
9
+ ████ ████ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██
10
+ ██ ████ ██ ██ ██ ███████ █████ █████ ██ ████ ██ ██████ ██ ██████ █████
11
+ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
12
+ ██ ██ ██████ ███████ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ███████
13
+
14
+ """
15
+
16
+
17
+ class Strategy(str, Enum):
18
+ flexible = "flexible"
19
+ protective = "protective"
20
+ aggressive = "aggressive"
21
+ random = "random"
22
+
23
+
24
+ class League(str, Enum):
25
+ bronze = "bronze"
26
+ silver = "silver"
27
+ gold = "gold"
28
+ platina = "platina"
29
+ diamond = "diamond"
30
+
31
+
32
+ class Settings(BaseSettings):
33
+ model_config = SettingsConfigDict(env_file=".env", env_ignore_empty=True, extra="allow")
34
+
35
+ API_ID: int
36
+ API_HASH: str
37
+
38
+ LOGIN_TIMEOUT: int = 3600
39
+
40
+ TAPS_ENABLED: bool = True
41
+ TAPS_PER_SECOND: list[int] = [20, 30]
42
+ AUTO_UPGRADE_HERO: bool = True
43
+ PVP_ENABLED: bool = True
44
+ PVP_LEAGUE: League = League.bronze
45
+ PVP_STRATEGY: Strategy = Strategy.random
46
+ PVP_COUNT: int = 5
47
+
48
+ SLEEP_BETWEEN_START: list[int] = [10, 20]
49
+ SESSION_AC_DELAY: int = 10
50
+ ERRORS_BEFORE_STOP: int = 5
51
+ USE_PROXY_FROM_FILE: bool = False
52
+ ADD_LOCAL_MACHINE_AS_IP: bool = False
53
+
54
+ RANDOM_SLEEP_TIME: int = 8
55
+ SKILL_WEIGHT: float = 0
56
+ MAX_SKILL_UPGRADE_COSTS: int = 5e9
57
+
58
+ MONEY_TO_SAVE: int = 1_000_000
59
+
60
+ AUTO_UPGRADE_MINING: bool = True
61
+ MAX_MINING_UPGRADE_LEVEL: int = 30
62
+ MAX_MINING_ENERGY_RECOVERY_UPGRADE_LEVEL: int = 60
63
+ MINING_ENERGY_SKILLS: list[str] = ["energy_capacity", "energy_recovery", "profit_per_tap_power"]
64
+ MAX_MINING_UPGRADE_COSTS: int = 5_000_000
65
+
66
+ SKIP_IMPROVE_DISCIPLINE_BUG: bool = Field(
67
+ default=False,
68
+ description="Skip improve discipline bug for eror "
69
+ "{'success': False, 'error': 'invalid key improve_discipline'}",
70
+ )
71
+ SKIP_TO_UPGRADE_SKILLS: list = Field([], description='Skip upgrade skills. For example: ["Уборщик", "Рекрутер,HR"]')
72
+
73
+ BOT_SLEEP_TIME: list[int] = [3000, 3500]
74
+ REF_ID: str = "hero1092379081"
75
+ base_url: str = "https://game.muskempire.io/"
76
+ bot_name: str = "empirebot"
77
+
78
+
79
+ config = Settings()
bot/core/__init__.py ADDED
File without changes
bot/core/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (136 Bytes). View file
 
bot/core/__pycache__/api.cpython-310.pyc ADDED
Binary file (11.5 kB). View file
 
bot/core/__pycache__/bot.cpython-310.pyc ADDED
Binary file (16.4 kB). View file
 
bot/core/__pycache__/errors.cpython-310.pyc ADDED
Binary file (464 Bytes). View file
 
bot/core/__pycache__/models.cpython-310.pyc ADDED
Binary file (6.96 kB). View file
 
bot/core/__pycache__/utils.cpython-310.pyc ADDED
Binary file (900 Bytes). View file
 
bot/core/api.py ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import json
3
+ import random
4
+ from datetime import datetime
5
+ from typing import NamedTuple
6
+ from urllib.parse import parse_qs
7
+
8
+ import aiohttp
9
+ from aiocache import Cache, cached
10
+ from better_proxy import Proxy
11
+ from pyrogram import Client, errors
12
+ from pyrogram.errors import FloodWait, RPCError, UserAlreadyParticipant
13
+ from pyrogram.raw.functions import account
14
+ from pyrogram.raw.functions.messages import RequestAppWebView
15
+ from pyrogram.raw.types import InputBotAppShortName, InputNotifyPeer, InputPeerNotifySettings
16
+ from pytz import UTC
17
+
18
+ from bot.config.logger import log
19
+ from bot.config.settings import config
20
+ from bot.helper.utils import error_handler, handle_request
21
+
22
+ from .errors import TapsError
23
+ from .models import FundHelper, Profile, PvpData, UserDataAfter
24
+ from .utils import num_prettier
25
+
26
+
27
+ class TgWebData(NamedTuple):
28
+ hash: str
29
+ request_data: dict
30
+
31
+
32
+ class CryptoBotApi:
33
+ def __init__(self, tg_client: Client):
34
+ self.session_name = tg_client.name
35
+ self.tg_client = tg_client
36
+ self.user_id = None
37
+ self.api_url = "https://api.xempire.io"
38
+ self.need_quiz = False
39
+ self.need_rebus = False
40
+ self.rebus_key = ""
41
+ self.errors = 0
42
+ self.logger = log.bind(session_name=self.session_name)
43
+ self._peer = None
44
+
45
+ async def get_tg_web_data(self, proxy: str | None) -> TgWebData:
46
+ if proxy:
47
+ proxy = Proxy.from_str(proxy)
48
+ proxy_dict = {
49
+ "scheme": proxy.protocol,
50
+ "hostname": proxy.host,
51
+ "port": proxy.port,
52
+ "username": proxy.login,
53
+ "password": proxy.password,
54
+ }
55
+ else:
56
+ proxy_dict = None
57
+
58
+ self.tg_client.proxy = proxy_dict
59
+
60
+ try:
61
+ async with self.tg_client:
62
+ if not self._peer:
63
+ try:
64
+ self._peer = await self.tg_client.resolve_peer(config.bot_name)
65
+ except FloodWait as error:
66
+ self.logger.warning(f"FloodWait error: {error} | Retry in {error.value} seconds")
67
+ await asyncio.sleep(delay=error.value)
68
+ # update in session db peer ids to fix this errors˚
69
+ async for dialog in self.tg_client.get_dialogs():
70
+ if dialog.chat and dialog.chat.username and dialog.chat.username == config.bot_name:
71
+ break
72
+ self._peer = await self.tg_client.resolve_peer(config.bot_name)
73
+
74
+ web_view = await self.tg_client.invoke(
75
+ RequestAppWebView(
76
+ peer=self._peer,
77
+ app=InputBotAppShortName(bot_id=self._peer, short_name="game"),
78
+ platform="android",
79
+ write_allowed=True,
80
+ start_param=config.REF_ID,
81
+ )
82
+ )
83
+ tg_web_data = parse_qs(web_view.url.split("#")[1]).get("tgWebAppData")[0]
84
+ query_params = parse_qs(tg_web_data)
85
+ return TgWebData(
86
+ request_data={
87
+ "data": {
88
+ "chatId": "",
89
+ "chatInstance": tg_web_data,
90
+ "chatType": query_params.get("chat_type")[0],
91
+ "initData": tg_web_data,
92
+ "platform": "android",
93
+ "startParam": config.REF_ID,
94
+ },
95
+ },
96
+ hash=query_params.get("hash")[0],
97
+ )
98
+
99
+ except RuntimeError as error:
100
+ raise error from error
101
+ except FloodWait as error:
102
+ log.warning(f"{self.session_name} | FloodWait error: {error} | Retry in {error.value} seconds")
103
+ await asyncio.sleep(delay=error.value)
104
+ raise
105
+ except Exception as error:
106
+ log.error(f"{self.session_name} | Authorization error: {error}")
107
+ await asyncio.sleep(delay=3)
108
+ raise
109
+
110
+ async def join_and_archive_channel(self, channel_name: str) -> None:
111
+ try:
112
+ async with self.tg_client:
113
+ try:
114
+ chat = await self.tg_client.join_chat(channel_name)
115
+ self.logger.info(f"Successfully joined to <g>{chat.title}</g>")
116
+ except UserAlreadyParticipant:
117
+ self.logger.info(f"Chat <y>{channel_name}</y> already joined")
118
+ chat = await self.tg_client.get_chat(channel_name)
119
+ except RPCError:
120
+ self.logger.error(f"Channel <y>{channel_name}</y> not found")
121
+ raise
122
+
123
+ await self.sleeper()
124
+ peer = await self.tg_client.resolve_peer(chat.id)
125
+
126
+ await self.tg_client.invoke(
127
+ account.UpdateNotifySettings(
128
+ peer=InputNotifyPeer(peer=peer), settings=InputPeerNotifySettings(mute_until=2147483647)
129
+ )
130
+ )
131
+ self.logger.info(f"Successfully muted chat <g>{chat.title}</g> for channel <y>{channel_name}</y>")
132
+ await self.sleeper()
133
+ await self.tg_client.archive_chats(chat_ids=[chat.id])
134
+ self.logger.info(f"Channel <g>{chat.title}</g> successfully archived for channel <y>{channel_name}</y>")
135
+
136
+ except errors.FloodWait as e:
137
+ self.logger.error(f"Waiting {e.value} seconds before the next attempt.")
138
+ await asyncio.sleep(e.value)
139
+ raise
140
+
141
+ async def sleeper(self, delay: int = config.RANDOM_SLEEP_TIME, additional_delay: int = 4) -> None:
142
+ await asyncio.sleep(random.random() * delay + additional_delay)
143
+
144
+ @error_handler()
145
+ @handle_request("/telegram/auth")
146
+ async def login(self, *, response_json: dict, json_body: dict) -> bool:
147
+ if response_json.get("success", False):
148
+ self.logger.success("Login successful")
149
+ return True
150
+ return False
151
+
152
+ @error_handler()
153
+ @handle_request("/dbs", json_body={"data": {"dbs": ["all"]}})
154
+ async def get_dbs(self, *, response_json: dict) -> dict:
155
+ return response_json["data"]
156
+
157
+ @error_handler()
158
+ @handle_request("/hero/balance/sync", json_body={"data": {}})
159
+ async def syn_hero_balance(self, *, response_json: dict) -> Profile:
160
+ self._update_money_balance(response_json)
161
+ self.logger.info(
162
+ f"Level: <blue>{self.level}</blue> | "
163
+ f"Balance: <y>{num_prettier(self.balance)}</y> | "
164
+ f"Money per hour: <g>{num_prettier(self.mph)}</g>"
165
+ )
166
+ return Profile(**response_json["data"])
167
+
168
+ @error_handler()
169
+ @handle_request("/user/data/all", json_body={"data": {}})
170
+ async def get_profile_full(self, *, response_json: dict) -> dict:
171
+ return dict(**response_json["data"])
172
+
173
+ @error_handler()
174
+ @handle_request("/user/data/after", json_body={"data": {"lang": "en"}})
175
+ async def user_data_after(self, *, response_json: dict) -> UserDataAfter:
176
+ return UserDataAfter(**response_json["data"])
177
+
178
+ @error_handler()
179
+ @handle_request("/hero/bonus/offline/claim")
180
+ async def get_offline_bonus(self, *, response_json: dict) -> None:
181
+ self._update_money_balance(response_json)
182
+ self.logger.success(f"Offline bonus claimed: <y>+{num_prettier(self.user_profile.offline_bonus)}</y>")
183
+
184
+ @error_handler()
185
+ @handle_request("/quests/daily/claim")
186
+ async def daily_reward(self, *, response_json: dict, json_body: dict) -> None:
187
+ self._update_money_balance(response_json)
188
+
189
+ @error_handler()
190
+ @handle_request("/quests/claim")
191
+ async def quest_reward_claim(self, *, response_json: dict, json_body: dict) -> bool:
192
+ self._update_money_balance(response_json)
193
+ return True
194
+
195
+ @error_handler()
196
+ @handle_request("/quests/daily/progress/claim")
197
+ async def daily_quest_reward(self, *, response_json: dict, json_body: dict) -> None:
198
+ self._update_money_balance(response_json)
199
+
200
+ @error_handler()
201
+ @handle_request("/quests/daily/progress/all")
202
+ async def all_daily_quests(self, *, response_json: dict) -> dict:
203
+ return response_json["data"]
204
+
205
+ @error_handler()
206
+ @handle_request("/quests/check")
207
+ async def quest_check(self, *, response_json: dict, json_body: dict) -> bool:
208
+ await self.sleeper()
209
+ await self.quest_reward_claim(json_body=json_body)
210
+
211
+ @error_handler()
212
+ @handle_request("/friends/claim")
213
+ async def friend_reward(self, *, response_json: dict, json_body: dict) -> None:
214
+ self._update_money_balance(response_json)
215
+
216
+ @error_handler()
217
+ @handle_request("/hero/action/tap")
218
+ async def api_perform_taps(self, *, response_json: dict, json_body: dict) -> int:
219
+ if (error_msg := response_json.get("error")) and "take some rest" in error_msg:
220
+ raise TapsError(error_msg)
221
+ data = self._update_money_balance(response_json)
222
+ self.tapped_today = data.get("tappedToday", 0)
223
+ return int(data["hero"]["earns"]["task"]["energy"])
224
+
225
+ @cached(ttl=2 * 60 * 60, cache=Cache.MEMORY)
226
+ @error_handler()
227
+ @handle_request(
228
+ "https://raw.githubusercontent.com/testingstrategy/musk_daily/main/daily.json",
229
+ method="GET",
230
+ full_url=True,
231
+ )
232
+ async def get_helper(self, *, response_json: str) -> FundHelper | dict:
233
+ response_json = json.loads(response_json)
234
+ return FundHelper(
235
+ funds=response_json.get(str(datetime.now(UTC).date()), {}).get("funds", set()),
236
+ **response_json,
237
+ )
238
+
239
+ @error_handler()
240
+ @handle_request("/fund/info")
241
+ async def get_funds_info(self, *, response_json: dict) -> dict:
242
+ return response_json["data"]
243
+
244
+ @error_handler()
245
+ @handle_request("/box/list", json_body={})
246
+ async def get_box_list(self, *, response_json: dict) -> dict:
247
+ return response_json["data"] or {}
248
+
249
+ @error_handler()
250
+ @handle_request("/box/open")
251
+ async def box_open(self, *, response_json: dict, json_body: dict) -> list:
252
+ return response_json["data"]
253
+
254
+ @error_handler()
255
+ @handle_request("/pvp/info")
256
+ async def get_pvp_info(self, *, response_json: dict) -> dict:
257
+ return response_json["data"]
258
+
259
+ @error_handler()
260
+ @handle_request("/pvp/fight/start")
261
+ async def get_pvp_fight(self, *, response_json: dict, json_body: dict) -> PvpData | None:
262
+ if response_json["data"].get("opponent"):
263
+ return PvpData(**response_json["data"])
264
+ return None
265
+
266
+ @error_handler()
267
+ @handle_request("/pvp/claim")
268
+ async def get_pvp_claim(self, *, response_json: dict) -> None:
269
+ if response_json.get("success"):
270
+ self._update_money_balance(response_json)
271
+
272
+ @error_handler()
273
+ @handle_request(
274
+ "/settings/save",
275
+ json_body={
276
+ "data": {
277
+ "id": None,
278
+ "music": False,
279
+ "sound": True,
280
+ "vibrate": True,
281
+ "animations": True,
282
+ "darkTheme": True,
283
+ "lang": "en",
284
+ }
285
+ },
286
+ )
287
+ async def sent_eng_settings(self, *, response_json: dict) -> None: ...
288
+
289
+ @error_handler()
290
+ @handle_request("/fund/invest")
291
+ async def invest(self, *, response_json: dict, json_body: dict) -> None:
292
+ data = self._update_money_balance(response_json)
293
+ for fnd in data["funds"]:
294
+ if fnd["fundKey"] == json_body["data"]["fund"]:
295
+ money = fnd["moneyProfit"]
296
+ money_str = (
297
+ f"Win: <y>+{num_prettier(money)}</y>" if money > 0 else f"Loss: <red>{num_prettier(money)}</red>"
298
+ )
299
+ self.logger.success(f"Invest completed: {money_str}")
300
+ break
301
+
302
+ @error_handler()
303
+ @handle_request("/skills/improve")
304
+ async def skills_improve(self, *, response_json: dict, json_body: dict) -> None:
305
+ self._update_money_balance(response_json)
306
+
307
+ async def check_proxy(self, proxy: Proxy) -> None:
308
+ try:
309
+ response = await self.http_client.get(url="https://httpbin.org/ip", timeout=aiohttp.ClientTimeout(10))
310
+ ip = (await response.json()).get("origin")
311
+ self.logger.info(f"Proxy IP: {ip}")
312
+ except Exception:
313
+ self.logger.exception(f"Proxy: {proxy}")
314
+
315
+ def _update_money_balance(self, response_json: dict) -> dict:
316
+ response_json = response_json["data"]
317
+ self.balance = int(response_json["hero"]["money"])
318
+ self.level = int(response_json["hero"]["level"])
319
+ self.mph = int(response_json["hero"]["moneyPerHour"])
320
+ return response_json
bot/core/api_js_helpers/__init__.py ADDED
File without changes
bot/core/api_js_helpers/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (151 Bytes). View file
 
bot/core/api_js_helpers/__pycache__/bet_counter.cpython-310.pyc ADDED
Binary file (1.72 kB). View file
 
bot/core/api_js_helpers/__pycache__/upgrader.cpython-310.pyc ADDED
Binary file (3.24 kB). View file
 
bot/core/api_js_helpers/bet_counter.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class BetCounter:
2
+ bet_steps_count = 7
3
+
4
+ def __init__(self, obj):
5
+ self.obj = obj
6
+
7
+ def min_bet(self):
8
+ multiplier = 2
9
+ if self.obj.level < 3:
10
+ multiplier = 5
11
+ elif self.obj.level < 6:
12
+ multiplier = 4
13
+ elif self.obj.level < 10:
14
+ multiplier = 3
15
+
16
+ calculated_bet = self.smart_zero_round(self.obj.mph * multiplier / (self.bet_steps_count * 3))
17
+ return calculated_bet or 100
18
+
19
+ def max_bet(self):
20
+ return self.min_bet() * self.bet_steps_count
21
+
22
+ def smart_zero_round(self, amount: int):
23
+ def round_to_nearest(value, base=100):
24
+ return round(value / base) * base
25
+
26
+ if amount < 100:
27
+ return round_to_nearest(amount, 50)
28
+ elif amount < 1000:
29
+ return round_to_nearest(amount, 100)
30
+ elif amount < 10000:
31
+ return round_to_nearest(amount, 1000)
32
+ elif amount < 100000:
33
+ return round_to_nearest(amount, 10000)
34
+ elif amount < 1000000:
35
+ return round_to_nearest(amount, 100000)
36
+ elif amount < 10000000:
37
+ return round_to_nearest(amount, 1000000)
38
+ elif amount < 100000000:
39
+ return round_to_nearest(amount, 10000000)
40
+ else:
41
+ return round_to_nearest(amount, 1000)
42
+
43
+ def calculate_bet(self) -> int:
44
+ max_bet_ = self.max_bet()
45
+ min_bet_ = self.min_bet()
46
+ while max_bet_ > self.obj.balance:
47
+ max_bet_ -= min_bet_
48
+ return max_bet_
bot/core/api_js_helpers/upgrader.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+
3
+
4
+ class Calculator:
5
+ def get_price(self, data, level):
6
+ return self.calculate_formula(data.priceFormula, level, data.priceBasic, data.priceFormulaK) if level else 0
7
+
8
+ def get_profit(self, data, level):
9
+ return (
10
+ self.calculate_formula(data.profitFormula, level, data.profitBasic, data.priceFormulaK, data)
11
+ if level
12
+ else 0
13
+ )
14
+
15
+ def calculate_formula(self, formula, level, base_value, formula_coefficient, data=None):
16
+ result = base_value
17
+ if formula == "fnCompound":
18
+ result = self.fn_compound(level, base_value, formula_coefficient)
19
+ elif formula == "fnLogarithmic":
20
+ result = self.fn_logarithmic(level, base_value)
21
+ elif formula == "fnLinear":
22
+ result = self.fn_linear(level, base_value)
23
+ elif formula == "fnQuadratic":
24
+ result = self.fn_quadratic(level, base_value)
25
+ elif formula == "fnCubic":
26
+ result = self.fn_cubic(level, base_value)
27
+ elif formula == "fnExponential":
28
+ result = self.fn_exponential(level, base_value, formula_coefficient)
29
+ elif formula == "fnPayback":
30
+ result = self.fn_payback(level, data)
31
+
32
+ return self.smart_round(result)
33
+
34
+ def smart_round(self, value):
35
+ def round_to(value, factor=100):
36
+ return round(value / factor) * factor
37
+
38
+ if value < 50:
39
+ return round(value)
40
+ elif value < 100:
41
+ return round_to(value, 5)
42
+ elif value < 500:
43
+ return round_to(value, 25)
44
+ elif value < 1000:
45
+ return round_to(value, 50)
46
+ elif value < 5000:
47
+ return round_to(value, 100)
48
+ elif value < 10000:
49
+ return round_to(value, 200)
50
+ elif value < 100000:
51
+ return round_to(value, 500)
52
+ elif value < 500000:
53
+ return round_to(value, 1000)
54
+ elif value < 1000000:
55
+ return round_to(value, 5000)
56
+ elif value < 50000000:
57
+ return round_to(value, 10000)
58
+ elif value < 100000000:
59
+ return round_to(value, 50000)
60
+ else:
61
+ return round_to(value, 100000)
62
+
63
+ def fn_linear(self, level, base_value):
64
+ return base_value * level
65
+
66
+ def fn_quadratic(self, level, base_value):
67
+ return base_value * level * level
68
+
69
+ def fn_cubic(self, level, base_value):
70
+ return base_value * level * level * level
71
+
72
+ def fn_exponential(self, level, base_value, coefficient):
73
+ return base_value * math.pow(coefficient / 10, level)
74
+
75
+ def fn_logarithmic(self, level, base_value):
76
+ return base_value * math.log2(level + 1)
77
+
78
+ def fn_compound(self, level, base_value, coefficient):
79
+ compound_rate = coefficient / 100
80
+ return base_value * math.pow(1 + compound_rate, level - 1)
81
+
82
+ def fn_payback(self, level, data):
83
+ accumulated = [0]
84
+ for current_level in range(1, level + 1):
85
+ previous_accumulated = accumulated[current_level - 1]
86
+ current_price = self.get_price(data, current_level)
87
+ current_profit = data.profitBasic + data.profitFormulaK * (current_level - 1)
88
+ smart_rounded_value = self.smart_round(previous_accumulated + current_price / current_profit)
89
+ accumulated.append(smart_rounded_value)
90
+ return accumulated[level]
bot/core/bot.py ADDED
@@ -0,0 +1,427 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import math
3
+ import random
4
+ import time
5
+ from collections.abc import Generator
6
+ from datetime import datetime
7
+ from enum import Enum
8
+
9
+ import aiohttp
10
+ from aiohttp_proxy import ProxyConnector
11
+ from aiohttp_socks import ProxyConnector as SocksProxyConnector
12
+ from pyrogram import Client
13
+ from pytz import UTC
14
+
15
+ from bot.config.headers import headers
16
+ from bot.config.logger import log
17
+ from bot.config.settings import Strategy, config
18
+ from bot.core.api_js_helpers.bet_counter import BetCounter
19
+
20
+ from .api import CryptoBotApi
21
+ from .errors import TapsError
22
+ from .models import DbSkill, DbSkills, Profile, ProfileData, SessionData, SkillLevel
23
+ from .utils import load_codes_from_files, num_prettier
24
+
25
+
26
+ class CryptoBot(CryptoBotApi):
27
+ def __init__(self, tg_client: Client, additional_data: dict) -> None:
28
+ super().__init__(tg_client)
29
+ self.temporary_stop_taps_time = 0
30
+ self.bet_calculator = BetCounter(self)
31
+ self.pvp_count = config.PVP_COUNT
32
+ self.authorized = False
33
+ self.settings_was_set = False
34
+ self.sleep_time = config.BOT_SLEEP_TIME
35
+ self.additional_data: SessionData = SessionData.model_validate(
36
+ {k: v for d in additional_data for k, v in d.items()}
37
+ )
38
+
39
+ async def claim_daily_reward(self) -> None:
40
+ for day, status in self.data_after.daily_rewards.items():
41
+ if status == "canTake":
42
+ await self.daily_reward(json_body={"data": str(day)})
43
+ self.logger.success("Daily reward claimed")
44
+ return
45
+
46
+ async def perform_taps(self, profile: Profile) -> None:
47
+ self.logger.info("Taps started")
48
+ energy = profile.energy
49
+ while True:
50
+ taps_per_second = random.randint(*config.TAPS_PER_SECOND)
51
+ seconds = random.randint(5, 8)
52
+ earned_money = profile.money_per_tap * taps_per_second * seconds
53
+ energy_spent = math.ceil(earned_money / 2)
54
+ energy -= energy_spent
55
+ if energy < 0:
56
+ self.logger.info("Taps stopped (not enough energy)")
57
+ break
58
+ await asyncio.sleep(delay=seconds)
59
+ try:
60
+ json_data = {
61
+ "data": {
62
+ "data": {"task": {"amount": earned_money, "currentEnergy": energy}},
63
+ "seconds": seconds,
64
+ }
65
+ }
66
+ energy = await self.api_perform_taps(json_body=json_data)
67
+ self.logger.success(
68
+ f"Earned money: <y>+{num_prettier(earned_money)}</y> | Energy left: <blue>{num_prettier(energy)}</blue>"
69
+ )
70
+ except TapsError as e:
71
+ self.logger.warning(f"Taps stopped (<red>{e.message}</red>)")
72
+ self.temporary_stop_taps_time = time.monotonic() + 60 * 60 * 3
73
+ break
74
+
75
+ async def execute_and_claim_daily_quest(self) -> None:
76
+ helper_data = await self.get_helper()
77
+ helper_data.youtube.update(load_codes_from_files())
78
+ all_daily_quests = await self.all_daily_quests()
79
+ for key, value in all_daily_quests.items():
80
+ desc = value["description"]
81
+ if (
82
+ value["type"] == "youtube"
83
+ and not value["isRewarded"]
84
+ and (code := helper_data.youtube.get(value["description"])) is not None
85
+ ):
86
+ await self.daily_quest_reward(json_body={"data": {"quest": key, "code": str(code)}})
87
+ self.logger.info(f"Quest <g>{desc}</g> claimed")
88
+ elif desc:
89
+ self.logger.info(f"Quest not executed: \n<r>{desc}</r>")
90
+ if not value["isRewarded"] and value["isComplete"] and not value["url"]:
91
+ await self.daily_quest_reward(json_body={"data": {"quest": key, "code": None}})
92
+ self.logger.info(f"Quest <g>{key}</g> claimed")
93
+
94
+ async def claim_all_executed_quest(self) -> None:
95
+ for i in self.data_after.quests:
96
+ if not i["isRewarded"]:
97
+ if config.SKIP_IMPROVE_DISCIPLINE_BUG and i["key"] == "improve_discipline":
98
+ continue
99
+ await self.quest_reward_claim(json_body={"data": [i["key"], None]})
100
+ self.logger.info(f'Quest <g>{i["key"]}</g> claimed ')
101
+
102
+ def random_pvp_count(self) -> int:
103
+ return random.randint(config.PVP_COUNT, config.PVP_COUNT * 2)
104
+
105
+ async def _perform_pvp(self, league: dict, strategy: str) -> None:
106
+ self.pvp_count = self.random_pvp_count()
107
+ self.logger.info(
108
+ f"PvP negotiations started | League: <blue>{league['key']}</blue> | Strategy: <g>{strategy}</g>"
109
+ )
110
+ res = await self.get_pvp_info()
111
+ await self.sleeper()
112
+ if res.get("fight"):
113
+ await self.get_pvp_claim()
114
+ await self.sleeper()
115
+ current_strategy = strategy
116
+ money = 0
117
+ while self.pvp_count > 0:
118
+ if self.balance < int(league["maxContract"]):
119
+ money_str = (
120
+ f"Profit: <y>+{num_prettier(money)}</y>"
121
+ if money >= 0
122
+ else f"Loss: <red>-{num_prettier(money)}</red>"
123
+ )
124
+ self.logger.info(f"PvP negotiations stopped (<red>not enough money</red>). Pvp profit: {money_str}")
125
+ break
126
+
127
+ if strategy == "random":
128
+ current_strategy = random.choice(self.strategies)
129
+ self.logger.info("Searching opponent...")
130
+ current_strategy = current_strategy.value if isinstance(current_strategy, Enum) else current_strategy
131
+ json_data = {"data": {"league": league["key"], "strategy": current_strategy}}
132
+ response_json = await self.get_pvp_fight(json_body=json_data)
133
+ if response_json is None:
134
+ await self.sleeper(delay=10, additional_delay=5)
135
+ continue
136
+
137
+ fight = response_json.fight
138
+ opponent_strategy = (
139
+ fight.player2Strategy if fight.player1 == self.user_profile.user_id else fight.player1Strategy
140
+ )
141
+ if fight.winner == self.user_profile.user_id:
142
+ money += fight.moneyProfit
143
+ log_part = f"You <g>WIN</g> (<y>+{num_prettier(fight.moneyProfit)})</y>"
144
+ else:
145
+ money -= fight.moneyContract
146
+ log_part = f"You <red>LOSE</red> (<y>-{num_prettier(fight.moneyProfit)}</y>)"
147
+ self.logger.success(
148
+ f"Contract sum: <y>{num_prettier(fight.moneyContract)}</y> | "
149
+ f"Your strategy: <c>{current_strategy}</c> | "
150
+ f"Opponent strategy: <blue>{opponent_strategy}</blue> | "
151
+ f"{log_part}"
152
+ )
153
+ await self.sleeper(additional_delay=10)
154
+ await self.get_pvp_claim()
155
+ self.pvp_count -= 1
156
+ await self.sleeper()
157
+
158
+ self.logger.info(
159
+ "Total money after all pvp:"
160
+ + (f"<i><g>+{num_prettier(money)}</g></i>" if money >= 0 else f"<i><red>{num_prettier(money)}</red></i>")
161
+ )
162
+ self.pvp_count = config.PVP_COUNT
163
+
164
+ async def get_friend_reward(self) -> None:
165
+ for friend in [friend for friend in self.data_after.friends if friend["bonusToTake"] > 0]:
166
+ await self.friend_reward(json_body={"data": friend["id"]})
167
+ self.logger.info(
168
+ f"Friend <g>{friend['name']}</g> claimed money <y>{num_prettier(friend['bonusToTake'])}</y>"
169
+ )
170
+ await self.sleeper()
171
+
172
+ async def solve_quiz_and_rebus(self) -> None:
173
+ for quest in self.dbs["dbQuests"]:
174
+ quest_key = quest["key"]
175
+ if quest["requiredLevel"] > self.user_profile.level:
176
+ continue
177
+ if "t.me" in (link := quest.get("actionUrl")) and not self._is_event_solved(quest_key):
178
+ if len(link.split("/")) > 4 or "muskempire" in link:
179
+ continue
180
+ if quest["checkType"] != "fakeCheck":
181
+ link = link if "/+" in link else link.split("/")[-1]
182
+ await self.join_and_archive_channel(link)
183
+ await self.quest_check(json_body={"data": [quest_key]})
184
+ self.logger.info(
185
+ f'Claimed <g>{quest["title"]}</g> Reward: <y>+{num_prettier(quest["rewardMoney"])}</y>quest'
186
+ )
187
+ if any(i in quest_key for i in ("riddle", "rebus", "tg_story")) and not self._is_event_solved(quest_key):
188
+ await self.quest_check(json_body={"data": [quest_key, quest["checkData"]]})
189
+ self.logger.info(f"Was solved <g>{quest['title']}</g>")
190
+
191
+ def _is_event_solved(self, quest_key: str) -> bool:
192
+ return self.data_after.quests and any(i["key"] == quest_key for i in self.data_after.quests)
193
+
194
+ async def set_funds(self) -> None:
195
+ helper_data = await self.get_helper()
196
+ if helper_data.funds:
197
+ current_invest = await self.get_funds_info()
198
+ already_funded = {i["fundKey"] for i in current_invest["funds"]}
199
+ for fund in list(helper_data.funds - already_funded)[: 3 - len(already_funded)]:
200
+ if self.balance > (amount := self.bet_calculator.calculate_bet()):
201
+ self.logger.info(f"Investing <y>{num_prettier(amount)}</y> to fund <blue>{fund}</blue>")
202
+ await self.invest(json_body={"data": {"fund": fund, "money": amount}})
203
+ else:
204
+ self.logger.info("Not enough money for invest")
205
+
206
+ async def starting_pvp(self) -> None:
207
+ if self.dbs:
208
+ league_data = None
209
+ for league in self.dbs["dbNegotiationsLeague"]:
210
+ if league["key"] == config.PVP_LEAGUE:
211
+ league_data = league
212
+ break
213
+
214
+ if league_data is not None:
215
+ if self.level >= int(league_data["requiredLevel"]):
216
+ self.strategies = [strategy["key"] for strategy in self.dbs["dbNegotiationsStrategy"]]
217
+ if Strategy.random == config.PVP_STRATEGY or config.PVP_STRATEGY in self.strategies:
218
+ await self._perform_pvp(
219
+ league=league_data,
220
+ strategy=config.PVP_STRATEGY.value,
221
+ )
222
+ else:
223
+ config.PVP_ENABLED = False
224
+ self.logger.warning("PVP_STRATEGY param is invalid. PvP negotiations disabled.")
225
+ else:
226
+ config.PVP_ENABLED = False
227
+ self.logger.warning(
228
+ f"Your level is too low for the {config.PVP_LEAGUE} league. PvP negotiations disabled."
229
+ )
230
+ else:
231
+ config.PVP_ENABLED = False
232
+ self.logger.warning("PVP_LEAGUE param is invalid. PvP negotiations disabled.")
233
+ else:
234
+ self.logger.warning("Database is missing. PvP negotiations will be skipped this time.")
235
+
236
+ async def upgrade_hero(self) -> None:
237
+ available_skill = list(self._get_available_skills())
238
+ if config.AUTO_UPGRADE_HERO:
239
+ await self._upgrade_hero_skill(available_skill)
240
+ if config.AUTO_UPGRADE_MINING:
241
+ await self._upgrade_mining_skill(available_skill)
242
+
243
+ async def get_box_rewards(self) -> None:
244
+ boxes = await self.get_box_list()
245
+ for key, box_count in boxes.items():
246
+ for _ in range(box_count):
247
+ res = await self.box_open(json_body={"data": key})
248
+ self.logger.info(f"Box <g>{key}</g> Was looted: <y>{res['loot']}</y>")
249
+
250
+ async def _upgrade_mining_skill(self, available_skill: list[DbSkill]) -> None:
251
+ for skill in [skill for skill in available_skill if skill.category == "mining"]:
252
+ if (
253
+ skill.key in config.MINING_ENERGY_SKILLS
254
+ and skill.next_level <= config.MAX_MINING_ENERGY_RECOVERY_UPGRADE_LEVEL
255
+ or (
256
+ skill.next_level <= config.MAX_MINING_UPGRADE_LEVEL
257
+ or skill.skill_price <= config.MAX_MINING_UPGRADE_COSTS
258
+ )
259
+ ):
260
+ await self._upgrade_skill(skill)
261
+
262
+ def _is_enough_money_for_upgrade(self, skill: DbSkill) -> bool:
263
+ return (self.balance - skill.skill_price) >= config.MONEY_TO_SAVE
264
+
265
+ async def _upgrade_hero_skill(self, available_skill: list[DbSkill]) -> None:
266
+ for skill in sorted(
267
+ [skill for skill in available_skill if skill.weight],
268
+ key=lambda x: x.weight,
269
+ reverse=True,
270
+ ):
271
+ if skill.title in config.SKIP_TO_UPGRADE_SKILLS:
272
+ continue
273
+ # if skill.weight >= config.SKILL_WEIGHT or skill.skill_price <= config.MAX_SKILL_UPGRADE_COSTS:
274
+ if skill.weight >= config.SKILL_WEIGHT:
275
+ await self._upgrade_skill(skill)
276
+
277
+ async def _upgrade_skill(self, skill: DbSkill) -> None:
278
+ if self._is_enough_money_for_upgrade(skill):
279
+ try:
280
+ await self.skills_improve(json_body={"data": skill.key})
281
+ self.logger.info(
282
+ f"Skill: <blue>{skill.title}</blue> upgraded to level: <c>{skill.next_level}</c> "
283
+ f"Profit: <y>{num_prettier(skill.skill_profit)}</y> "
284
+ f"Costs: <blue>{num_prettier(skill.skill_price)}</blue> "
285
+ f"Money stay: <y>{num_prettier(self.balance)}</y> "
286
+ f"Skill weight <magenta>{skill.weight:.5f}</magenta>"
287
+ )
288
+ await self.sleeper()
289
+ except ValueError:
290
+ self.logger.exception(f"Failed to upgrade skill: {skill}")
291
+ raise
292
+
293
+ def _get_available_skills(self) -> Generator[DbSkill, None, None]:
294
+ for skill in DbSkills(**self.dbs).dbSkills:
295
+ self._calkulate_skill_requirements(skill)
296
+ if self._is_available_to_upgrade_skills(skill):
297
+ yield skill
298
+
299
+ def _calkulate_skill_requirements(self, skill: DbSkill) -> None:
300
+ skill.next_level = (
301
+ self.data_after.skills[skill.key]["level"] + 1 if self.data_after.skills.get(skill.key) else 1
302
+ )
303
+ skill.skill_profit = skill.calculate_profit(skill.next_level)
304
+ skill.skill_price = skill.price_for_level(skill.next_level)
305
+ skill.weight = skill.skill_profit / skill.skill_price
306
+ skill.progress_time = skill.get_skill_time(self.data_after)
307
+
308
+ def _is_available_to_upgrade_skills(self, skill: DbSkill) -> bool:
309
+ # check the current skill is still in the process of improvement
310
+ if skill.progress_time and skill.progress_time.timestamp() + 60 > datetime.now(UTC).timestamp():
311
+ return False
312
+ if skill.next_level > skill.maxLevel:
313
+ return False
314
+ skill_requirements = skill.get_level_by_skill_level(skill.next_level)
315
+ if not skill_requirements:
316
+ return True
317
+ return (
318
+ len(self.data_after.friends) >= skill_requirements.requiredFriends
319
+ and self.user_profile.level >= skill_requirements.requiredHeroLevel
320
+ and self._is_can_learn_skill(skill_requirements)
321
+ )
322
+
323
+ def _is_can_learn_skill(self, level: SkillLevel) -> bool:
324
+ if not level.requiredSkills:
325
+ return True
326
+ for skill, level in level.requiredSkills.items():
327
+ if skill not in self.data_after.skills:
328
+ return False
329
+ if self.data_after.skills[skill]["level"] >= level:
330
+ return True
331
+ return False
332
+
333
+ async def login_to_app(self, proxy: str | None) -> bool:
334
+ if self.authorized:
335
+ return True
336
+ tg_web_data = await self.get_tg_web_data(proxy=proxy)
337
+ self.http_client.headers["Api-Key"] = tg_web_data.hash
338
+ if await self.login(json_body=tg_web_data.request_data):
339
+ self.authorized = True
340
+ return True
341
+ return False
342
+
343
+ async def run(self, proxy: str | None) -> None:
344
+ proxy = proxy or self.additional_data.proxy
345
+ if proxy and "socks" in proxy:
346
+ proxy_conn = SocksProxyConnector.from_url(proxy)
347
+ elif proxy:
348
+ proxy_conn = ProxyConnector.from_url(proxy)
349
+ else:
350
+ proxy_conn = None
351
+
352
+ async with aiohttp.ClientSession(
353
+ headers=headers,
354
+ connector=proxy_conn,
355
+ timeout=aiohttp.ClientTimeout(total=60),
356
+ ) as http_client:
357
+ self.http_client = http_client
358
+ if proxy:
359
+ await self.check_proxy(proxy=proxy)
360
+
361
+ while True:
362
+ if self.errors >= config.ERRORS_BEFORE_STOP:
363
+ self.logger.error("Bot stopped (too many errors)")
364
+ break
365
+ try:
366
+ if await self.login_to_app(proxy):
367
+ # if not self.settings_was_set:
368
+ # await self.sent_eng_settings()
369
+ data = await self.get_profile_full()
370
+ self.dbs = data["dbData"]
371
+ await self.get_box_rewards()
372
+
373
+ self.user_profile: ProfileData = ProfileData(**data)
374
+ if self.user_profile.offline_bonus > 0:
375
+ await self.get_offline_bonus()
376
+
377
+ profile = await self.syn_hero_balance()
378
+
379
+ config.MONEY_TO_SAVE = self.bet_calculator.max_bet()
380
+ self.logger.info(f"Max bet for funds saved: <y>{num_prettier(config.MONEY_TO_SAVE)}</y>")
381
+
382
+ self.data_after = await self.user_data_after()
383
+
384
+ await self.claim_daily_reward()
385
+
386
+ await self.execute_and_claim_daily_quest()
387
+
388
+ await self.syn_hero_balance()
389
+
390
+ await self.get_friend_reward()
391
+
392
+ if config.TAPS_ENABLED and profile.energy and time.monotonic() > self.temporary_stop_taps_time:
393
+ await self.perform_taps(profile)
394
+
395
+ await self.set_funds()
396
+ await self.solve_quiz_and_rebus()
397
+
398
+ await self.claim_all_executed_quest()
399
+
400
+ await self.syn_hero_balance()
401
+
402
+ await self.upgrade_hero()
403
+
404
+ if config.PVP_ENABLED:
405
+ await self.starting_pvp()
406
+ await self.syn_hero_balance()
407
+ sleep_time = random.randint(*config.BOT_SLEEP_TIME)
408
+ self.logger.info(f"Sleep minutes {sleep_time // 60} minutes")
409
+ await asyncio.sleep(sleep_time)
410
+
411
+ except RuntimeError as error:
412
+ raise error from error
413
+ except Exception:
414
+ self.errors += 1
415
+ self.authorized = False
416
+ self.logger.exception("Unknown error")
417
+ await self.sleeper(additional_delay=self.errors * 8)
418
+ else:
419
+ self.errors = 0
420
+ self.authorized = False
421
+
422
+
423
+ async def run_bot(tg_client: Client, proxy: str | None, additional_data: dict) -> None:
424
+ try:
425
+ await CryptoBot(tg_client=tg_client, additional_data=additional_data).run(proxy=proxy)
426
+ except RuntimeError:
427
+ log.bind(session_name=tg_client.name).exception("Session error")
bot/core/errors.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ class TapsError(Exception):
2
+ def __init__(self, message: str) -> None:
3
+ self.message = message
bot/core/models.py ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime
2
+ from typing import Any
3
+
4
+ from pydantic import AliasPath, BaseModel, Field, field_validator
5
+ from pytz import UTC
6
+
7
+ from bot.core.api_js_helpers.upgrader import Calculator
8
+
9
+
10
+ class SkillLevel(BaseModel):
11
+ level: int
12
+ title: str
13
+ requiredSkills: dict | list
14
+ requiredHeroLevel: int
15
+ requiredFriends: int
16
+ desc: str
17
+
18
+
19
+ class DbSkill(BaseModel):
20
+ key: str
21
+ title: str
22
+ category: str
23
+ subCategory: str
24
+ priceBasic: int
25
+ priceFormula: str
26
+ priceFormulaK: int
27
+ profitBasic: int
28
+ profitFormula: str
29
+ profitFormulaK: int
30
+ maxLevel: int
31
+ timeBasic: str
32
+ timeFormula: str
33
+ timeFormulaK: str
34
+ desc: str
35
+ special: str
36
+ levels: list[SkillLevel]
37
+ next_level: int = 1
38
+ skill_profit: int = 0
39
+ skill_price: int = 0
40
+ weight: int = 0
41
+ progress_time: datetime | None = None
42
+
43
+ def __init__(self, /, **data: Any) -> None:
44
+ super().__init__(**data)
45
+ self._calculator = Calculator()
46
+
47
+ def get_level_by_skill_level(self, level: int) -> SkillLevel | None:
48
+ if not self.levels or self.levels[0].level > level:
49
+ return None
50
+
51
+ for index, skill_level in enumerate(self.levels):
52
+ if skill_level.level <= level:
53
+ if index + 1 == len(self.levels):
54
+ return skill_level
55
+ if self.levels[index + 1].level > level:
56
+ return skill_level
57
+
58
+ return None
59
+
60
+ def calculate_profit(self, level: int) -> int:
61
+ return self._calculator.get_profit(self, level)
62
+
63
+ def price_for_level(self, level: int) -> int:
64
+ return self._calculator.get_price(self, level)
65
+
66
+ def get_skill_time(self, data_after: "UserDataAfter") -> None | datetime:
67
+ if finish_time := data_after.skills.get(self.key, {}).get("finishUpgradeDate"):
68
+ return datetime.strptime(finish_time, "%Y-%m-%d %H:%M:%S").replace(tzinfo=UTC)
69
+ return None
70
+
71
+
72
+ class DbSkills(BaseModel):
73
+ dbSkills: list[DbSkill]
74
+
75
+
76
+ class ProfileData(BaseModel):
77
+ user_id: int = Field(validation_alias=AliasPath("profile", "id"))
78
+ money: int = Field(validation_alias=AliasPath("hero", "money"))
79
+ level: int = Field(validation_alias=AliasPath("hero", "level"))
80
+ money_per_hour: int = Field(validation_alias=AliasPath("hero", "moneyPerHour"))
81
+ offline_bonus: int = Field(validation_alias=AliasPath("hero", "offlineBonus"))
82
+
83
+
84
+ class UserDataAfter(BaseModel):
85
+ daily_rewards: dict = Field(validation_alias=AliasPath("dailyRewards"))
86
+ quests: list = Field(validation_alias=AliasPath("quests"))
87
+ friends: list = Field(validation_alias=AliasPath("friends"))
88
+ skills: dict | list = Field(
89
+ description="all user learned skills",
90
+ examples=[
91
+ {"desks": {"level": 6, "lastUpgradeDate": "2024-07-30 19:20:32", "finishUpgradeDate": None}},
92
+ {
93
+ "empathy": {
94
+ "level": 6,
95
+ "lastUpgradeDate": "2024-07-30 19:21:36",
96
+ "finishUpgradeDate": "2024-07-30 19:22:13",
97
+ }
98
+ },
99
+ ],
100
+ )
101
+
102
+ @field_validator("skills")
103
+ @classmethod
104
+ def check_skills(cls, v: Any) -> dict:
105
+ return v or {}
106
+
107
+
108
+ class Profile(BaseModel):
109
+ money_per_tap: int = Field(validation_alias=AliasPath("hero", "earns", "task", "moneyPerTap"))
110
+ limit: int = Field(validation_alias=AliasPath("hero", "earns", "task", "limit"))
111
+ energy: int = Field(validation_alias=AliasPath("hero", "earns", "task", "energy"))
112
+ energy_recovery: int = Field(validation_alias=AliasPath("hero", "earns", "task", "recoveryPerSecond"))
113
+
114
+ money: int = Field(validation_alias=AliasPath("hero", "money"))
115
+ level: int = Field(validation_alias=AliasPath("hero", "level"))
116
+ money_per_hour: int = Field(validation_alias=AliasPath("hero", "moneyPerHour"))
117
+
118
+
119
+ class Fight(BaseModel):
120
+ league: str
121
+ moneyProfit: int
122
+ player1: int
123
+ moneyContract: int
124
+ player1Strategy: str
125
+ player1Level: int
126
+ player1Rewarded: bool
127
+ player2: int
128
+ player2Strategy: str
129
+ player2Rewarded: bool
130
+ winner: int
131
+
132
+
133
+ class PvpData(BaseModel):
134
+ opponent: dict | None
135
+ fight: Fight | None
136
+
137
+
138
+ class FundHelper(BaseModel):
139
+ funds: set = Field(default_factory=set)
140
+ youtube: dict
141
+
142
+
143
+ class Skills(BaseModel):
144
+ skills: dict
145
+
146
+
147
+ if __name__ == "__main__":
148
+ data = {
149
+ "hero": {
150
+ "id": 1092379081,
151
+ "level": 12,
152
+ "exp": 207156950,
153
+ "money": 8154952,
154
+ "moneyUpdateDate": "2024-08-05 07:02:28",
155
+ "lastOfflineBonusDate": "2024-08-05 07:02:28",
156
+ "moneyPerHour": 7943050,
157
+ "energyUpdateDate": "2024-08-05 07:02:28",
158
+ "tax": 20,
159
+ "pvpMatch": 1143,
160
+ "pvpWin": 646,
161
+ "pvpLose": 497,
162
+ "pvpMatchesDaily": 123,
163
+ "pvpMatchesDailyDay": "2024-08-04",
164
+ "earns": {
165
+ "task": {"moneyPerTap": 21, "limit": 9500, "energy": 9500, "recoveryPerSecond": 14},
166
+ "sell": {"moneyPerTap": 20, "limit": 6600, "energy": 6600, "recoveryPerSecond": 14},
167
+ },
168
+ "dailyRewardLastDate": "2024-08-04 11:15:56",
169
+ "dailyRewardLastIndex": 7,
170
+ "onboarding": [
171
+ "9040",
172
+ "41",
173
+ "30",
174
+ "40",
175
+ "9000",
176
+ "90",
177
+ "70",
178
+ "10720",
179
+ "9020",
180
+ "10015",
181
+ "9010",
182
+ "80",
183
+ "50",
184
+ "10700",
185
+ "60",
186
+ "9030",
187
+ "20",
188
+ "51",
189
+ "1",
190
+ ],
191
+ "updateDate": "2024-07-19 16:39:56.91573",
192
+ "userId": 1092379081,
193
+ },
194
+ "fight": {
195
+ "id": "08999015-6835-44ed-b00e-3ac529b62285",
196
+ "league": "bronze",
197
+ "moneyContract": 6600,
198
+ "moneyProfit": None,
199
+ "searchTime": None,
200
+ "player1": 1092379081,
201
+ "player1Strategy": "aggressive",
202
+ "player1Level": 12,
203
+ "player1Rewarded": False,
204
+ "player2": None,
205
+ "player2Strategy": None,
206
+ "player2Rewarded": False,
207
+ "winner": None,
208
+ "draw": [],
209
+ "updateDate": None,
210
+ "creationDate": "2024-08-05 07:02:35",
211
+ },
212
+ "opponent": None,
213
+ }
214
+ PvpData(**data)
215
+
216
+
217
+ class SessionData(BaseModel):
218
+ user_agent: str = Field(validation_alias="User-Agent")
219
+ proxy: str | None = None
bot/core/utils.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from functools import lru_cache
3
+ from pathlib import Path
4
+
5
+
6
+ @lru_cache
7
+ def load_codes_from_files() -> dict:
8
+ with Path("youtube.json").open("r", encoding="utf-8") as file:
9
+ return json.load(file)
10
+
11
+
12
+ def num_prettier(num: int) -> str:
13
+ number = abs(num)
14
+ if number >= (comparer := 1e12):
15
+ prettier_num = f"{number / comparer:.1f}T"
16
+ elif number >= (comparer := 1e9):
17
+ prettier_num = f"{number / comparer:.1f}B"
18
+ elif number >= (comparer := 1e6):
19
+ prettier_num = f"{number / comparer:.1f}M"
20
+ elif number >= (comparer := 1e3):
21
+ prettier_num = f"{number / comparer:.1f}k"
22
+ else:
23
+ prettier_num = str(number)
24
+ return f"-{prettier_num}" if num < 0 else prettier_num
bot/helper/__pycache__/utils.cpython-310.pyc ADDED
Binary file (3.03 kB). View file
 
bot/helper/utils.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import hashlib
3
+ import json
4
+ import random
5
+ from collections.abc import Callable
6
+ from functools import wraps
7
+ from time import time
8
+
9
+ import aiohttp
10
+ from loguru import logger
11
+
12
+
13
+ def error_handler(delay=3):
14
+ def decorator(func):
15
+ @wraps(func)
16
+ async def wrapper(*args, **kwargs):
17
+ try:
18
+ return await func(*args, **kwargs)
19
+ except Exception as error:
20
+ logger.error(f"Error in {func.__name__}: {error}")
21
+ await asyncio.sleep(random.randint(delay, delay * 2))
22
+ raise
23
+
24
+ return wrapper
25
+
26
+ return decorator
27
+
28
+
29
+ def handle_request(
30
+ endpoint: str,
31
+ full_url: bool = False,
32
+ method: str = "POST",
33
+ raise_for_status: bool = True,
34
+ json_body: dict | None = None,
35
+ ):
36
+ def decorator(func: Callable) -> Callable:
37
+ @wraps(func)
38
+ async def wrapper(self, *args, **kwargs):
39
+ url = endpoint if full_url else self.api_url + endpoint
40
+ if method.upper() == "POST":
41
+ _json_body = kwargs.get("json_body") or json_body or {}
42
+ set_sign_headers(http_client=self.http_client, data=_json_body)
43
+ response = await self.http_client.post(url, json=_json_body)
44
+ elif method.upper() == "GET":
45
+ response = await self.http_client.get(url)
46
+ else:
47
+ msg = "Unsupported HTTP method"
48
+ raise ValueError(msg)
49
+ if raise_for_status:
50
+ response.raise_for_status()
51
+
52
+ content_type = response.headers.get("Content-Type", "")
53
+ if "application/json" in content_type:
54
+ response_data = await response.json()
55
+ elif "text/" in content_type:
56
+ response_data = await response.text()
57
+ else:
58
+ response_data = await response.read()
59
+ return await func(self, response_json=response_data, **kwargs)
60
+
61
+ return wrapper
62
+
63
+ return decorator
64
+
65
+
66
+ def set_sign_headers(http_client: aiohttp.ClientSession, data: dict) -> None:
67
+ time_string = str(int(time()))
68
+ json_string = json.dumps(data)
69
+ hash_object = hashlib.md5()
70
+ hash_object.update(f"{time_string}_{json_string}".encode())
71
+ hash_string = hash_object.hexdigest()
72
+ http_client.headers["Api-Time"] = time_string
73
+ http_client.headers["Api-Hash"] = hash_string
74
+
75
+
76
+ def error_handler(delay=3):
77
+ def decorator(func):
78
+ @wraps(func)
79
+ async def wrapper(self, *args, **kwargs):
80
+ try:
81
+ return await func(self, *args, **kwargs)
82
+ except Exception as error:
83
+ self.logger.error(f"Error in {func.__name__}: {error}")
84
+ await asyncio.sleep(random.randint(delay, delay * 2))
85
+ raise
86
+
87
+ return wrapper
88
+
89
+ return decorator
bot/launcher.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import random
3
+ from argparse import ArgumentParser
4
+ from itertools import cycle
5
+ from pathlib import Path
6
+ from typing import NamedTuple
7
+
8
+ from better_proxy import Proxy
9
+ from pyrogram import Client
10
+
11
+ from bot.config.logger import log
12
+ from bot.config.settings import config, logo
13
+ from bot.core.bot import run_bot
14
+ from bot.utils import get_session_profiles
15
+
16
+ start_text = """
17
+ Select an action:
18
+ 1. Create session
19
+ 2. Run bot
20
+ """
21
+
22
+
23
+ class SessionData(NamedTuple):
24
+ tg_client: Client
25
+ session_data: dict
26
+
27
+
28
+ def get_session_names() -> list[str]:
29
+ return [file.stem for file in sorted(Path("sessions").glob("*.session"))]
30
+
31
+
32
+ async def register_sessions() -> None:
33
+ session_name = input("\nEnter the session name (press Enter to exit): ")
34
+ if not session_name:
35
+ return
36
+
37
+ sessions_path = Path("sessions")
38
+ if not sessions_path.exists():
39
+ sessions_path.mkdir()
40
+
41
+ session = Client(
42
+ name=session_name,
43
+ api_id=config.API_ID,
44
+ api_hash=config.API_HASH,
45
+ workdir="sessions/",
46
+ )
47
+
48
+ async with session:
49
+ user_data = await session.get_me()
50
+ log.success(
51
+ f"Session added successfully: {user_data.username or user_data.id} | "
52
+ f"{user_data.first_name or ''} {user_data.last_name or ''}"
53
+ )
54
+
55
+
56
+ def get_proxies() -> [str | None]:
57
+ if config.USE_PROXY_FROM_FILE:
58
+ with Path("proxies.txt").open(encoding="utf-8") as file:
59
+ return [Proxy.from_str(proxy=row.strip()).as_url for row in file if row.strip()]
60
+ return None
61
+
62
+
63
+ async def get_tg_clients() -> list[SessionData]:
64
+ session_names = get_session_names()
65
+
66
+ if not session_names:
67
+ msg = "Not found session files"
68
+ raise FileNotFoundError(msg)
69
+ session_profiles = get_session_profiles(session_names)
70
+ return [
71
+ SessionData(
72
+ tg_client=Client(
73
+ name=session_name,
74
+ api_id=config.API_ID,
75
+ api_hash=config.API_HASH,
76
+ workdir="sessions/",
77
+ ),
78
+ session_data=session_profiles[session_name],
79
+ )
80
+ for session_name in session_names
81
+ ]
82
+
83
+
84
+ async def run_bot_with_delay(tg_client: Client, proxy: str | None, additional_data: dict, session_index: int) -> None:
85
+ delay = session_index * config.SESSION_AC_DELAY + random.randint(*config.SLEEP_BETWEEN_START)
86
+ log.bind(session_name=tg_client.name).info(f"Wait {delay} seconds before start")
87
+ await asyncio.sleep(delay)
88
+ await run_bot(tg_client=tg_client, proxy=proxy, additional_data=additional_data)
89
+
90
+
91
+ async def run_clients(session_data: list[SessionData]) -> None:
92
+ proxies = get_proxies() or [None]
93
+ if config.ADD_LOCAL_MACHINE_AS_IP:
94
+ proxies.append(None)
95
+ proxy_cycle = cycle(proxies)
96
+ await asyncio.gather(
97
+ *[
98
+ run_bot_with_delay(
99
+ tg_client=s_data.tg_client,
100
+ proxy=next(proxy_cycle),
101
+ additional_data=s_data.session_data,
102
+ session_index=index,
103
+ )
104
+ for index, s_data in enumerate(session_data)
105
+ ]
106
+ )
107
+
108
+
109
+ async def start() -> None:
110
+ print(logo)
111
+ parser = ArgumentParser()
112
+ parser.add_argument("-a", "--action", type=int, choices=[1, 2], help="Action to perform (1 or 2)")
113
+ log.info(f"Detected {len(get_session_names())} sessions | {len(proxy) if (proxy := get_proxies()) else 0} proxies")
114
+ action = parser.parse_args().action
115
+
116
+ if not action:
117
+ print(start_text)
118
+ while True:
119
+ action = input("> ").strip()
120
+ if action.isdigit() and action in ["1", "2"]:
121
+ action = int(action)
122
+ break
123
+ log.warning("Action must be a number (1 or 2)")
124
+
125
+ if action == 1:
126
+ await register_sessions()
127
+ elif action == 2:
128
+ session_data = await get_tg_clients()
129
+ await run_clients(session_data=session_data)
bot/utils.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from pathlib import Path
3
+
4
+ from fake_useragent import UserAgent
5
+
6
+
7
+ def read_session_profiles(sessions: list[str]) -> dict | None:
8
+ file_path = Path("session_profile.json")
9
+ if not file_path.exists():
10
+ return None
11
+
12
+ try:
13
+ with file_path.open(encoding="utf-8") as file:
14
+ data = json.load(file)
15
+ return data if all(session in data and len(data[session]) >= 2 for session in sessions) else None
16
+ except (OSError, json.JSONDecodeError):
17
+ return None
18
+
19
+
20
+ def get_session_profiles(sessions: list[str]) -> dict:
21
+ session_profiles = read_session_profiles(sessions)
22
+ if session_profiles is None:
23
+ session_profiles = {}
24
+ ua_generator = UserAgent(browsers=["safari"], os=["ios"], platforms=["mobile", "tablet"])
25
+
26
+ for session in sessions:
27
+ inner = session_profiles.setdefault(session, [])
28
+ inner.append({"User-Agent": ua_generator.random})
29
+ inner.append({"proxy": None})
30
+
31
+ with Path("session_profile.json").open("w", encoding="utf-8") as file:
32
+ json.dump(session_profiles, file, ensure_ascii=False, indent=4)
33
+
34
+ return session_profiles
data.json ADDED
File without changes
docker-compose.yml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3'
2
+ services:
3
+ bot:
4
+ container_name: 'MuskEmpireBot'
5
+ stop_signal: SIGINT
6
+ build:
7
+ context: .
8
+ working_dir: /app
9
+ volumes:
10
+ - .:/app
11
+ entrypoint: "python3 main.py"
12
+ command: ["-a", "2"]
13
+ restart: unless-stopped
14
+ env_file: .env
main.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+
3
+ from bot import launcher
4
+ from bot.config.logger import log
5
+
6
+
7
+ async def main() -> None:
8
+ await launcher.start()
9
+
10
+
11
+ if __name__ == "__main__":
12
+ try:
13
+ asyncio.run(main())
14
+ except KeyboardInterrupt:
15
+ log.info("Bot stopped by user")
proxies.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
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
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ pydantic-settings==2.3.4
2
+ aiohttp==3.10.2
3
+ better-proxy==1.2.0
4
+ loguru==0.7.2
5
+ Pyrogram==2.0.106
6
+ TgCrypto==1.2.5
7
+ aiocache==0.12.2
8
+ pytz==2024.1
9
+ fake-useragent==1.5.1
10
+ aiohttp-socks==0.9.0
11
+ aiohttp-proxy==0.1.2
sessions/yasir.session ADDED
Binary file (28.7 kB). View file
 
youtube.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "From Queens to billionaire: the real story of Donald Trump. Controversy, power, wealth, and success": 2007,
3
+ "How сloud storage works? Episode 28": 75928,
4
+ "How biomimicry is changing the World. Episode 27": 35527,
5
+ "The Bezos phenomenon. The billionaire's path from the garage to space.": 0,
6
+ "How will AI change the world? Episode 29": 34329,
7
+ "What does a CEO really do? Episode 32": 12932,
8
+ "Marketing magic: turning Ordinary into Extraordinary. Episode 35": 15235,
9
+ "The secrets of multicurrency transfers. Episode 38": 22938,
10
+ "Who’s behind your crypto transfers? Episode 39": 44139,
11
+ "Check out the guide on how to connect your wallet and complete a test transaction. Once you've reviewed it, connect your wallet to participate in the Airdrop!": 3,
12
+ "How Sam Altman Is changing the AI world and what’s behind his popularity?": 2023,
13
+ "Bioengineering: medical miracles of tomorrow. Episode 37": 72837,
14
+ "Turning Creativity Into Cash: Intellectual Property Valuation. Episode 40": 65340,
15
+ "Corporate Anthropology: the art of Improving team work. Episode 41": 10941,
16
+ "The truth about Inflation. Episode 42": 83242,
17
+ "Mining secrets: How digital currency Is really made? Episode 43": 87843,
18
+ "Broker secrets: how they make your money work? Episode 44": 62944,
19
+ "From dorm room to tech Icon: Zuckerberg's story!": 2011,
20
+ "Why personal branding is the key to success? Episode 47": 24147,
21
+ "The power of strategic thinking: Think long-term, win big! Episode 50": 89350,
22
+ "Steve Jobs: Innovator, leader, enigma. The truth about the man behind Apple!": 1989,
23
+ "The Hidden Power and Harm of Monopolies. Episode 51": 37251,
24
+ "Reshoring: why Global businesses are coming home? Episode 49": 52649
25
+ }