Hey! Can you make my python roblox autoclicker more reliable?
All this code does is click a roblox window every 600s, but sometimes it just skips because of windows errors - some, ironically erroring with success.
Hey, I have premade a roblox window clicker, but it is somewhat unreliable. Arteficial delays will not suffice. Can you take a look at it and have your spin on it?
import pygetwindow as gw
import pyautogui
import time
import logging
import threading
from tkinter import Tk, Label, StringVar
from screeninfo import get_monitors

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def is_window_fullscreen(window):
"""
Checks if the specified window is in full-screen mode.
"""
screen = pyautogui.size()
x, y, width, height = window.box
return (width, height) == (screen.width, screen.height)

def get_secondary_monitor():
"""
Returns the secondary monitor if available, else returns None.
"""
monitors = get_monitors()
return monitors[1] if len(monitors) > 1 else None

def bring_window_to_foreground(window, secondary_monitor):
"""
Brings the specified window to the foreground on the secondary monitor and unminimizes it if needed.
"""
if window.isMinimized: # Check if the window is minimized
window.restore() # Unminimize the window
if secondary_monitor:
window.moveTo(secondary_monitor.x, secondary_monitor.y) # Move to secondary monitor
window.activate() # Activate the window

def is_window_on_secondary_monitor(window, secondary_monitor):
"""
Checks if the window is on the secondary monitor.
"""
if not secondary_monitor:
return False
x, y, width, height = window.box
return (secondary_monitor.x <= x < secondary_monitor.x + secondary_monitor.width and
secondary_monitor.y <= y < secondary_monitor.y + secondary_monitor.height)

def click_windows(title, excluded_apps, click_count, delay_between_clicks, loop_delay, update_clicks_callback):
total_clicks = 0
pyautogui.FAILSAFE = False
secondary_monitor = get_secondary_monitor()

while True:
# Store the current mouse position
initial_mouse_position = pyautogui.position()

windows_to_click = [win for win in gw.getAllWindows() if title in win.title and not any(app in win.title for app in excluded_apps)]

for win in windows_to_click:
try:
logging.info(f"Processing window: {win.title}")

if win.isMinimized or not win.isActive:
logging.info("Window is minimized or not active, maximizing and bringing to foreground.")
bring_window_to_foreground(win, secondary_monitor)
time.sleep(0.1) # Wait a bit for the window to respond

if not is_window_on_secondary_monitor(win, secondary_monitor):
logging.info("Window is not on secondary monitor, skipping.")
continue

if is_window_fullscreen(win):
logging.info("Window is fullscreen, skipping.")
continue

x, y, width, height = win.box
click_x, click_y = x + width / 2, y + height / 2 # Center of the window

for _ in range(click_count):
pyautogui.moveTo(click_x, click_y, duration=0.05) # Smooth mouse movement
pyautogui.click()
time.sleep(delay_between_clicks)
total_clicks += 1
if update_clicks_callback:
update_clicks_callback(total_clicks)

logging.info(f"Finished clicking on window {win.title}, minimizing.")
win.minimize()

except Exception as e:
logging.error(f"Could not click on window {win.title}: {e}")

# Move the mouse back to its original position
pyautogui.moveTo(initial_mouse_position)

time.sleep(loop_delay)
if update_clicks_callback:
update_clicks_callback(total_clicks)

def start_clicking_thread(*args, **kwargs):
threading.Thread(target=click_windows, args=args, kwargs=kwargs, daemon=True).start()

def setup_gui():
root = Tk()
root.title("Click Tracker")

click_count_var = StringVar(root, value="Total Clicks: 0")
next_click_time_var = StringVar(root, value="Next Click: N/A")

def update_clicks(total_clicks=0):
click_count_var.set(f"Total Clicks: {total_clicks}")

def update_timer():
while True:
remaining_time = int(loop_delay - (time.time() % loop_delay))
next_click_time_var.set(f"Next Click in: {remaining_time}s")
time.sleep(1)

Label(root, textvariable=click_count_var).pack()
Label(root, textvariable=next_click_time_var).pack()

# Define the loop delay here
loop_delay = 600

start_clicking_thread("Roblox", ["Google Chrome", "Edge", "Mozilla Firefox", "Discord", "Roblox Studio"], click_count=5, delay_between_clicks=0.25, loop_delay=loop_delay, update_clicks_callback=update_clicks)
threading.Thread(target=update_timer, daemon=True).start()

root.mainloop()

if name == "main":
setup_gui()