import threading import time import requests import json import random import logging import sys import traceback from flask import Flask, jsonify, make_response from bs4 import BeautifulSoup from FunPayAPI.account import Account from FunPayAPI.common import enums try: from FunPayAPI.updater.runner import Runner except ImportError: from FunPayAPI.account import Runner # ========================================== # 0. DEBUGGING INFRASTRUCTURE # ========================================== LOG_BUFFER = [] class BufferHandler(logging.Handler): def emit(self, record): try: msg = self.format(record) LOG_BUFFER.append(f"{time.strftime('%H:%M:%S', time.localtime())} - {msg}") if len(LOG_BUFFER) > 200: LOG_BUFFER.pop(0) except Exception: pass logging.basicConfig(level=logging.INFO) logger = logging.getLogger("FunPayBot") logger.addHandler(BufferHandler()) # ========================================== # 1. KEEP-ALIVE SERVER (Hugging Face) # ========================================== app = Flask(__name__) @app.route('/') def home(): lines = "\n".join(LOG_BUFFER) # Return HTML for better display return f"""

🤖 Bot Status: Running

Go to /logs to see full logs.

Go to /test_tg to force test Telegram.

Last 10 Logs:

{lines[-1000:]}
""" @app.route('/logs') def get_logs(): return "
" + "\n".join(LOG_BUFFER) + "
" @app.route('/test_tg') def test_tg(): try: url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage" payload = {"chat_id": TELEGRAM_CHAT_ID, "text": "TEST MESSAGE FROM WEB. If you see this, connectivity works."} r = requests.post(url, json=payload, timeout=5) return f"OK: {r.status_code} {r.text}" except Exception as e: return f"ERROR: {e}" def run_web(): logger.info("Keep-Alive Web Server started on port 7860") app.run(host='0.0.0.0', port=7860) t = threading.Thread(target=run_web) t.start() # ========================================== # 2. PROXY MONKEY PATCH (Cloudflare) # ========================================== PROXY_URL = "https://damp-cell-4702.newnout6.workers.dev/" original_request = requests.Session.request def proxy_request(self, method, url, *args, **kwargs): if "funpay.com" in url and PROXY_URL not in url: target = url valid_cookies = self.cookies.get_dict(domain=".funpay.com") valid_cookies.update(self.cookies.get_dict(domain="funpay.com")) kw_cookies = kwargs.get('cookies') if kw_cookies: valid_cookies.update(kw_cookies) headers = kwargs.get('headers', {}) or {} headers = headers.copy() found_cookie_key = None for k in list(headers.keys()): if k.lower() == 'cookie': found_cookie_key = k raw_c = headers[k] for part in raw_c.split(';'): if '=' in part: kv = part.strip().split('=', 1) if len(kv) == 2: valid_cookies[kv[0]] = kv[1] del headers[k] cookie_header = "; ".join([f"{k}={v}" for k, v in valid_cookies.items()]) if cookie_header: headers['Cookie'] = cookie_header if 'User-Agent' not in headers: headers['User-Agent'] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" # Ensure RUB/RU locale if 'cy' not in valid_cookies: valid_cookies['cy'] = 'rub' if 'locale' not in valid_cookies: valid_cookies['locale'] = 'ru' params = kwargs.get('params', {}) or {} params = params.copy() params['url'] = target kwargs['headers'] = headers kwargs['params'] = params kwargs['cookies'] = {} return original_request(self, method, PROXY_URL, *args, **kwargs) return original_request(self, method, url, *args, **kwargs) requests.Session.request = proxy_request requests.request = proxy_request # ========================================== # 3. BOT LOGIC # ========================================== TELEGRAM_BOT_TOKEN = "8203118488:AAGC1EQavBt0u9suYQ32qt4owkU_VuubWG0" TELEGRAM_CHAT_ID = "1517760699" API_URL = "http://shrvld789.pythonanywhere.com" # Default Key GOLDEN_KEY = "dummy_key_waiting_for_update" DUMP_CATEGORY_URL = "https://funpay.com/lots/1355/" MY_USERNAME = "" # Will be filled after login def send_telegram_notification(message): try: url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage" payload = {"chat_id": TELEGRAM_CHAT_ID, "text": message, "parse_mode": "HTML"} logger.info(f"Adding to TG queue: {message[:20]}...") requests.post(url, json=payload, timeout=10) except Exception as e: logger.error(f"Failed to send Telegram notification: {e}") def get_golden_key_from_api(): try: url = f"{API_URL}/api/config" resp = requests.get(url, timeout=10) if resp.status_code == 200: config = resp.json() key = config.get('golden_key') if key and len(key) > 10: return key except Exception as e: logger.error(f"Failed to fetch key from API: {e}") return None def get_product_from_api(quantity, buyer_name, price): try: url = f"{API_URL}/api/sell" payload = {"quantity": quantity, "customer_name": buyer_name, "price": price} response = requests.post(url, json=payload, timeout=20) if response.status_code == 200: data = response.json() if data.get('success'): return "\n".join(data.get('accounts', [])) return None except Exception as e: logger.error(f"Error requesting product from API: {e}") return None def send_heartbeat(): """Periodically sends a heartbeat to the Admin Bot""" while True: try: requests.post(f"{API_URL}/api/heartbeat", timeout=5) except Exception as e: logger.error(f"Heartbeat failed: {e}") time.sleep(60) def dump_price_check(): """Monitors competitor prices and suggests updates""" global MY_USERNAME logger.info("Initializing Price Monitor...") # Wait for username with attempts attempts = 0 while not MY_USERNAME: attempts += 1 if attempts % 10 == 0: logger.warning("Still waiting for MY_USERNAME...") time.sleep(5) logger.info(f"Starting Price Monitor for {MY_USERNAME}...") while True: try: wait_time = random.randint(300, 420) logger.info(f"Checking prices... Next check in {wait_time}s") # Manually fetch page session = requests.Session() headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", "Accept-Language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7" } resp = session.get(DUMP_CATEGORY_URL, headers=headers, cookies={'cy': 'rub', 'locale': 'ru'}, timeout=20) if resp.status_code == 200: soup = BeautifulSoup(resp.text, "html.parser") offers = soup.find_all("a", class_="tc-item") online_competitor_prices = [] my_current_price = None for offer in offers: # Filter 1: Check Online Status if offer.get("data-online") != "1": continue # Filter 2: Check Subscription (Must include "с подпиской") subscription = offer.get("data-f-subscription", "").lower() if "подписк" not in subscription or "без" in subscription: continue # Filter 3: Check Keywords in Description desc_div = offer.find("div", class_="tc-desc-text") desc = desc_div.get_text(strip=True).lower() if desc_div else "" # Filter: Reviews rating_div = offer.find("span", class_="rating-mini-count") if rating_div: try: reviews = int(rating_div.get_text(strip=True).replace(' ', '')) if reviews > 100: continue except: pass # Filter: Shared if "общий" in desc or "shared" in desc or "обще" in desc: continue # Filter: Plus/Business has_plus = "plus" in desc or "плюс" in desc has_business = "business" in desc or "бизнес" in desc has_month = "month" in desc or "месяц" in desc or "30" in desc if not ((has_plus or has_business) and has_month): continue # Get Price price_div = offer.find("div", class_="tc-price") if not price_div: continue raw_s = price_div.get("data-s") if not raw_s: continue price = float(raw_s) user_div = offer.find("div", class_="media-user-name") seller = user_div.get_text(strip=True) if user_div else "Unknown" if seller == MY_USERNAME: if my_current_price is None or price < my_current_price: my_current_price = price else: online_competitor_prices.append(price) logger.info(f"Price Check Done. My Price: {my_current_price}, Min Competitor: {min(online_competitor_prices) if online_competitor_prices else 'None'}") if online_competitor_prices and my_current_price: min_competitor = min(online_competitor_prices) target_price = round(max(1.0, min_competitor - 0.01), 2) if my_current_price > target_price: send_telegram_notification( f"📉 Конкурент дешевле!\n\n" f"👤 Мин. конкурент: {min_competitor:.2f} ₽\n" f"💰 Твоя цена: {my_current_price:.2f} ₽\n" f"👉 Рекомендую: {target_price:.2f} ₽" ) elif not my_current_price: logger.warning(f"User {MY_USERNAME} not found on page!") except Exception as e: logger.error(f"Dump check failed: {e}") time.sleep(wait_time) def main(): global GOLDEN_KEY, MY_USERNAME logger.info("Starting FunPay Bot Loop on Hugging Face (DEBUG MODE)...") # Start Aux Threads t_heartbeat = threading.Thread(target=send_heartbeat, daemon=True) t_heartbeat.start() t_dump = threading.Thread(target=dump_price_check, daemon=True) t_dump.start() remote_key = get_golden_key_from_api() if remote_key: logger.info(f"✅ Key fetched from API: {remote_key[:5]}...") GOLDEN_KEY = remote_key else: logger.error("❌ Failed to fetch key from API!") while True: try: try: logger.info(f"Attempting login with key ending in ...{GOLDEN_KEY[-5:]}") acc = Account(GOLDEN_KEY).get() runner = Runner(acc) MY_USERNAME = acc.username logger.info(f"Logged in successfully: {acc.username}") send_telegram_notification(f"🤖 FunPay Bot Started!\nUser: {acc.username}\nMonitoring: Active (Smart Filter)") except Exception as e: logger.error(f"Login failed: {e}") logger.error(traceback.format_exc()) # Print full traceback time.sleep(5) new_key = get_golden_key_from_api() if new_key and new_key != GOLDEN_KEY: GOLDEN_KEY = new_key continue send_telegram_notification(f"⚠️ Login Failed!\n{e}") time.sleep(60) continue for event in runner.listen(requests_delay=4): if event.type == enums.EventTypes.NEW_ORDER: order = event.order logger.info(f"New Order Event: {order.id}") send_telegram_notification(f"💰 Новый заказ!\n{order.buyer_username} - {order.sum} руб.") product = get_product_from_api(1, order.buyer_username, order.sum) if product: try: chat = acc.get_chat_by_name(order.buyer_username, True) acc.send_message(chat.id, f"Спасибо за покупку!\n\n{product}") send_telegram_notification(f"✅ Выдан товар для {order.id}") except Exception as e: logger.error(f"Chat error: {e}") send_telegram_notification(f"⚠️ Ошибка чата: {e}") else: logger.error(f"Product not found for order {order.id}") send_telegram_notification(f"❌ Ошибка выдачи для {order.id}") except Exception as e: logger.error(f"Main Loop error: {e}") logger.error(traceback.format_exc()) time.sleep(30) if __name__ == '__main__': main()