interlink-bot / bot.py
imseldrith's picture
Upload 3 files
2c59b39 verified
from aiohttp import (
ClientResponseError,
ClientSession,
ClientTimeout,
BasicAuth
)
from aiohttp_socks import ProxyConnector
from base64 import urlsafe_b64decode
from datetime import datetime
from colorama import *
import asyncio, time, json, pytz, re, os
wib = pytz.timezone('Asia/Jakarta')
class Interlink:
def __init__(self) -> None:
self.HEADERS = {
"Accept-Encoding": "*/*",
"User-Agent": "okhttp/4.12.0",
"Accept-Encoding": "gzip"
}
self.BASE_API = "https://prod.interlinklabs.ai/api/v1"
self.proxies = []
self.proxy_index = 0
self.account_proxies = {}
self.access_tokens = {}
def clear_terminal(self):
os.system('cls' if os.name == 'nt' else 'clear')
def log(self, message):
print(
f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}"
f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}{message}",
flush=True
)
def welcome(self):
print(
f"""
{Fore.GREEN + Style.BRIGHT}Auto Claim {Fore.BLUE + Style.BRIGHT}Interlink - BOT
"""
f"""
{Fore.GREEN + Style.BRIGHT}Rey? {Fore.YELLOW + Style.BRIGHT}<INI WATERMARK>
"""
)
def format_seconds(self, seconds):
hours, remainder = divmod(seconds, 3600)
minutes, seconds = divmod(remainder, 60)
return f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}"
def load_accounts(self):
filename = "tokens.json"
env_tokens = os.getenv("TOKENS_JSON")
if env_tokens:
try:
data = json.loads(env_tokens)
if isinstance(data, list):
self.log(
f"{Fore.GREEN + Style.BRIGHT}Loaded accounts from environment variable TOKENS_JSON.{Style.RESET_ALL}"
)
return data
self.log(
f"{Fore.RED + Style.BRIGHT}TOKENS_JSON is not a JSON array. No accounts loaded.{Style.RESET_ALL}"
)
return []
except json.JSONDecodeError as exc:
self.log(
f"{Fore.RED + Style.BRIGHT}Failed to parse TOKENS_JSON: {exc}.{Style.RESET_ALL}"
)
return []
try:
if not os.path.exists(filename):
self.log(f"{Fore.RED}File {filename} Not Found.{Style.RESET_ALL}")
return []
with open(filename, 'r') as file:
data = json.load(file)
if isinstance(data, list):
return data
self.log(
f"{Fore.RED + Style.BRIGHT}{filename} does not contain a JSON array. No accounts loaded.{Style.RESET_ALL}"
)
return []
except json.JSONDecodeError as exc:
self.log(
f"{Fore.RED + Style.BRIGHT}Failed to parse {filename}: {exc}.{Style.RESET_ALL}"
)
return []
async def load_proxies(self):
filename = "proxy.txt"
try:
env_proxies = os.getenv("PROXIES")
if env_proxies:
self.proxies = self.parse_env_list(env_proxies)
source = "environment variable PROXIES"
else:
if not os.path.exists(filename):
self.log(f"{Fore.RED + Style.BRIGHT}File {filename} Not Found.{Style.RESET_ALL}")
return
with open(filename, 'r') as f:
self.proxies = [line.strip() for line in f.read().splitlines() if line.strip()]
source = filename
if not self.proxies:
self.log(f"{Fore.RED + Style.BRIGHT}No Proxies Found.{Style.RESET_ALL}")
return
self.log(
f"{Fore.GREEN + Style.BRIGHT}Proxies Total : {Style.RESET_ALL}"
f"{Fore.WHITE + Style.BRIGHT}{len(self.proxies)}{Style.RESET_ALL}"
f"{Fore.GREEN + Style.BRIGHT} (from {source}){Style.RESET_ALL}"
)
except Exception as e:
self.log(f"{Fore.RED + Style.BRIGHT}Failed To Load Proxies: {e}{Style.RESET_ALL}")
self.proxies = []
def check_proxy_schemes(self, proxies):
schemes = ["http://", "https://", "socks4://", "socks5://"]
if any(proxies.startswith(scheme) for scheme in schemes):
return proxies
return f"http://{proxies}"
def get_next_proxy_for_account(self, account):
if account not in self.account_proxies:
if not self.proxies:
return None
proxy = self.check_proxy_schemes(self.proxies[self.proxy_index])
self.account_proxies[account] = proxy
self.proxy_index = (self.proxy_index + 1) % len(self.proxies)
return self.account_proxies[account]
def rotate_proxy_for_account(self, account):
if not self.proxies:
return None
proxy = self.check_proxy_schemes(self.proxies[self.proxy_index])
self.account_proxies[account] = proxy
self.proxy_index = (self.proxy_index + 1) % len(self.proxies)
return proxy
def build_proxy_config(self, proxy=None):
if not proxy:
return None, None, None
if proxy.startswith("socks"):
connector = ProxyConnector.from_url(proxy)
return connector, None, None
elif proxy.startswith("http"):
match = re.match(r"http://(.*?):(.*?)@(.*)", proxy)
if match:
username, password, host_port = match.groups()
clean_url = f"http://{host_port}"
auth = BasicAuth(username, password)
return None, clean_url, auth
else:
return None, proxy, None
raise Exception("Unsupported Proxy Type.")
def decode_token(self, token: str):
try:
header, payload, signature = token.split(".")
decoded_payload = urlsafe_b64decode(payload + "==").decode("utf-8")
parsed_payload = json.loads(decoded_payload)
exp_time = parsed_payload["exp"]
return exp_time
except Exception as e:
return None
def mask_account(self, account):
if "@" in account:
local, domain = account.split('@', 1)
mask_account = local[:3] + '*' * 3 + local[-3:]
return f"{mask_account}@{domain}"
def parse_env_list(self, raw: str):
items = []
if not raw:
return items
normalized = raw.replace("\r\n", "\n")
for line in normalized.split("\n"):
for part in line.split(","):
candidate = part.strip()
if candidate:
items.append(candidate)
return items
def get_env_bool(self, name: str, default=None):
value = os.getenv(name)
if value is None:
return default
value = value.strip().lower()
if value in {"1", "true", "yes", "y"}:
return True
if value in {"0", "false", "no", "n"}:
return False
return default
def print_question(self):
while True:
try:
print(f"{Fore.WHITE + Style.BRIGHT}1. Run With Proxy{Style.RESET_ALL}")
print(f"{Fore.WHITE + Style.BRIGHT}2. Run Without Proxy{Style.RESET_ALL}")
proxy_choice = int(input(f"{Fore.BLUE + Style.BRIGHT}Choose [1/2] -> {Style.RESET_ALL}").strip())
if proxy_choice in [1, 2]:
proxy_type = (
"With" if proxy_choice == 1 else
"Without"
)
print(f"{Fore.GREEN + Style.BRIGHT}Run {proxy_type} Proxy Selected.{Style.RESET_ALL}")
break
else:
print(f"{Fore.RED + Style.BRIGHT}Please enter either 1 or 2.{Style.RESET_ALL}")
except ValueError:
print(f"{Fore.RED + Style.BRIGHT}Invalid input. Enter a number (1 or 2).{Style.RESET_ALL}")
rotate_proxy = False
if proxy_choice == 1:
while True:
rotate_proxy = input(f"{Fore.BLUE + Style.BRIGHT}Rotate Invalid Proxy? [y/n] -> {Style.RESET_ALL}").strip()
if rotate_proxy in ["y", "n"]:
rotate_proxy = rotate_proxy == "y"
break
else:
print(f"{Fore.RED + Style.BRIGHT}Invalid input. Enter 'y' or 'n'.{Style.RESET_ALL}")
return proxy_choice, rotate_proxy
async def check_connection(self, proxy_url=None):
connector, proxy, proxy_auth = self.build_proxy_config(proxy_url)
try:
async with ClientSession(connector=connector, timeout=ClientTimeout(total=10)) as session:
async with session.get(url="https://api.ipify.org?format=json", proxy=proxy, proxy_auth=proxy_auth) as response:
response.raise_for_status()
return True
except (Exception, ClientResponseError) as e:
self.log(
f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}"
f"{Fore.RED+Style.BRIGHT} Connection Not 200 OK {Style.RESET_ALL}"
f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}"
)
return None
async def token_balance(self, email: str, proxy_url=None, retries=5):
url = f"{self.BASE_API}/token/get-token"
headers = {
**self.HEADERS,
"Authorization": f"Bearer {self.access_tokens[email]}"
}
await asyncio.sleep(3)
for attempt in range(retries):
connector, proxy, proxy_auth = self.build_proxy_config(proxy_url)
try:
async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session:
async with session.get(url=url, headers=headers, proxy=proxy, proxy_auth=proxy_auth, ssl=False) as response:
response.raise_for_status()
return await response.json()
except (Exception, ClientResponseError) as e:
if attempt < retries - 1:
await asyncio.sleep(5)
continue
self.log(
f"{Fore.CYAN+Style.BRIGHT}Balance:{Style.RESET_ALL}"
f"{Fore.RED+Style.BRIGHT} GET Token Earned Failed {Style.RESET_ALL}"
f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}"
)
return None
async def claimable_check(self, email: str, proxy_url=None, retries=5):
url = f"{self.BASE_API}/token/check-is-claimable"
headers = {
**self.HEADERS,
"Authorization": f"Bearer {self.access_tokens[email]}"
}
await asyncio.sleep(3)
for attempt in range(retries):
connector, proxy, proxy_auth = self.build_proxy_config(proxy_url)
try:
async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session:
async with session.get(url=url, headers=headers, proxy=proxy, proxy_auth=proxy_auth, ssl=False) as response:
response.raise_for_status()
return await response.json()
except (Exception, ClientResponseError) as e:
if attempt < retries - 1:
await asyncio.sleep(5)
continue
self.log(
f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}"
f"{Fore.RED+Style.BRIGHT} GET Status Failed {Style.RESET_ALL}"
f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}"
)
return None
async def claim_airdrop(self, email: str, proxy_url=None, retries=1):
url = f"{self.BASE_API}/token/claim-airdrop"
headers = {
**self.HEADERS,
"Authorization": f"Bearer {self.access_tokens[email]}",
"Content-Length": "2",
"Content-Type": "application/json"
}
await asyncio.sleep(3)
for attempt in range(retries):
connector, proxy, proxy_auth = self.build_proxy_config(proxy_url)
try:
async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session:
async with session.post(url=url, headers=headers, json={}, proxy=proxy, proxy_auth=proxy_auth, ssl=False) as response:
response.raise_for_status()
return await response.json()
except (Exception, ClientResponseError) as e:
if attempt < retries - 1:
await asyncio.sleep(5)
continue
self.log(
f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}"
f"{Fore.RED+Style.BRIGHT} Not Claimed {Style.RESET_ALL}"
f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}"
)
return None
async def process_check_connection(self, email: str, use_proxy: bool, rotate_proxy: bool):
while True:
proxy = self.get_next_proxy_for_account(email) if use_proxy else None
self.log(
f"{Fore.CYAN+Style.BRIGHT}Proxy :{Style.RESET_ALL}"
f"{Fore.WHITE+Style.BRIGHT} {proxy if proxy else 'No Proxy'} {Style.RESET_ALL}"
)
is_valid = await self.check_connection(proxy)
if is_valid: return True
if rotate_proxy:
proxy = self.rotate_proxy_for_account(email)
await asyncio.sleep(1)
continue
return False
async def process_accounts(self, email: str, use_proxy: bool, rotate_proxy: bool):
is_valid = await self.process_check_connection(email, use_proxy, rotate_proxy)
if not is_valid: return
proxy = self.get_next_proxy_for_account(email) if use_proxy else None
balance = await self.token_balance(email, proxy)
if balance:
token_balance = balance.get("data", {}).get("interlinkTokenAmount", 0)
silver_balance = balance.get("data", {}).get("interlinkSilverTokenAmount", 0)
gold_balance = balance.get("data", {}).get("interlinkGoldTokenAmount", 0)
diamond_balance = balance.get("data", {}).get("interlinkDiamondTokenAmount", 0)
self.log(f"{Fore.CYAN+Style.BRIGHT}Balance:{Style.RESET_ALL}")
self.log(
f"{Fore.MAGENTA+Style.BRIGHT}{Style.RESET_ALL}"
f"{Fore.BLUE+Style.BRIGHT}Interlink:{Style.RESET_ALL}"
f"{Fore.WHITE+Style.BRIGHT} {token_balance} {Style.RESET_ALL}"
)
self.log(
f"{Fore.MAGENTA+Style.BRIGHT}{Style.RESET_ALL}"
f"{Fore.BLUE+Style.BRIGHT}Silver :{Style.RESET_ALL}"
f"{Fore.WHITE+Style.BRIGHT} {silver_balance} {Style.RESET_ALL}"
)
self.log(
f"{Fore.MAGENTA+Style.BRIGHT}{Style.RESET_ALL}"
f"{Fore.BLUE+Style.BRIGHT}Gold :{Style.RESET_ALL}"
f"{Fore.WHITE+Style.BRIGHT} {gold_balance} {Style.RESET_ALL}"
)
self.log(
f"{Fore.MAGENTA+Style.BRIGHT}{Style.RESET_ALL}"
f"{Fore.BLUE+Style.BRIGHT}Diamond :{Style.RESET_ALL}"
f"{Fore.WHITE+Style.BRIGHT} {diamond_balance} {Style.RESET_ALL}"
)
claimable = await self.claimable_check(email, proxy)
if claimable:
is_claimable = claimable.get("data", {}).get("isClaimable", False)
if is_claimable:
claim = await self.claim_airdrop(email, proxy)
if claim:
reward = claim.get("data") or "N/A"
self.log(
f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}"
f"{Fore.GREEN+Style.BRIGHT} Claimed Successfully {Style.RESET_ALL}"
f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
f"{Fore.CYAN+Style.BRIGHT} Reward: {Style.RESET_ALL}"
f"{Fore.WHITE+Style.BRIGHT}{reward}{Style.RESET_ALL}"
)
else:
next_frame_ts = claimable.get("data", {}).get("nextFrame", 0) / 1000
next_frame_wib = datetime.fromtimestamp(next_frame_ts).astimezone(wib).strftime('%x %X %Z')
self.log(
f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}"
f"{Fore.YELLOW+Style.BRIGHT} Already Claimed {Style.RESET_ALL}"
f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
f"{Fore.CYAN+Style.BRIGHT} Next Claim at: {Style.RESET_ALL}"
f"{Fore.WHITE+Style.BRIGHT}{next_frame_wib}{Style.RESET_ALL}"
)
async def main(self):
try:
accounts = self.load_accounts()
if not accounts:
self.log(f"{Fore.RED}No Accounts Loaded.{Style.RESET_ALL}")
return
env_use_proxy = self.get_env_bool("USE_PROXY")
env_rotate_proxy = self.get_env_bool("ROTATE_PROXY")
if env_use_proxy is None:
proxy_choice, rotate_proxy = self.print_question()
use_proxy = proxy_choice == 1
else:
use_proxy = bool(env_use_proxy)
rotate_proxy = use_proxy and (
env_rotate_proxy if env_rotate_proxy is not None else True
)
mode_text = "With Proxy" if use_proxy else "Without Proxy"
source_text = "environment variables"
self.log(
f"{Fore.GREEN + Style.BRIGHT}Run {mode_text} Selected via {source_text}.{Style.RESET_ALL}"
)
if not use_proxy:
rotate_proxy = False
elif rotate_proxy:
self.log(
f"{Fore.GREEN + Style.BRIGHT}Invalid proxy auto-rotation enabled.{Style.RESET_ALL}"
)
else:
self.log(
f"{Fore.YELLOW + Style.BRIGHT}Invalid proxy auto-rotation disabled.{Style.RESET_ALL}"
)
while True:
self.clear_terminal()
self.welcome()
self.log(
f"{Fore.GREEN + Style.BRIGHT}Account's Total: {Style.RESET_ALL}"
f"{Fore.WHITE + Style.BRIGHT}{len(accounts)}{Style.RESET_ALL}"
)
if use_proxy:
await self.load_proxies()
separator = "=" * 27
for idx, account in enumerate(accounts, start=1):
if account:
email = account["email"]
token = account["token"]
self.log(
f"{Fore.CYAN + Style.BRIGHT}{separator}[{Style.RESET_ALL}"
f"{Fore.WHITE + Style.BRIGHT} {idx} {Style.RESET_ALL}"
f"{Fore.CYAN + Style.BRIGHT}Of{Style.RESET_ALL}"
f"{Fore.WHITE + Style.BRIGHT} {len(accounts)} {Style.RESET_ALL}"
f"{Fore.CYAN + Style.BRIGHT}]{separator}{Style.RESET_ALL}"
)
if not "@" in email or not token:
self.log(
f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}"
f"{Fore.RED+Style.BRIGHT} Invalid Account Data {Style.RESET_ALL}"
)
continue
self.log(
f"{Fore.CYAN+Style.BRIGHT}Account:{Style.RESET_ALL}"
f"{Fore.WHITE+Style.BRIGHT} {self.mask_account(email)} {Style.RESET_ALL}"
)
exp_time = self.decode_token(token)
if not exp_time:
self.log(
f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}"
f"{Fore.RED+Style.BRIGHT} Invalid Token {Style.RESET_ALL}"
)
continue
if int(time.time()) > exp_time:
self.log(
f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}"
f"{Fore.RED+Style.BRIGHT} Token Already Expired {Style.RESET_ALL}"
)
continue
self.access_tokens[email] = token
await self.process_accounts(email, use_proxy, rotate_proxy)
await asyncio.sleep(3)
self.log(f"{Fore.CYAN + Style.BRIGHT}={Style.RESET_ALL}"*65)
seconds = 4 * 60 * 60
while seconds > 0:
formatted_time = self.format_seconds(seconds)
print(
f"{Fore.CYAN+Style.BRIGHT}[ Wait for{Style.RESET_ALL}"
f"{Fore.WHITE+Style.BRIGHT} {formatted_time} {Style.RESET_ALL}"
f"{Fore.CYAN+Style.BRIGHT}... ]{Style.RESET_ALL}"
f"{Fore.WHITE+Style.BRIGHT} | {Style.RESET_ALL}"
f"{Fore.BLUE+Style.BRIGHT}All Accounts Have Been Processed...{Style.RESET_ALL}",
end="\r"
)
await asyncio.sleep(1)
seconds -= 1
except Exception as e:
self.log(f"{Fore.RED+Style.BRIGHT}Error: {e}{Style.RESET_ALL}")
raise e
if __name__ == "__main__":
try:
bot = Interlink()
asyncio.run(bot.main())
except KeyboardInterrupt:
print(
f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}"
f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}"
f"{Fore.RED + Style.BRIGHT}[ EXIT ] Interlink - BOT{Style.RESET_ALL} "
)