import os import uuid import json import threading import time from datetime import datetime from flask import Flask, request, jsonify import requests UPLOAD_DIR = os.path.join(os.path.dirname(__file__), "uploads") os.makedirs(UPLOAD_DIR, exist_ok=True) app = Flask(__name__) app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 sessions = {} sessions_lock = threading.Lock() # ---------------- Helpers ---------------- def load_messages(path): with open(path, "r", encoding="utf-8") as f: return [l.strip() for l in f.readlines() if l.strip()] # ---- Cloud API (Meta) ---- def cloud_send_text(phone_number_id, to, text, access_token, api_version="v21.0"): url = f"https://graph.facebook.com/{api_version}/{phone_number_id}/messages" headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } payload = { "messaging_product": "whatsapp", "to": to, "type": "text", "text": {"body": text} } return requests.post(url, headers=headers, json=payload, timeout=30) # ---- Green-API ---- def green_send_message(api_url, id_instance, api_token, to, text): endpoint = f"{api_url}/waInstance{id_instance}/sendMessage/{api_token}" body = {"chatId": to, "message": text} headers = {"Content-Type": "application/json"} return requests.post(endpoint, headers=headers, json=body, timeout=30) # ---------------- Worker ---------------- def session_worker(sid): while True: with sessions_lock: s = sessions.get(sid) if not s or s.get("stopped"): break idx = s.get("next_index", 0) msg = s["messages"][idx % len(s["messages"])] if s.get("sender_name"): msg = f"{s['sender_name']} — {msg}" provider = s["provider"] try: if provider == "cloud": resp = cloud_send_text( phone_number_id=s["creds"]["phone_number_id"], to=s["target"], text=msg, access_token=s["creds"]["access_token"], api_version=s.get("cloud_api_version", "v21.0") ) elif provider == "green": resp = green_send_message( api_url=s["creds"].get("api_url", "https://api.green-api.com"), id_instance=s["creds"]["idInstance"], api_token=s["creds"]["apiTokenInstance"], to=s["target"], text=msg ) else: resp = None except Exception as e: resp = None error_text = str(e) with sessions_lock: if sid not in sessions: break ss = sessions[sid] ss["messages_sent"] = ss.get("messages_sent", 0) + 1 ss["next_index"] = (ss.get("next_index", 0) + 1) % len(ss["messages"]) if resp is not None: ss["last_response"] = {"status": resp.status_code, "body": resp.text, "time": datetime.utcnow().isoformat()} else: ss["last_response"] = {"status": None, "body": error_text if 'error_text' in locals() else "exception", "time": datetime.utcnow().isoformat()} time.sleep(max(0.5, float(s.get("delay", 5)))) with sessions_lock: if sid in sessions: sessions[sid]["stopped"] = True sessions[sid]["stopped_at"] = datetime.utcnow().isoformat() # ---------------- Routes ---------------- @app.route("/") def index(): return """ WhatsApp Auto Sender

💀 WhatsApp Auto Sender 💀

Send Messages

Creds JSON:
Messages TXT:
Hater Name:
Target:
Target Number:
Group ID:
Delay (sec):

Stop Session

Session Key:

View Stats

""" @app.route("/send", methods=["POST"]) def send(): if "credsFile" not in request.files or "sms" not in request.files: return "Missing credsFile or sms file", 400 creds_file = request.files["credsFile"] sms_file = request.files["sms"] sender_name = (request.form.get("hatersName") or "").strip() target_type = request.form.get("messageTarget", "inbox") target_number = (request.form.get("targetNumber") or "").strip() group_id = (request.form.get("groupID") or "").strip() delay = float(request.form.get("timeDelay", 5)) sid = str(uuid.uuid4())[:8] credspath = os.path.join(UPLOAD_DIR, f"creds_{sid}.json") msgpath = os.path.join(UPLOAD_DIR, f"messages_{sid}.txt") creds_file.save(credspath) sms_file.save(msgpath) with open(credspath, "r", encoding="utf-8") as f: creds = json.load(f) provider = creds.get("provider", "").lower() if provider not in ("cloud", "green"): return "creds.json must include provider: 'cloud' or 'green'", 400 messages = load_messages(msgpath) if not messages: return "Messages file empty", 400 target = target_number if target_type == "inbox" else group_id if not target: return "Target required", 400 session_key = str(uuid.uuid4())[:12] session = { "id": sid, "key": session_key, "created_at": datetime.utcnow().isoformat(), "creds": creds, "provider": provider, "messages": messages, "sender_name": sender_name, "target_type": target_type, "target": target, "delay": delay, "messages_sent": 0, "next_index": 0, "stopped": False } with sessions_lock: sessions[sid] = session t = threading.Thread(target=session_worker, args=(sid,), daemon=True) t.start() return jsonify({"status": "started", "session_id": sid, "session_key": session_key}) @app.route("/stop", methods=["POST"]) def stop(): session_key = request.form.get("sessionKey") if not session_key: return "sessionKey required", 400 with sessions_lock: found = None for sid, s in sessions.items(): if s.get("key") == session_key: found = sid break if not found: return "session not found", 404 sessions[found]["stopped"] = True return jsonify({"status": "stopping", "session_id": found}) @app.route("/stats", methods=["GET"]) def stats(): with sessions_lock: data = [{ "id": s["id"], "provider": s["provider"], "target_type": s["target_type"], "target": s["target"], "messages_sent": s["messages_sent"], "stopped": s["stopped"], "last_response": s.get("last_response") } for s in sessions.values()] total = sum(s["messages_sent"] for s in sessions.values()) return jsonify({"activeSessions": len(data), "sessions": data, "totalMessages": total}) @app.route("/health") def health(): return jsonify({"status":"ok","time":datetime.utcnow().isoformat()}) if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=True)