gi2h270 commited on
Commit
ffcbcf7
·
verified ·
1 Parent(s): 6b7205f

Upload 8 files

Browse files
Files changed (8) hide show
  1. .env +0 -0
  2. .gitignore +5 -0
  3. Dockerfile +41 -0
  4. README.md +24 -10
  5. app.py +65 -0
  6. bot.js +296 -0
  7. package.json +11 -0
  8. solver.js +58 -0
.env ADDED
File without changes
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ node_modules
2
+ .env
3
+ stats.json
4
+ cookies.json
5
+ .DS_Store
Dockerfile ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9-slim
2
+
3
+ # Install Node.js 18 dan dependensi Playwright
4
+ RUN apt-get update && apt-get install -y \
5
+ curl \
6
+ software-properties-common \
7
+ && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
8
+ && apt-get install -y nodejs \
9
+ && apt-get install -y \
10
+ libnss3 \
11
+ libatk-bridge2.0-0 \
12
+ libdrm2 \
13
+ libxkbcommon0 \
14
+ libgbm1 \
15
+ libasound2 \
16
+ xvfb \
17
+ && rm -rf /var/lib/apt/lists/*
18
+
19
+ # 🔥 Hapus semua versi Gradio lama, instal Gradio 4.44.1 + huggingface_hub kompatibel
20
+ RUN pip install --no-cache-dir --upgrade pip && \
21
+ pip uninstall -y gradio huggingface_hub || true && \
22
+ pip uninstall -y gradio huggingface_hub || true && \
23
+ pip install --no-cache-dir gradio==4.44.1 huggingface_hub==0.23.4
24
+
25
+ # Install Playwright (browser Chromium)
26
+ RUN npx playwright install-deps && \
27
+ npx playwright install chromium
28
+
29
+ WORKDIR /app
30
+
31
+ COPY package*.json ./
32
+ RUN npm install
33
+
34
+ COPY . .
35
+
36
+ # ✅ Verifikasi versi saat build (harus 4.44.1)
37
+ RUN python -c "import gradio; assert gradio.__version__ == '4.44.1', f'Gradio version is {gradio.__version__}'; print('✅ Gradio 4.44.1 installed')"
38
+
39
+ EXPOSE 7860
40
+
41
+ CMD ["python", "app.py"]
README.md CHANGED
@@ -1,10 +1,24 @@
1
- ---
2
- title: Multibot
3
- emoji: 📈
4
- colorFrom: blue
5
- colorTo: indigo
6
- sdk: docker
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Multi-Coin Faucet Bot
3
+ emoji: 🤖
4
+ colorFrom: blue
5
+ colorTo: indigo
6
+ sdk: docker
7
+ app_port: 7860
8
+ pinned: false
9
+ ---
10
+
11
+ # Multi-Coin Faucet Bot
12
+
13
+ Bot otomatis claim LTC, DOGE, TRUMP di freepepecoin.com.
14
+
15
+ ## Setup
16
+
17
+ 1. **Tambahkan Secret**
18
+ `SOLVER_KEY` = (isi dengan kunci solver Anda)
19
+
20
+ 2. **Build otomatis** dengan Docker.
21
+
22
+ ## Cara Pakai
23
+
24
+ Buka tab **App**, klik **Start Bot**.
app.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import subprocess
3
+ import os
4
+ import signal
5
+
6
+ print(f"📦 Gradio version: {gr.__version__}")
7
+
8
+ bot_process = None
9
+
10
+ def start_bot():
11
+ global bot_process
12
+ if bot_process and bot_process.poll() is None:
13
+ return "Bot sudah berjalan."
14
+ bot_process = subprocess.Popen(
15
+ ["node", "bot.js"],
16
+ stdout=subprocess.PIPE,
17
+ stderr=subprocess.STDOUT,
18
+ text=True,
19
+ cwd=os.path.dirname(os.path.abspath(__file__)),
20
+ preexec_fn=os.setsid if hasattr(os, 'setsid') else None
21
+ )
22
+ return "✅ Bot started"
23
+
24
+ def stop_bot():
25
+ global bot_process
26
+ if bot_process and bot_process.poll() is None:
27
+ if hasattr(os, 'killpg'):
28
+ os.killpg(os.getpgid(bot_process.pid), signal.SIGTERM)
29
+ else:
30
+ bot_process.terminate()
31
+ bot_process = None
32
+ return "⏹️ Bot stopped"
33
+ return "Bot tidak berjalan"
34
+
35
+ def get_log():
36
+ global bot_process
37
+ if bot_process and bot_process.poll() is None:
38
+ try:
39
+ output = bot_process.stdout.read()
40
+ return output[-2000:] if output else "Menunggu log..."
41
+ except:
42
+ return "Log tidak tersedia"
43
+ else:
44
+ return "Bot tidak aktif."
45
+
46
+ # Di Gradio 4, CSS bisa langsung di sini
47
+ with gr.Blocks(title="Faucet Bot Controller", css="#log {height: 400px;}") as demo:
48
+ gr.Markdown("# 🤖 Multi-Coin Faucet Bot")
49
+ gr.Markdown("Bot otomatis claim LTC, DOGE, TRUMP di freepepecoin.com")
50
+
51
+ with gr.Row():
52
+ start_btn = gr.Button("🚀 Start Bot", variant="primary")
53
+ stop_btn = gr.Button("🛑 Stop Bot", variant="stop")
54
+
55
+ log_output = gr.Textbox(label="📋 Log Output", lines=20, max_lines=30, elem_id="log")
56
+ refresh_btn = gr.Button("🔄 Refresh Log")
57
+
58
+ start_btn.click(fn=start_bot, outputs=gr.State())
59
+ stop_btn.click(fn=stop_bot, outputs=gr.State())
60
+ refresh_btn.click(fn=get_log, outputs=log_output)
61
+
62
+ # 🔥 Auto-refresh setiap 3 detik (fitur Gradio 4)
63
+ demo.load(fn=get_log, outputs=log_output, every=3)
64
+
65
+ demo.launch(server_name="0.0.0.0", server_port=7860)
bot.js ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { chromium } from 'playwright-extra';
2
+ import StealthPlugin from 'puppeteer-extra-plugin-stealth';
3
+ import fs from 'fs/promises';
4
+ import { getRecaptchaToken } from './solver.js';
5
+
6
+ chromium.use(StealthPlugin());
7
+
8
+ const BASE_URL = 'https://litecoin.freepepecoin.com';
9
+ const EMAIL = 'gi2h2701@gmail.com'; // Ganti dengan email kamu
10
+ const SITE_KEY = '6LcbMB0sAAAAAAxsy76NqLNBhHfzZO8E4jLJ8XNl';
11
+
12
+ // Konfigurasi coin
13
+ const COINS = {
14
+ LTC: { name: 'Litecoin', path: '/faucet/LTC', defaultCooldown: 180, cooldown: 180, lastClaim: 0, totalClaims: 0, successCount: 0, totalRewards: 0 },
15
+ DOGE: { name: 'Dogecoin', path: '/faucet/DOGE', defaultCooldown: 30, cooldown: 30, lastClaim: 0, totalClaims: 0, successCount: 0, totalRewards: 0 },
16
+ TRUMP: { name: 'Trumpcoin', path: '/faucet/TRUMP', defaultCooldown: 10, cooldown: 10, lastClaim: 0, totalClaims: 0, successCount: 0, totalRewards: 0 }
17
+ };
18
+
19
+ let browser, page;
20
+ let isRunning = false;
21
+ let cycleCount = 0;
22
+
23
+ // ========== PERSISTENSI ==========
24
+ async function saveCookies(context) {
25
+ const cookies = await context.cookies();
26
+ await fs.writeFile('cookies.json', JSON.stringify(cookies, null, 2));
27
+ }
28
+
29
+ async function loadCookies(context) {
30
+ try {
31
+ const cookies = JSON.parse(await fs.readFile('cookies.json', 'utf-8'));
32
+ await context.addCookies(cookies);
33
+ } catch (e) {
34
+ // file tidak ada
35
+ }
36
+ }
37
+
38
+ async function saveStats() {
39
+ const stats = {
40
+ cycleCount,
41
+ COINS,
42
+ lastUpdate: new Date().toISOString()
43
+ };
44
+ await fs.writeFile('stats.json', JSON.stringify(stats, null, 2));
45
+ }
46
+
47
+ async function loadStats() {
48
+ try {
49
+ const stats = JSON.parse(await fs.readFile('stats.json', 'utf-8'));
50
+ cycleCount = stats.cycleCount || 0;
51
+ if (stats.COINS) {
52
+ Object.keys(COINS).forEach(sym => {
53
+ if (stats.COINS[sym]) {
54
+ Object.assign(COINS[sym], stats.COINS[sym]);
55
+ }
56
+ });
57
+ }
58
+ } catch (e) {}
59
+ }
60
+
61
+ // ========== LOGIN ==========
62
+ async function login() {
63
+ console.log('[login] Membuka halaman...');
64
+ await page.goto(BASE_URL, { waitUntil: 'networkidle' });
65
+
66
+ // Isi email
67
+ await page.waitForSelector('input[name="address"]');
68
+ await page.fill('input[name="address"]', EMAIL);
69
+
70
+ // Dapatkan token reCAPTCHA
71
+ console.log('[login] Meminta token reCAPTCHA...');
72
+ const token = await getRecaptchaToken(BASE_URL, SITE_KEY);
73
+
74
+ // Inject token
75
+ await page.evaluate((t) => {
76
+ const el = document.getElementById('g-recaptcha-response');
77
+ if (el) el.value = t;
78
+ }, token);
79
+
80
+ // Submit form
81
+ await page.click('button[type="submit"]');
82
+ await page.waitForLoadState('networkidle');
83
+
84
+ const html = await page.content();
85
+ if (html.includes(`Welcome, <b>${EMAIL}</b>`)) {
86
+ console.log('[login] ✅ Berhasil login');
87
+ await saveCookies(page.context());
88
+ return true;
89
+ } else {
90
+ console.log('[login] ❌ Gagal login');
91
+ return false;
92
+ }
93
+ }
94
+
95
+ // ========== CLAIM COIN ==========
96
+ async function claimCoin(symbol) {
97
+ const coin = COINS[symbol];
98
+ console.log(`\n[claim] 🪙 ${symbol} - ${coin.name}`);
99
+
100
+ // Kunjungi halaman faucet coin
101
+ await page.goto(`${BASE_URL}${coin.path}`, { waitUntil: 'networkidle' });
102
+
103
+ // Ambil CSRF token
104
+ try {
105
+ await page.waitForSelector('input[name="csrf_token"]', { timeout: 10000 });
106
+ } catch (e) {
107
+ console.log('[claim] ❌ CSRF token tidak ditemukan');
108
+ return false;
109
+ }
110
+ const csrfToken = await page.inputValue('input[name="csrf_token"]');
111
+ console.log(`[claim] CSRF token: ${csrfToken.substring(0, 10)}...`);
112
+
113
+ // Dapatkan token reCAPTCHA untuk claim
114
+ console.log('[claim] Meminta token reCAPTCHA...');
115
+ const recaptchaToken = await getRecaptchaToken(BASE_URL, SITE_KEY);
116
+
117
+ // Submit form claim
118
+ await page.evaluate((token, csrf, sym) => {
119
+ const recaptchaEl = document.getElementById('g-recaptcha-response');
120
+ if (recaptchaEl) recaptchaEl.value = token;
121
+
122
+ const form = document.querySelector('form');
123
+ if (form) {
124
+ // Pastikan csrf_token di form
125
+ let csrfInput = form.querySelector('input[name="csrf_token"]');
126
+ if (!csrfInput) {
127
+ csrfInput = document.createElement('input');
128
+ csrfInput.type = 'hidden';
129
+ csrfInput.name = 'csrf_token';
130
+ form.appendChild(csrfInput);
131
+ }
132
+ csrfInput.value = csrf;
133
+ form.submit();
134
+ }
135
+ }, recaptchaToken, csrfToken, symbol);
136
+
137
+ await page.waitForLoadState('networkidle');
138
+ const responseText = await page.content();
139
+
140
+ // Deteksi keberhasilan
141
+ const lower = responseText.toLowerCase();
142
+ const successKeywords = ['successfully', 'claimed', 'reward', 'thank you', 'congratulation'];
143
+ const isSuccess = successKeywords.some(kw => lower.includes(kw));
144
+
145
+ if (isSuccess) {
146
+ console.log(`[claim] ✅ Berhasil claim ${symbol}`);
147
+
148
+ coin.totalClaims++;
149
+ coin.successCount = (coin.successCount || 0) + 1;
150
+
151
+ // Ekstrak reward
152
+ const rewardPatterns = [
153
+ new RegExp(`(\\d+\\.?\\d*)\\s*${symbol}`, 'i'),
154
+ /claimed\s*:\s*(\d+\.?\d*)/i,
155
+ /reward\s*:\s*(\d+\.?\d*)/i,
156
+ /(\d+\.?\d*)\s*coins?/i
157
+ ];
158
+
159
+ let reward = 0;
160
+ for (const pattern of rewardPatterns) {
161
+ const match = responseText.match(pattern);
162
+ if (match) {
163
+ reward = parseFloat(match[1]);
164
+ if (!isNaN(reward) && reward > 0) break;
165
+ }
166
+ }
167
+
168
+ if (reward > 0) {
169
+ coin.totalRewards += reward;
170
+ console.log(`[claim] 💰 Reward: ${reward} ${symbol}`);
171
+ } else {
172
+ // Estimasi default
173
+ const defaultRewards = { LTC: 0.000001, DOGE: 0.00001, TRUMP: 0.01 };
174
+ coin.totalRewards += defaultRewards[symbol] || 0.0001;
175
+ console.log(`[claim] 💰 Reward: ~${defaultRewards[symbol] || 0.0001} ${symbol} (estimasi)`);
176
+ }
177
+
178
+ coin.lastClaim = Date.now() / 1000;
179
+ await saveStats();
180
+ return true;
181
+ } else {
182
+ console.log(`[claim] ❌ Gagal claim ${symbol}`);
183
+
184
+ // Cek pesan cooldown
185
+ const cdMatch = responseText.match(/(\d+)\s*(?:second|sec|minute|min)/i);
186
+ if (cdMatch) {
187
+ let value = parseInt(cdMatch[1]);
188
+ const unit = cdMatch[0].toLowerCase();
189
+ if (unit.includes('min')) value *= 60;
190
+ coin.cooldown = value;
191
+ console.log(`[claim] ⏱️ Cooldown diperbarui: ${value} detik`);
192
+ } else {
193
+ coin.cooldown = coin.defaultCooldown;
194
+ }
195
+
196
+ coin.lastClaim = Date.now() / 1000; // catat waktu gagal agar tidak spam
197
+ await saveStats();
198
+ return false;
199
+ }
200
+ }
201
+
202
+ // ========== LOGIKA CYCLE ==========
203
+ async function runCycle() {
204
+ cycleCount++;
205
+ console.log(`\n🔄 CYCLE #${cycleCount}`);
206
+
207
+ const now = Date.now() / 1000;
208
+
209
+ // Cari coin yang siap
210
+ let available = null;
211
+ for (const sym in COINS) {
212
+ if (now - COINS[sym].lastClaim >= COINS[sym].cooldown) {
213
+ available = sym;
214
+ break;
215
+ }
216
+ }
217
+
218
+ if (!available) {
219
+ // Hitung waktu tunggu minimal
220
+ let minWait = Infinity;
221
+ for (const sym in COINS) {
222
+ const wait = Math.max(0, COINS[sym].cooldown - (now - COINS[sym].lastClaim));
223
+ if (wait < minWait) minWait = wait;
224
+ }
225
+ console.log(`⏳ Semua coin cooldown, tunggu ${Math.ceil(minWait)} detik...`);
226
+ await new Promise(r => setTimeout(r, minWait * 1000));
227
+ // Rekursif coba lagi
228
+ return runCycle();
229
+ }
230
+
231
+ // Claim coin yang tersedia
232
+ const success = await claimCoin(available);
233
+ if (!success) {
234
+ console.log(`[cycle] Claim ${available} gagal, lanjut cycle berikutnya.`);
235
+ }
236
+
237
+ // Simpan statistik tiap cycle
238
+ await saveStats();
239
+ }
240
+
241
+ // ========== START BOT ==========
242
+ export async function startBot() {
243
+ if (isRunning) {
244
+ console.log('[bot] Sudah berjalan');
245
+ return;
246
+ }
247
+ isRunning = true;
248
+
249
+ console.log('[bot] Memulai bot...');
250
+ await loadStats();
251
+
252
+ // Launch browser
253
+ browser = await chromium.launch({
254
+ headless: true,
255
+ args: ['--no-sandbox', '--disable-setuid-sandbox']
256
+ });
257
+
258
+ const context = await browser.newContext({
259
+ viewport: { width: 1280, height: 720 },
260
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
261
+ });
262
+
263
+ await loadCookies(context);
264
+ page = await context.newPage();
265
+
266
+ // Login jika perlu
267
+ if (!await login()) {
268
+ console.log('[bot] ❌ Login gagal, hentikan bot');
269
+ isRunning = false;
270
+ await browser.close();
271
+ return;
272
+ }
273
+
274
+ // Loop utama
275
+ try {
276
+ while (isRunning) {
277
+ await runCycle();
278
+ // Jeda 2 detik antar siklus agar tidak overload
279
+ await new Promise(r => setTimeout(r, 2000));
280
+ }
281
+ } catch (err) {
282
+ console.error('[bot] Error di loop:', err);
283
+ } finally {
284
+ await browser.close();
285
+ isRunning = false;
286
+ }
287
+ }
288
+
289
+ // ========== STOP BOT ==========
290
+ export async function stopBot() {
291
+ console.log('[bot] Menghentikan bot...');
292
+ isRunning = false;
293
+ if (browser) {
294
+ await browser.close();
295
+ }
296
+ }
package.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "faucet-bot",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "dependencies": {
6
+ "playwright": "^1.41.0",
7
+ "playwright-extra": "^4.3.6",
8
+ "puppeteer-extra-plugin-stealth": "^2.11.2",
9
+ "node-fetch": "^3.3.2"
10
+ }
11
+ }
solver.js ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import fetch from 'node-fetch';
2
+
3
+ const SOLVER_URL = 'https://gi2h-xxx.hf.space/solve'; // ganti dengan endpoint kamu
4
+
5
+ export async function getRecaptchaToken(domain, siteKey) {
6
+ const SOLVER_KEY ="00000000000000000000#0000000000000000000#000000000000000000#"
7
+ if (!SOLVER_KEY) throw new Error('SOLVER_KEY tidak ditemukan di environment');
8
+
9
+ console.log('[solver] Meminta token...');
10
+
11
+ // Submit task
12
+ const submitRes = await fetch(SOLVER_URL, {
13
+ method: 'POST',
14
+ headers: {
15
+ 'Content-Type': 'application/json',
16
+ 'key': SOLVER_KEY
17
+ },
18
+ body: JSON.stringify({
19
+ type: 'recaptcha3',
20
+ domain,
21
+ siteKey
22
+ })
23
+ });
24
+
25
+ const submitData = await submitRes.json();
26
+ const taskId = submitData.taskId;
27
+ if (!taskId) throw new Error('Gagal mendapatkan taskId');
28
+
29
+ console.log(`[solver] Task ID: ${taskId}`);
30
+
31
+ // Polling hasil (maks 60 detik)
32
+ for (let i = 0; i < 30; i++) {
33
+ await new Promise(r => setTimeout(r, 2000));
34
+
35
+ const pollRes = await fetch(SOLVER_URL, {
36
+ method: 'POST',
37
+ headers: {
38
+ 'Content-Type': 'application/json',
39
+ 'key': SOLVER_KEY
40
+ },
41
+ body: JSON.stringify({ taskId })
42
+ });
43
+
44
+ const pollData = await pollRes.json();
45
+
46
+ if (pollData.status === 'done') {
47
+ const token = pollData.token || pollData.solution?.token;
48
+ console.log('[solver] ✅ Token diterima');
49
+ return token;
50
+ }
51
+
52
+ if (pollData.status === 'error') {
53
+ throw new Error(`Solver error: ${pollData.message || 'unknown'}`);
54
+ }
55
+ }
56
+
57
+ throw new Error('Timeout: solver tidak merespon');
58
+ }