Guest User

windice bot - mybot.py

a guest
Oct 11th, 2026
3
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.94 KB | Source Code | 0 0
  1. # ---------------------------------------------------------
  2. # Author     : domdom
  3. # Project    : Windice Dice Bot
  4. # License    : Free to use and modify for Windice community members
  5. # API Documentation : https://windice.org/docsapi
  6. # -----------------------------------------------------------
  7. import re
  8. import time
  9. import requests
  10. import threading
  11. import winsound
  12. import tkinter as tk
  13. from tkinter import ttk, messagebox
  14.  
  15. # Global flag to control the background betting thread state
  16. is_running = False
  17. HOUSE_EDGE = 2.0
  18.  
  19. # ===========================================================
  20. # 1. WINDICE API FUNCTIONS (Direct Token / Raw Header Authorization)
  21. # ===========================================================
  22.  
  23. BASE_URL = "https://windice.org"
  24. # >>> REPLACE WITH YOUR ACTUAL WINDICE API KEY <<<
  25. API_KEY = "YOUR API KEY HERE".strip()
  26.  
  27. # HTTP headers required for API authentication
  28. HEADERS = {
  29.     "Authorization": API_KEY,
  30.     "Content-Type": "application/json"
  31. }
  32.  
  33. def get_user_info_api():
  34.     """Fetch user account details and coin balances from the API."""
  35.     url = f"{BASE_URL}/api/v1/api/user"
  36.     try:
  37.         # request information to user api using requests.get()
  38.         response = requests.get(url, headers=HEADERS, timeout=10)
  39.         return response.json()
  40.     except Exception as e:
  41.         return {"status": "error", "message": str(e)}
  42.  
  43. def place_roll_api(currency, bet_amount, game_type, min_range, max_range):
  44.     """Send a dice roll bet request to the API."""
  45.     url = f"{BASE_URL}/api/v1/api/roll"
  46.     payload = {
  47.         "curr": str(currency).lower(),
  48.         "bet": float(bet_amount),
  49.         "game": str(game_type),
  50.         "low": int(min_range),
  51.         "high": int(max_range)
  52.     }
  53.     try:
  54.         # send a request to the roll api with paramters using requests.post()
  55.         response = requests.post(url, json=payload, headers=HEADERS, timeout=10)
  56.         return response.json()
  57.     except Exception as e:
  58.         return {"status": "error", "message": str(e)}
  59.  
  60.  
  61. # ==============================================================================
  62. # 2. GUI LOGIC & EVENT HANDLERS
  63. # ==============================================================================
  64.  
  65. def update_account_info():    
  66.     """Fetch user profile and update balance labels asynchronously."""
  67.     selected_coin = combo_coins.get().strip().lower()
  68.    
  69.     def fetch():
  70.         res = get_user_info_api()
  71.        
  72.         # If API successfully returns user data
  73.         if res.get("status") == "success":
  74.             data = res.get("data", {})
  75.             username = data.get("username", "Unknown")
  76.             balances = data.get("balance", {})
  77.            
  78.             coin_balance = 0.0
  79.             if isinstance(balances, dict):
  80.                 coin_balance = balances.get(selected_coin, 0.0)
  81.                                
  82.  
  83.             # Update GUI elements safely on the main thread
  84.             def apply_ui():
  85.                 lbl_username_val.config(text=username)
  86.                 lbl_balance_val.config(text=f"{float(coin_balance):.8f} {selected_coin.upper()}")
  87.  
  88.             root.after(0, apply_ui)
  89.         else:
  90.             # If authentication or request fails
  91.             def apply_err():
  92.                 lbl_username_val.config(text="Auth Failed")
  93.                 lbl_balance_val.config(text="0.00000000")
  94.             root.after(0, apply_err)
  95.  
  96.     # Run network request in a background thread to prevent GUI freezing
  97.     threading.Thread(target=fetch, daemon=True).start()
  98.  
  99.  
  100. def on_coin_change(event=None):    
  101.     """Reset bet size and refresh balance when a new coin is selected."""
  102.     entry_bet_size.delete(0, tk.END)
  103.     entry_bet_size.insert(0, "0.00000000")
  104.     update_account_info()
  105.  
  106.  
  107. def calculate_payout(event=None):
  108.     """Calculate potential multiplier payout based on win chance and house edge."""
  109.     try:
  110.         r_min = float(entry_range_min.get())
  111.         r_max = float(entry_range_max.get())
  112.  
  113.         win_chance = (r_max - r_min) + 1.0
  114.  
  115.         entry_payout.config(state="normal")
  116.         entry_payout.delete(0, tk.END)
  117.  
  118.         # Check if win chance is within valid platform limits and range order is correct
  119.         if 1.0 <= win_chance <= 10000.0 and r_max >= r_min:            
  120.             rtp = 100.0 - HOUSE_EDGE
  121.             payout = (rtp * 100.0) / win_chance
  122.             entry_payout.insert(0, f"{payout:.4f}")
  123.         else:
  124.             entry_payout.insert(0, "Invalid")
  125.  
  126.         entry_payout.config(state="readonly")
  127.  
  128.     except ValueError:
  129.         entry_payout.config(state="normal")
  130.         entry_payout.delete(0, tk.END)
  131.         entry_payout.config(state="readonly")
  132.  
  133.  
  134. def update_table(bet_id, roll, target, profit, status):
  135.     """Insert a new roll result row into the Treeview table with color tags."""
  136.     item_id = tree.insert("", 0, values=(bet_id, roll, target, profit, status))
  137.    
  138.     # Apply green color for wins, red for losses
  139.     if status == "WIN":
  140.         tree.item(item_id, tags=("win_tag",))
  141.     else:
  142.         tree.item(item_id, tags=("loss_tag",))
  143.  
  144.  
  145. def clear_table():
  146.     """Clear all records from the history table."""
  147.     for item in tree.get_children():
  148.         tree.delete(item)
  149.  
  150.  
  151. def extract_minimum_bet(error_msg):
  152.     """Parse minimum bet value from API error messages using regex."""
  153.     match = re.search(r"Minimum bet\s+(\d+(?:\.\d+)?)", error_msg, re.IGNORECASE)
  154.     if match:
  155.         return match.group(1)
  156.     return None
  157.  
  158.  
  159. def play_victory_chime():
  160.     """Play custom win audio alert"""
  161.     try:        
  162.         winsound.PlaySound("mybot-win.wav", winsound.SND_FILENAME | winsound.SND_ASYNC)
  163.     except Exception:        
  164.         winsound.MessageBeep(winsound.MB_ICONASTERISK)
  165.  
  166.        
  167. def betting_loop():
  168.     """Main automated betting loop running in a background thread."""
  169.     global is_running
  170.     try:
  171.         # Lock configuration inputs while bot is running
  172.         combo_coins.config(state="disabled")
  173.         entry_bet_size.config(state="disabled")
  174.        
  175.         # Pass all input field values to variables
  176.         total_bets = int(entry_num_bets.get())
  177.         bet_size = float(entry_bet_size.get())
  178.         currency = combo_coins.get()
  179.         r_min = float(entry_range_min.get())
  180.         r_max = float(entry_range_max.get())
  181.  
  182.         t_min_str = entry_target_min.get().strip()
  183.         t_max_str = entry_target_max.get().strip()
  184.         has_target = bool(t_min_str and t_max_str)
  185.         t_min = float(t_min_str) if has_target else None
  186.         t_max = float(t_max_str) if has_target else None
  187.        
  188.         # --- Range Validation ---
  189.         if r_min > r_max:
  190.             root.after(0, lambda: messagebox.showerror("Error", "Min Range cannot be greater than Max Range!"))
  191.             stop_betting()
  192.             return
  193.            
  194.     except ValueError:
  195.         root.after(0, lambda: messagebox.showerror("Error", "Please check your numeric inputs!"))
  196.         stop_betting()
  197.         return
  198.  
  199.     # Loop through the specified number of bets
  200.     for i in range(1, total_bets + 1):
  201.         # Stop loop immediately if user clicked Stop button
  202.         if not is_running:
  203.             break
  204.        
  205.         res = place_roll_api(
  206.             currency=currency,
  207.             bet_amount=bet_size,
  208.             game_type="in",
  209.             min_range=r_min,
  210.             max_range=r_max
  211.         )
  212.  
  213.         # If roll request succeeds
  214.         if res.get("status") == "success":
  215.             data = res.get("data", {})
  216.             roll_result = data.get("result", 0)
  217.             win_amount = data.get("win", 0.0)
  218.  
  219.             is_win = (win_amount > 0)
  220.             profit = (win_amount - bet_size) if is_win else -bet_size
  221.             status = "WIN" if is_win else "LOSS"
  222.             is_target_hit = has_target and (t_min <= roll_result <= t_max)
  223.  
  224.             # Update table and account balance on GUI thread
  225.             root.after(0, update_table, i, roll_result, "YES" if is_target_hit else "-", f"{profit:+.8f}", status)
  226.             root.after(0, update_account_info)
  227.  
  228.             # Handle target hit events & audio notification
  229.             if is_target_hit:
  230.                 play_victory_chime()
  231.                
  232.                 should_continue = [True]
  233.                 event_done = threading.Event()
  234.  
  235.                 def ask_user(r_res):
  236.                     answer = messagebox.askyesno(
  237.                         "Target Hit!",
  238.                         f"Target hit detected on roll: {r_res}\n\nDo you want to CONTINUE betting?"
  239.                     )
  240.                     should_continue[0] = answer
  241.                     event_done.set()
  242.  
  243.                 root.after(0, ask_user, roll_result)
  244.                 event_done.wait()
  245.  
  246.                 # Stop if user clicks No on confirmation dialog
  247.                 if not should_continue[0]:
  248.                     is_running = False
  249.                     break
  250.  
  251.         else:
  252.             # If roll request returns an error from server
  253.             err_msg = res.get("message", "API Request Failed")
  254.            
  255.             # Auto-detect minimum bet if error matches platform rules
  256.             extracted_min = extract_minimum_bet(err_msg)
  257.             if extracted_min and bet_size == 0:
  258.                 def autofill_bet(val):
  259.                     entry_bet_size.config(state="normal")
  260.                     entry_bet_size.delete(0, tk.END)
  261.                     entry_bet_size.insert(0, val)
  262.                     entry_bet_size.config(state="disabled")
  263.                     messagebox.showinfo("Minimum Bet Set", f"Auto detected minimum bet for {currency.upper()}: {val}")
  264.  
  265.                 root.after(0, autofill_bet, extracted_min)
  266.             else:
  267.                 # Show generic API error popup
  268.                 root.after(0, lambda m=err_msg: messagebox.showerror("API Error", m))
  269.  
  270.             break
  271.  
  272.         time.sleep(0.25)  # Short delay between bets in seconds
  273.  
  274.     root.after(0, stop_betting)
  275.  
  276.  
  277. def start_betting():
  278.     """Start the automated betting worker thread."""
  279.     global is_running
  280.     clear_table()
  281.     is_running = True
  282.     btn_start.config(state="disabled")
  283.     btn_stop.config(state="normal")
  284.     threading.Thread(target=betting_loop, daemon=True).start()
  285.  
  286.  
  287. def stop_betting():
  288.     """Stop active betting and restore GUI element states."""
  289.     global is_running
  290.     is_running = False
  291.     btn_start.config(state="normal")
  292.     btn_stop.config(state="disabled")
  293.     combo_coins.config(state="readonly")
  294.     entry_bet_size.config(state="normal")
  295.  
  296.  
  297. # ==============================================================================
  298. # 3. TKINTER GUI LAYOUT
  299. # ==============================================================================
  300.  
  301. root = tk.Tk()
  302. root.title("Windice Simple Betting Bot (Tutorial)")
  303. root.geometry("600x600")
  304. root.resizable(False, False)
  305.  
  306. # Main Top Container Frame
  307. top_container = ttk.Frame(root, padding=5)
  308. top_container.pack(fill="x", padx=5, pady=5)
  309.  
  310. # --- Left Column: Betting Settings Panel ---
  311. input_frame = ttk.LabelFrame(top_container, text=" Betting Settings ", padding=10)
  312. input_frame.pack(side="left", fill="both", expand=True, padx=5)
  313.  
  314. # Coins Dropdown selection
  315. ttk.Label(input_frame, text="Coins:", width=14).grid(row=0, column=0, sticky="w", pady=4)
  316. combo_coins = ttk.Combobox(input_frame, values=["WIN", "USDT", "BTC", "ETH", "TRX", "LTC", "DOGE", "BCH",
  317.                     "XRP", "BNB", "TON"], state="readonly", width=14)
  318. combo_coins.current(0)  
  319. combo_coins.grid(row=0, column=1, columnspan=3, sticky="ew", pady=4)
  320. combo_coins.bind("<<ComboboxSelected>>", on_coin_change)
  321.  
  322. # Bet Size Input field
  323. ttk.Label(input_frame, text="Bet Size:").grid(row=1, column=0, sticky="w", pady=4)
  324. entry_bet_size = ttk.Entry(input_frame, width=16)
  325. entry_bet_size.insert(0, "0.00000000")
  326. entry_bet_size.grid(row=1, column=1, columnspan=3, sticky="ew", pady=4)
  327.  
  328. # Range (Min - Max) Inputs
  329. ttk.Label(input_frame, text="Range:").grid(row=2, column=0, sticky="w", pady=4)
  330. entry_range_min = ttk.Entry(input_frame, width=7)
  331. entry_range_min.insert(0, "0")
  332. entry_range_min.grid(row=2, column=1, pady=4)
  333.  
  334. ttk.Label(input_frame, text="-").grid(row=2, column=2, pady=4)
  335.  
  336. entry_range_max = ttk.Entry(input_frame, width=7)
  337. entry_range_max.insert(0, "4999")
  338. entry_range_max.grid(row=2, column=3, pady=4)
  339.  
  340. entry_range_min.bind("<KeyRelease>", calculate_payout)
  341. entry_range_max.bind("<KeyRelease>", calculate_payout)
  342.  
  343. # Calculated Payout Display (Readonly)
  344. ttk.Label(input_frame, text="Payout:").grid(row=3, column=0, sticky="w", pady=4)
  345. entry_payout = ttk.Entry(input_frame, state="readonly", width=16)
  346. entry_payout.grid(row=3, column=1, columnspan=3, sticky="ew", pady=4)
  347.  
  348. # Target Roll Range Inputs
  349. ttk.Label(input_frame, text="Target:").grid(row=4, column=0, sticky="w", pady=4)
  350. entry_target_min = ttk.Entry(input_frame, width=7)
  351. entry_target_min.grid(row=4, column=1, pady=4)
  352.  
  353. ttk.Label(input_frame, text="-").grid(row=4, column=2, pady=4)
  354.  
  355. entry_target_max = ttk.Entry(input_frame, width=7)
  356. entry_target_max.grid(row=4, column=3, pady=4)
  357.  
  358. # Number of Bets Input
  359. ttk.Label(input_frame, text="No. Bets:").grid(row=5, column=0, sticky="w", pady=4)
  360. entry_num_bets = ttk.Entry(input_frame, width=16)
  361. entry_num_bets.insert(0, "10")
  362. entry_num_bets.grid(row=5, column=1, columnspan=3, sticky="ew", pady=4)
  363.  
  364.  
  365. # --- Right Column: Account Information Panel ---
  366. account_frame = ttk.LabelFrame(top_container, text=" Account Info ", padding=10)
  367. account_frame.pack(side="right", fill="both", expand=True, padx=5)
  368.  
  369. ttk.Label(account_frame, text="Username:", font=("Helvetica", 9, "bold")).pack(anchor="w", pady=(5, 2))
  370. lbl_username_val = ttk.Label(account_frame, text="Loading...", font=("Helvetica", 10), foreground="#0056b3")
  371. lbl_username_val.pack(anchor="w", pady=(0, 15))
  372.  
  373. ttk.Label(account_frame, text="Balance:", font=("Helvetica", 9, "bold")).pack(anchor="w", pady=(5, 2))
  374. lbl_balance_val = ttk.Label(account_frame, text="0.00000000 WIN", font=("Helvetica", 11, "bold"), foreground="#2e7d32")
  375. lbl_balance_val.pack(anchor="w", pady=(0, 10))
  376.  
  377. # Initialize layout data
  378. calculate_payout()
  379. update_account_info()
  380.  
  381. # --- Control Buttons Section (Start / Stop) ---
  382. control_frame = ttk.Frame(root, padding=5)
  383. control_frame.pack(fill="x", padx=10)
  384.  
  385. btn_start = ttk.Button(control_frame, text="[ Start ]", command=start_betting)
  386. btn_start.pack(side="left", expand=True, fill="x", padx=5)
  387.  
  388. btn_stop = ttk.Button(control_frame, text="[ Stop ]", command=stop_betting, state="disabled")
  389. btn_stop.pack(side="right", expand=True, fill="x", padx=5)
  390.  
  391. # --- History Table Section (Betting Results) ---
  392. table_frame = ttk.LabelFrame(root, text=" Betting Results ", padding=10)
  393. table_frame.pack(fill="both", expand=True, padx=10, pady=5)
  394.  
  395. style = ttk.Style()
  396.  
  397. style.configure("Treeview",
  398.                 background="white",
  399.                 fieldbackground="white",
  400.                 foreground="black",
  401.                 rowheight=25)
  402.  
  403. style.map("Treeview",
  404.           background=[('selected', '#347083')],
  405.           foreground=[('selected', 'white')])
  406.  
  407. tree = ttk.Treeview(table_frame, columns=("bet_id", "roll", "target", "profit", "status"),
  408.                     show="headings", height=10)
  409. tree.heading("bet_id", text="Bet ID")
  410. tree.heading("roll", text="Roll Result")
  411. tree.heading("target", text="Target Hit?")
  412. tree.heading("profit", text="Profit/Loss")
  413. tree.heading("status", text="Status")
  414.  
  415. tree.column("bet_id", width=70, anchor="center")
  416. tree.column("roll", width=80, anchor="center")
  417. tree.column("target", width=80, anchor="center")
  418. tree.column("profit", width=140, anchor="e")
  419. tree.column("status", width=70, anchor="center")
  420.  
  421. # Configure text colors for win/loss rows
  422. tree.tag_configure("win_tag", foreground="green")
  423. tree.tag_configure("loss_tag", foreground="red")
  424.  
  425. # Put a vertical scrollbar to the right side of the treeview
  426. scrollbar = ttk.Scrollbar(table_frame, orient="vertical", command=tree.yview)
  427. tree.configure(yscrollcommand=scrollbar.set)
  428.  
  429. tree.pack(side="left", fill="both", expand=True)
  430. scrollbar.pack(side="right", fill="y")
  431.  
  432. # Start the application event loop
  433. root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment