gadisk820 commited on
Commit
afdef91
Β·
verified Β·
1 Parent(s): a732ec6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +366 -222
app.py CHANGED
@@ -1,266 +1,410 @@
1
- import requests
 
2
  import time
 
3
  import re
4
- from colorama import init, Fore, Style
 
 
 
5
 
6
  init(autoreset=True)
7
- print = lambda *a, **k: __builtins__.print(*a, **k, flush=True)
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- class AllAndRichAutoClaim:
11
- def __init__(self):
12
- self.base = "https://partner.allandrich.shop"
13
- self.dashboard_url = self.base + "/dashboard"
14
- self.login_url = self.base + "/login"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
- self.email = "gi2h27@gmail.com"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- self.session = requests.Session()
19
- self.session.headers.update({
20
- "User-Agent": "Mozilla/5.0",
21
- "Content-Type": "application/x-www-form-urlencoded",
22
- "Referer": self.dashboard_url
23
- })
 
 
 
 
 
 
 
 
 
24
 
25
- # ========================
26
- # LOGIN
27
- # ========================
28
- def get_login_csrf(self):
29
- print("Opening login page...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- r = self.session.get(self.dashboard_url, timeout=30)
 
 
 
32
 
33
- match = re.search(
34
- r'name="csrf_token"\s+value="([^"]+)"',
35
- r.text
36
- )
37
 
38
- if match:
39
- print("CSRF login OK")
40
- return match.group(1)
 
 
41
 
42
- print("CSRF login not found")
43
- return None
 
 
44
 
45
- def login(self):
46
- csrf = self.get_login_csrf()
47
  if not csrf:
48
  return False
49
 
50
- payload = {
 
51
  "csrf_token": csrf,
52
- "website": "",
53
- "js_challenge": "passed",
54
- "email": self.email
 
55
  }
56
 
57
- print("Sending login...")
58
-
59
- r = self.session.post(
60
- self.login_url,
61
- data=payload,
62
- timeout=30
63
- )
64
-
65
- if "dashboard" in r.text.lower():
66
- print(f"{Fore.GREEN}βœ“ Login success{Style.RESET_ALL}")
67
- return True
68
-
69
- print("Login unclear, retry later")
70
- return False
71
 
72
- # ========================
73
- # UPDATE CSRF
74
- # ========================
75
- def update_csrf_token(self):
76
  try:
77
- r = self.session.get(self.dashboard_url, timeout=30)
78
-
79
- match = re.search(
80
- r'name="csrf_token"\s+value="([^"]+)"',
81
- r.text
82
- )
83
-
84
- if match:
85
- return match.group(1)
86
-
 
 
87
  except Exception as e:
88
- print("CSRF error:", e)
89
-
90
- return None
91
 
92
- # ========================
93
- # START FAUCET
94
- # ========================
95
- def start_faucet(self, csrf):
96
  try:
97
- data = {
98
- "csrf_token": csrf,
99
- "action": "start_faucet"
100
- }
101
-
102
- r = self.session.post(
103
- self.dashboard_url,
104
- data=data,
105
- timeout=30
106
- )
107
 
108
- txt = r.text.lower()
109
 
110
- if "started" in txt:
111
- print("βœ“ Faucet started")
112
- return True
113
 
114
- if "already" in txt:
115
- print("βœ“ Faucet already running")
116
- return True
 
 
 
 
 
117
 
118
  except Exception as e:
119
- print("Start faucet error:", e)
120
-
121
- return False
122
-
123
- # ========================
124
- # BALANCE PARSER
125
- # ========================
126
- def extract_balance_info(self, html_text):
127
- balance_info = {
128
- "balance": "0.00000000",
129
- "total_withdrawn": "0.00000000"
130
- }
131
 
132
- try:
133
- balance_pattern = r'<div class="balance-display">([\d.,]+) DOGE</div>'
134
- match = re.search(balance_pattern, html_text)
135
- if match:
136
- balance_info["balance"] = match.group(1).replace(",", "")
137
-
138
- withdrawn_pattern = r'Total Withdrawn:\s*<strong>([\d.]+) DOGE</strong>'
139
- match = re.search(withdrawn_pattern, html_text)
140
- if match:
141
- balance_info["total_withdrawn"] = match.group(1)
142
-
143
- except:
144
- pass
145
-
146
- return balance_info
147
-
148
- # ========================
149
- # MESSAGE PARSER
150
- # ========================
151
- def extract_message_box(self, html):
152
- match = re.search(
153
- r'<div[^>]*id="message-box"[^>]*>(.*?)</div>',
154
- html,
155
- re.DOTALL
156
- )
157
 
158
- if match:
159
- msg = re.sub(r'<[^>]+>', '', match.group(1))
160
- return re.sub(r'\s+', ' ', msg).strip()
 
161
 
162
- return None
 
 
 
 
 
 
 
 
 
163
 
164
- # ========================
165
- # COLLECT
166
- # ========================
167
- def collect_reward(self, csrf):
168
  try:
169
- data = {
170
- "csrf_token": csrf,
171
- "action": "collect"
172
- }
173
-
174
- r = self.session.post(
175
- self.dashboard_url,
176
- data=data,
177
- timeout=30
178
- )
179
-
180
- info = self.extract_balance_info(r.text)
181
- balance = info["balance"]
182
- withdrawn = info["total_withdrawn"]
183
-
184
- print("=" * 40)
185
- print("Balance:", balance, "DOGE")
186
- print("Withdrawn:", withdrawn, "DOGE")
187
-
188
- msg = self.extract_message_box(r.text)
189
- if msg:
190
- print("INFO:", msg)
191
-
192
- if "successful auto-withdrawal" in r.text.lower():
193
- print("βœ“ Withdrawal success")
194
- return True
195
-
196
- if "please wait" in r.text.lower():
197
- print("⏳ Timer active")
198
- return False
199
-
200
- if "credited" in r.text.lower():
201
- return True
202
-
203
- return False
204
-
205
  except Exception as e:
206
- print("Collect error:", e)
207
  return False
208
 
209
- # ========================
210
- # MAIN LOOP
211
- # ========================
212
- def run_auto_claim(self, interval_minutes=1):
213
- print("=" * 50)
214
- print("πŸš€ Starting AllAndRich Auto Claim Bot")
215
- print("=" * 50)
216
-
217
- if not self.login():
218
- print("Login failed")
219
- return
220
 
221
- claim_count = 0
 
222
 
223
- while True:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  try:
225
- print("\nAttempt:", claim_count + 1)
226
- print("Time:", time.strftime('%Y-%m-%d %H:%M:%S'))
227
-
228
- csrf = self.update_csrf_token()
229
-
230
- if not csrf:
231
- print("CSRF refresh failed, retrying...")
232
- time.sleep(10)
233
- continue
234
-
235
- result = self.collect_reward(csrf)
236
-
237
- if not result:
238
- print("Trying start faucet...")
239
- self.start_faucet(csrf)
240
-
241
- claim_count += 1
242
-
243
- wait_time = interval_minutes * 60
244
-
245
- for remaining in range(wait_time, 0, -1):
246
- if remaining % 15 == 0 or remaining <= 5:
247
- m, s = divmod(remaining, 60)
248
- print(f"Next claim in {m:02d}:{s:02d}")
249
- time.sleep(1)
250
-
251
- except KeyboardInterrupt:
252
- print("Bot stopped")
253
- break
254
-
255
  except Exception as e:
256
- print("Loop error:", e)
257
- time.sleep(30)
258
-
259
-
260
- def main():
261
- bot = AllAndRichAutoClaim()
262
- bot.run_auto_claim(1)
263
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
 
 
265
  if __name__ == "__main__":
266
- main()
 
 
1
+ import os
2
+ import random
3
  import time
4
+ import threading
5
  import re
6
+ import cloudscraper
7
+ import requests
8
+ from bs4 import BeautifulSoup
9
+ from colorama import init, Fore
10
 
11
  init(autoreset=True)
 
12
 
13
+ # ================= KONFIGURASI =================
14
+ BASE_URL = "https://firefaucet.win"
15
+ DASHBOARD_URL = f"{BASE_URL}/"
16
+ FAUCET_URL = f"{BASE_URL}/faucet/"
17
+ PAYOUT_URL = f"{BASE_URL}/internal-api/payout/"
18
+ BALANCE_URL = f"{BASE_URL}/balance/"
19
+ WITHDRAW_INFO_URL = f"{BASE_URL}/internal-api/withdraw/get-withdrawal-info/"
20
+ WITHDRAW_URL = f"{BASE_URL}/api/withdraw/" # <--- PERBAIKAN: endpoint withdraw
21
+ LEVELS_URL = f"{BASE_URL}/levels"
22
+
23
+ # Environment variables
24
+ SOLVER_URLS = os.getenv("SOLVER_URLS", "https://gi2h-minerton23.hf.space").split(',')
25
+ SOLVER_KEY = os.getenv("SOLVER_KEY", "00000000000000000000#0000000000000000000#000000000000000000#")
26
+ PROXY_URL = os.getenv("PROXY_URL", None)
27
+ LTC_ADDRESS = os.getenv("LTC_ADDRESS", "ltc1qrthepxg7yxs5d8v94k6y8p74q0qxvv7vk5qe7m") # Alamat LTC tujuan withdraw
28
+
29
+ HEADERS = {
30
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
31
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
32
+ "Referer": DASHBOARD_URL
33
+ }
34
+
35
+ COOKIES = {
36
+ "session": "ae530762-a411-49c1-9b86-00741a937b60.l40aeEK2wwSTMN2ifOUFUIi7KVw",
37
+ "refer_by" : "1022644"
38
+ }
39
+
40
+ # ================= SOLVER TURNSTILE =================
41
+ class TurnstileSolver:
42
+ def __init__(self, email=""):
43
+ self.email = email
44
+ self.solver_url = random.choice(SOLVER_URLS).strip()
45
+ self.sitekey = "0x4AAAAAAAEUvFih09RuyAna"
46
+
47
+ def solve(self, domain):
48
+ domain_with_proto = f"https://{domain}" if not domain.startswith('http') else domain
49
+ headers = {"Content-Type": "application/json", "key": SOLVER_KEY}
50
+ data = {"type": "turnstile", "domain": domain_with_proto, "siteKey": self.sitekey}
51
+
52
+ for attempt in range(1, 6):
53
+ try:
54
+ resp = requests.post(f"{self.solver_url}/solve", headers=headers, json=data, timeout=30)
55
+ result = resp.json()
56
+ if "taskId" not in result:
57
+ print(Fore.RED + f"❌ Tidak ada taskId (percobaan {attempt})", flush=True)
58
+ continue
59
+ task_id = result["taskId"]
60
+ for _ in range(30):
61
+ time.sleep(5)
62
+ poll = requests.post(f"{self.solver_url}/solve", headers=headers,
63
+ json={"taskId": task_id}, timeout=30)
64
+ poll_res = poll.json()
65
+ if poll_res.get("status") == "done":
66
+ token = poll_res.get("token") or poll_res.get("solution", {}).get("token")
67
+ if token:
68
+ print(Fore.GREEN + "βœ… Token Turnstile diterima", flush=True)
69
+ return token
70
+ elif poll_res.get("status") == "error":
71
+ print(Fore.RED + f"⚠️ Error solver: {poll_res}", flush=True)
72
+ break
73
+ print(Fore.YELLOW + "⏳ Timeout polling, coba solver lain?", flush=True)
74
+ except Exception as e:
75
+ print(Fore.RED + f"⚠️ Solver error: {e}", flush=True)
76
+ time.sleep(2 ** attempt)
77
+ return None
78
 
79
+ # ================= BOT UTAMA =================
80
+ class FaucetBot:
81
+ def __init__(self, cookies, email="user@example.com"):
82
+ self.session = cloudscraper.create_scraper()
83
+ self.session.cookies.update(cookies)
84
+ self.email = email
85
+ self.solver = TurnstileSolver(email)
86
+ self.running = True
87
+ self.proxy_url = PROXY_URL
88
+ self.using_proxy = False
89
+
90
+ if self.proxy_url:
91
+ self.proxy_session = cloudscraper.create_scraper()
92
+ self.proxy_session.cookies.update(cookies)
93
+ proxies = {"http": self.proxy_url, "https": self.proxy_url}
94
+ self.proxy_session.proxies.update(proxies)
95
+ else:
96
+ self.proxy_session = None
97
+
98
+ def get_csrf_token(self, use_proxy=False):
99
+ session = self.proxy_session if use_proxy and self.proxy_session else self.session
100
+ try:
101
+ resp = session.get(DASHBOARD_URL, headers=HEADERS, timeout=30)
102
+ resp.raise_for_status()
103
+ soup = BeautifulSoup(resp.text, "html.parser")
104
+ token_input = soup.find("input", {"name": "csrf_token"})
105
+ if token_input:
106
+ return token_input['value']
107
+ else:
108
+ print(Fore.RED + "⚠️ CSRF token tidak ditemukan", flush=True)
109
+ return None
110
+ except Exception as e:
111
+ print(Fore.RED + f"⚠️ Gagal ambil CSRF: {e}", flush=True)
112
+ return None
113
 
114
+ def check_cooldown(self, html):
115
+ match = re.search(r'(?:after|in)\s+(\d+)\s*(minute|minutes|hour|hours)', html, re.IGNORECASE)
116
+ if match:
117
+ value = int(match.group(1))
118
+ unit = match.group(2).lower()
119
+ seconds = value * 3600 if 'hour' in unit else value * 60
120
+ print(Fore.YELLOW + f"⏳ Cooldown {value} {unit}, menunggu {seconds} detik...", flush=True)
121
+ time.sleep(seconds)
122
+ return True
123
+ if re.search(r'please come back after|try again later|cooldown', html, re.IGNORECASE):
124
+ default_wait = 30 * 60
125
+ print(Fore.YELLOW + f"⏳ Cooldown terdeteksi (tanpa durasi), menunggu {default_wait//60} menit default...", flush=True)
126
+ time.sleep(default_wait)
127
+ return True
128
+ return False
129
 
130
+ def get_balance(self, use_proxy=False):
131
+ session = self.proxy_session if use_proxy and self.proxy_session else self.session
132
+ try:
133
+ resp = session.get(BALANCE_URL, headers=HEADERS, timeout=30)
134
+ if resp.status_code != 200:
135
+ return None
136
+ soup = BeautifulSoup(resp.text, "html.parser")
137
+ usd_elem = soup.find("span", id="ltc-usd-balance")
138
+ ltc_elem = soup.find("b", id="ltc-balance")
139
+ usd = usd_elem.text.strip() if usd_elem else "N/A"
140
+ ltc = ltc_elem.text.strip() if ltc_elem else "N/A"
141
+ return usd, ltc
142
+ except Exception as e:
143
+ print(Fore.RED + f"⚠️ Gagal ambil balance: {e}", flush=True)
144
+ return None
145
 
146
+ # ========== FUNGSI WITHDRAW ==========
147
+ def get_withdrawal_info(self, coin="ltc", use_proxy=False):
148
+ session = self.proxy_session if use_proxy and self.proxy_session else self.session
149
+ params = {"coin": coin}
150
+ try:
151
+ resp = session.get(WITHDRAW_INFO_URL, headers=HEADERS, params=params, timeout=30)
152
+ resp.raise_for_status()
153
+ return resp.json()
154
+ except Exception as e:
155
+ print(Fore.RED + f"⚠️ Gagal ambil info withdrawal: {e}", flush=True)
156
+ return None
157
+
158
+ def withdraw(self, coin="ltc", address=None, amount=None, use_proxy=False):
159
+ """Lakukan withdraw dengan amount USD ke address tertentu (network mainnet)"""
160
+ if not address:
161
+ address = LTC_ADDRESS
162
+ if not address:
163
+ print(Fore.RED + "❌ Alamat LTC tidak ditemukan. Set LTC_ADDRESS di environment variable.", flush=True)
164
+ return False
165
 
166
+ # Ambil info withdrawal
167
+ info = self.get_withdrawal_info(coin, use_proxy=use_proxy)
168
+ if not info:
169
+ return False
170
 
171
+ user_balance_usd = info['user']['balance_usd']
172
+ if user_balance_usd < 4.0:
173
+ print(Fore.YELLOW + f"⏳ Saldo belum mencukupi untuk withdraw: ${user_balance_usd:.2f} < $4", flush=True)
174
+ return False
175
 
176
+ daily_limit = info['user']['daily_withdrawal_limit']
177
+ max_possible = min(user_balance_usd, daily_limit['max'] - daily_limit['used'])
178
+ if max_possible < 4.0:
179
+ print(Fore.YELLOW + f"⏳ Maksimum withdraw ${max_possible:.2f} < $4", flush=True)
180
+ return False
181
 
182
+ if amount is None:
183
+ amount = max_possible
184
+ else:
185
+ amount = min(amount, max_possible)
186
 
187
+ # Dapatkan CSRF token
188
+ csrf = self.get_csrf_token(use_proxy=use_proxy)
189
  if not csrf:
190
  return False
191
 
192
+ # Data POST sesuai form (network mainnet untuk LTC)
193
+ data = {
194
  "csrf_token": csrf,
195
+ "coin": coin,
196
+ "network": "mainnet", # <--- PENTING: field network
197
+ "address": address,
198
+ "amount": str(amount)
199
  }
200
 
201
+ headers_post = HEADERS.copy()
202
+ headers_post.update({
203
+ "Content-Type": "application/x-www-form-urlencoded",
204
+ "X-Requested-With": "XMLHttpRequest"
205
+ })
 
 
 
 
 
 
 
 
 
206
 
207
+ session = self.proxy_session if use_proxy and self.proxy_session else self.session
 
 
 
208
  try:
209
+ resp = session.post(WITHDRAW_URL, headers=headers_post, data=data, timeout=30)
210
+ if resp.status_code == 200:
211
+ result = resp.json()
212
+ if result.get('success'):
213
+ print(Fore.GREEN + f"βœ… Withdraw sukses! ID: {result.get('withdrawal_id')}", flush=True)
214
+ return True
215
+ else:
216
+ print(Fore.RED + f"❌ Withdraw gagal: {result.get('message')}", flush=True)
217
+ return False
218
+ else:
219
+ print(Fore.RED + f"❌ Withdraw error status: {resp.status_code}", flush=True)
220
+ return False
221
  except Exception as e:
222
+ print(Fore.RED + f"⚠️ Gagal POST withdraw: {e}", flush=True)
223
+ return False
 
224
 
225
+ # ========== FUNGSI LEVEL ==========
226
+ def check_and_claim_levels(self, use_proxy=False):
227
+ """Cek level tiap jam dan klaim jika tersedia"""
228
+ session = self.proxy_session if use_proxy and self.proxy_session else self.session
229
  try:
230
+ resp = session.get(LEVELS_URL, headers=HEADERS)
231
+ resp.raise_for_status()
232
+ soup = BeautifulSoup(resp.text, "html.parser")
 
 
 
 
 
 
 
233
 
234
+ collect_buttons = [a['href'] for a in soup.select("a.collect-btn") if 'disabled' not in a.get('class', [])]
235
 
236
+ if not collect_buttons:
237
+ print(Fore.YELLOW + "⚠️ Tidak ada level yang tersedia untuk diklaim saat ini.")
238
+ return
239
 
240
+ for href in collect_buttons:
241
+ url = href if href.startswith("http") else BASE_URL + href
242
+ print(Fore.MAGENTA + f"🟒 Mengklaim level: {url}")
243
+ claim_resp = session.get(url, headers=HEADERS)
244
+ if claim_resp.status_code == 200:
245
+ print(Fore.GREEN + "βœ… Claim level berhasil!")
246
+ else:
247
+ print(Fore.RED + f"⚠️ Claim gagal, status code: {claim_resp.status_code}")
248
 
249
  except Exception as e:
250
+ print(Fore.RED + "⚠️ Error saat cek atau klaim level:", e)
 
 
 
 
 
 
 
 
 
 
 
251
 
252
+ # ========== LOOP UTAMA ==========
253
+ def claim_faucet(self, use_proxy=False):
254
+ session = self.proxy_session if use_proxy and self.proxy_session else self.session
255
+ csrf = self.get_csrf_token(use_proxy=use_proxy)
256
+ if not csrf:
257
+ return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
+ token = self.solver.solve("firefaucet.win")
260
+ if not token:
261
+ print(Fore.RED + "❌ Gagal mendapatkan token Turnstile", flush=True)
262
+ return False
263
 
264
+ data = {
265
+ "csrf_token": csrf,
266
+ "selected-captcha": "turnstile",
267
+ "cf-turnstile-response": token
268
+ }
269
+ headers_post = HEADERS.copy()
270
+ headers_post.update({
271
+ "Content-Type": "application/x-www-form-urlencoded",
272
+ "X-Requested-With": "XMLHttpRequest"
273
+ })
274
 
 
 
 
 
275
  try:
276
+ resp = session.post(FAUCET_URL, headers=headers_post, data=data, timeout=30, allow_redirects=True)
277
+ html = resp.text
278
+ print(Fore.CYAN + f"πŸ“ Response URL: {resp.url}", flush=True)
279
+ print(Fore.CYAN + f"πŸ“Š Status code: {resp.status_code}", flush=True)
280
+ if resp.history:
281
+ print(Fore.YELLOW + "πŸ”„ Redirect history:", [r.url for r in resp.history], flush=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  except Exception as e:
283
+ print(Fore.RED + f"⚠️ Gagal POST claim: {e}", flush=True)
284
  return False
285
 
286
+ if "Proxy Detected" in html or "<title>Proxy Detected</title>" in html:
287
+ print(Fore.RED + "🚫 Proxy terdeteksi!", flush=True)
288
+ return "proxy_detected"
 
 
 
 
 
 
 
 
289
 
290
+ if self.check_cooldown(html):
291
+ return False
292
 
293
+ success = False
294
+ soup = BeautifulSoup(html, "html.parser")
295
+ success_div = soup.find("div", class_="success_msg")
296
+ if success_div:
297
+ print(Fore.GREEN + f"βœ… Claim sukses: {success_div.text.strip()}", flush=True)
298
+ success = True
299
+ elif "successfully added" in html.lower():
300
+ print(Fore.GREEN + "βœ… Claim sukses (dari teks)", flush=True)
301
+ success = True
302
+ else:
303
+ print(Fore.RED + "❌ Claim gagal, respon tidak dikenali", flush=True)
304
+ print(Fore.YELLOW + "πŸ“„ HTML preview (first 500 chars):", flush=True)
305
+ print(html[:500], flush=True)
306
+
307
+ return success
308
+
309
+ def payout_loop(self):
310
+ while self.running:
311
  try:
312
+ resp = self.session.get(PAYOUT_URL, headers=HEADERS, timeout=30)
313
+ resp.raise_for_status()
314
+ data = resp.json()
315
+ if data.get("success"):
316
+ print(Fore.GREEN + f"πŸ’° Payout berhasil! Balance: {data.get('balance')}", flush=True)
317
+ print(Fore.CYAN + f"⏳ Next payout: {data.get('time_left')}", flush=True)
318
+ else:
319
+ print(Fore.RED + f"⚠️ Payout gagal: {data}", flush=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  except Exception as e:
321
+ print(Fore.RED + f"⚠️ Gagal request payout: {e}", flush=True)
322
+ for _ in range(60):
323
+ if not self.running:
324
+ break
325
+ time.sleep(1)
326
+
327
+ def balance_loop(self):
328
+ while self.running:
329
+ balance = self.get_balance(use_proxy=self.using_proxy)
330
+ if balance:
331
+ usd, ltc = balance
332
+ print(Fore.CYAN + f"πŸ’΅ Balance: ${usd} USD | {ltc} LTC", flush=True)
333
+ else:
334
+ print(Fore.RED + "❌ Gagal mengambil balance", flush=True)
335
+ for _ in range(300):
336
+ if not self.running:
337
+ break
338
+ time.sleep(1)
339
+
340
+ def withdraw_loop(self):
341
+ """Loop pengecekan saldo untuk withdraw setiap 5 menit"""
342
+ while self.running:
343
+ time.sleep(300) # 5 menit
344
+ info = self.get_withdrawal_info(use_proxy=self.using_proxy)
345
+ if info and info['user']['balance_usd'] >= 4.0:
346
+ print(Fore.CYAN + f"πŸ’° Saldo mencukupi untuk withdraw: ${info['user']['balance_usd']:.2f}", flush=True)
347
+ self.withdraw(use_proxy=self.using_proxy)
348
+ else:
349
+ if info:
350
+ print(Fore.CYAN + f"πŸ’° Saldo saat ini: ${info['user']['balance_usd']:.2f} (< $4)", flush=True)
351
+
352
+ def level_loop(self):
353
+ """Loop pengecekan level setiap jam"""
354
+ while self.running:
355
+ self.check_and_claim_levels(use_proxy=self.using_proxy)
356
+ # Tunggu 1 jam (3600 detik) sebelum cek lagi
357
+ for _ in range(3600):
358
+ if not self.running:
359
+ break
360
+ time.sleep(1)
361
+
362
+ def claim_loop(self):
363
+ while self.running:
364
+ result = self.claim_faucet(use_proxy=False)
365
+
366
+ if result == "proxy_detected":
367
+ if self.proxy_session and not self.using_proxy:
368
+ print(Fore.YELLOW + "πŸ”„ Mencoba menggunakan proxy...", flush=True)
369
+ result2 = self.claim_faucet(use_proxy=True)
370
+ if result2 == "proxy_detected":
371
+ print(Fore.RED + "🚫 Proxy juga terdeteksi. Menunggu 1 jam sebelum coba lagi...", flush=True)
372
+ time.sleep(3600)
373
+ elif result2 is True:
374
+ print(Fore.GREEN + "βœ… Claim sukses dengan proxy!", flush=True)
375
+ self.using_proxy = True
376
+ time.sleep(60)
377
+ continue
378
+ else:
379
+ print(Fore.RED + "❌ Claim dengan proxy gagal karena alasan lain.", flush=True)
380
+ time.sleep(10)
381
+ else:
382
+ print(Fore.RED + "🚫 Proxy terdeteksi dan tidak ada proxy alternatif. Menunggu 1 jam...", flush=True)
383
+ time.sleep(3600)
384
+ elif result is True:
385
+ print(Fore.CYAN + "⏳ Menunggu 60 detik sebelum claim berikutnya...", flush=True)
386
+ time.sleep(60)
387
+ else:
388
+ print(Fore.CYAN + "⏳ Mencoba lagi dalam 10 detik...", flush=True)
389
+ time.sleep(10)
390
+
391
+ def run(self):
392
+ print(Fore.MAGENTA + "πŸ”Ή Memulai bot faucet dengan Turnstile solver, thread payout, balance monitor, withdraw monitor, dan level checker...", flush=True)
393
+ payout_thread = threading.Thread(target=self.payout_loop, daemon=True)
394
+ payout_thread.start()
395
+ balance_thread = threading.Thread(target=self.balance_loop, daemon=True)
396
+ balance_thread.start()
397
+ withdraw_thread = threading.Thread(target=self.withdraw_loop, daemon=True)
398
+ withdraw_thread.start()
399
+ level_thread = threading.Thread(target=self.level_loop, daemon=True)
400
+ level_thread.start()
401
+ try:
402
+ self.claim_loop()
403
+ except KeyboardInterrupt:
404
+ print(Fore.YELLOW + "\nπŸ›‘ Dihentikan oleh user.", flush=True)
405
+ self.running = False
406
 
407
+ # ================= EKSEKUSI =================
408
  if __name__ == "__main__":
409
+ bot = FaucetBot(COOKIES, email="your_email@example.com")
410
+ bot.run()