#!/usr/bin/env python3 """ Sistema de cliques automáticos baseado em reconhecimento de imagem. Clique no botão especificado por 'botaoparaclicar.png' a cada X segundos, apenas dentro do horário configurado no .env. """ import os import sys import time import random import re import cv2 import numpy as np import pyautogui from datetime import datetime from dotenv import load_dotenv load_dotenv() LARGURA_TERMINAL = int(os.getenv("LARGURA_TERMINAL", "60")) INTERVALO_MINIMO_CLIQUE = int(os.getenv("INTERVALO_MINIMO_CLIQUE", "10")) INTERVALO_MAXIMO_CLIQUE = int(os.getenv("INTERVALO_MAXIMO_CLIQUE", "30")) INTERVALO_PRIMEIRO_CLIQUE = int(os.getenv("INTERVALO_PRIMEIRO_CLIQUE", "10")) MAXIMO_CLIQUES_POR_SESSAO = int(os.getenv("MAXIMO_CLIQUES_POR_SESSAO", "20")) INTERVALO_ENTRE_SESSOES = int(os.getenv("INTERVALO_ENTRE_SESSOES", "60")) INTERVALO_CLIQUE_ESPERA = int(os.getenv("INTERVALO_CLIQUE_ESPERA", "900")) MAXIMO_FALHAS = int(os.getenv("MAXIMO_FALHAS", "5")) HORA_INICIO = os.getenv("HORA_INICIO", "09:00") HORA_FIM = os.getenv("HORA_FIM", "18:00") CONFIANCA = float(os.getenv("CONFIANCA", "0.8")) IMAGEM_BOTAO = os.path.join(os.path.dirname(os.path.abspath(__file__)), "botaoparaclicar.png") LOG_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "log.txt") pyautogui.FAILSAFE = True RST = "\033[0m" BOLD = "\033[1m" C_TITLE = "\033[96m" C_GREEN = "\033[92m" C_YELLOW = "\033[93m" C_RED = "\033[91m" C_MAG = "\033[95m" C_WHITE = "\033[97m" C_GRAY = "\033[90m" C_CYAN = "\033[36m" _RE_ANSI = re.compile(r"\x1b\[[0-9;]*m") def vis_largura(texto: str) -> int: sem_ansi = _RE_ANSI.sub("", texto) emojis = re.findall( r"[\U0001F300-\U0001FAFF" r"\U00002702-\U000027B0" r"\U0000FE0F" r"\U0001F1E0-\U0001F1FF" r"\U00002600-\U000026FF" r"\U00002700-\U000027BF" r"]+", sem_ansi, flags=re.UNICODE, ) ajuste_emoji = sum((2 - len(e)) for e in emojis) return len(sem_ansi) + ajuste_emoji def terminal_width() -> int: return LARGURA_TERMINAL def largura() -> int: return terminal_width() def center(text: str, pre: str = "", pos: str = "") -> str: w = largura() - vis_largura(pre) - vis_largura(pos) return pre + text.center(w) + pos def banner() -> None: print() print(center(" 🤖 AUTO-CLICADOR 🤖 ", C_TITLE + BOLD)) print(center("Sistema de Cliques Automáticos", C_TITLE)) print() def painel_config() -> None: itens = [ (C_GRAY, "Largura do terminal", f"{LARGURA_TERMINAL} colunas"), (C_GREEN, "Intervalo mínimo entre cliques", f"{INTERVALO_MINIMO_CLIQUE}s"), (C_GREEN, "Intervalo máximo entre cliques", f"{INTERVALO_MAXIMO_CLIQUE}s"), (C_CYAN, "Espera antes do 1º clique", f"{INTERVALO_PRIMEIRO_CLIQUE}s"), (C_YELLOW, "Máximo de cliques por sessão", str(MAXIMO_CLIQUES_POR_SESSAO)), (C_YELLOW, "Intervalo entre sessões", f"{INTERVALO_ENTRE_SESSOES}s"), (C_CYAN, "Clique de espera entre sessões", f"{INTERVALO_CLIQUE_ESPERA}s"), (C_MAG, "Máximo de falhas", str(MAXIMO_FALHAS)), (C_WHITE, "Horário de funcionamento", f"{HORA_INICIO} às {HORA_FIM}"), (C_GRAY, "Confiança mínima", str(CONFIANCA)), ] print(center(" ⚙ CONFIGURAÇÃO", C_TITLE + BOLD)) print() labels_sem_cor = [_RE_ANSI.sub("", f" {label}") for _, label, _ in itens] max_label_vis = max(vis_largura(l) for l in labels_sem_cor) largura_label = max(max_label_vis, 1) for cor, label, valor in itens: label_raw = f" {label}" label_vis = vis_largura(label_raw) padding_label = max(1, largura_label - label_vis + 2) print( cor + label_raw + RST + " " * padding_label + C_WHITE + str(valor) + RST ) print() def cabecalho_sessao(num: int) -> None: print() print(C_MAG + BOLD + f" 🔄 SESSÃO {num} 🔄" + RST) print() def rodape_clique() -> None: w = largura() inner_w = w - 4 barra_preenchida = max(1, int(inner_w * 0.4)) barra_vazia = inner_w - barra_preenchida barra = C_GREEN + "█" * barra_preenchida + C_GRAY + "░" * barra_vazia + RST print(" " + barra) def log(mensagem: str, cor: str = C_WHITE) -> None: agora = datetime.now() ts = agora.strftime("%H:%M:%S") ts_raw = f"[{ts}] " ts_color = C_GRAY linha_terminal = ( " " + ts_color + ts_raw + RST + cor + mensagem + RST ) print(linha_terminal) try: with open(LOG_FILE, "a", encoding="utf-8") as f: ts_full = agora.strftime("%Y-%m-%d %H:%M:%S") f.write(f"[{ts_full}] {_RE_ANSI.sub('', mensagem)}\n") except Exception: pass def dentro_horario(hora_inicio: str, hora_fim: str) -> bool: agora = datetime.now().time() hi = datetime.strptime(hora_inicio, "%H:%M").time() hf = datetime.strptime(hora_fim, "%H:%M").time() return hi <= agora <= hf def encontrar_botao(imagem_path: str, confianca: float = 0.8): if not os.path.isfile(imagem_path): log(f"ERRO: Imagem '{imagem_path}' não encontrada.", C_RED) return None screenshot = pyautogui.screenshot() screenshot_np = np.array(screenshot) screenshot_cv = cv2.cvtColor(screenshot_np, cv2.COLOR_RGB2BGR) template = cv2.imread(imagem_path, cv2.IMREAD_UNCHANGED) if template is None: log(f"ERRO: Não foi possível carregar '{imagem_path}'.", C_RED) return None if template.shape[2] == 4: template_bgr = cv2.cvtColor(template, cv2.COLOR_BGRA2BGR) alpha = template[:, :, 3] mascara = alpha.astype(np.uint8) else: template_bgr = template mascara = None resultado = cv2.matchTemplate(screenshot_cv, template_bgr, cv2.TM_CCOEFF_NORMED, mask=mascara) _, max_val, _, max_loc = cv2.minMaxLoc(resultado) if max_val >= confianca: h, w2 = template_bgr.shape[:2] centro_x = max_loc[0] + w2 // 2 centro_y = max_loc[1] + h // 2 log( f"Botão encontrado! Confiança: {max_val:.2f} | Pos: ({centro_x}, {centro_y})", C_GREEN, ) return (centro_x, centro_y) else: log( f"Botão NÃO encontrado. Confiança: {max_val:.2f} (mín: {confianca})", C_RED, ) return None def gerar_intervalo_aleatorio(intervalo_min: int, intervalo_max: int) -> int: return random.randint(intervalo_min, intervalo_max) def main() -> None: banner() painel_config() print(center(" 🚀 Iniciando sistema... ", C_TITLE + BOLD)) print() log("Pressione CTRL+C para parar.", C_YELLOW) print() primeiro_clique = True falhas_consecutivas = 0 total_cliques = 0 cliques_na_sessao = 0 numero_sessao = 1 try: while True: agora = datetime.now() if not dentro_horario(HORA_INICIO, HORA_FIM): log( f"[Sessão {numero_sessao}] Fora do horário permitido ({agora.strftime('%H:%M:%S')}).", C_YELLOW, ) log(f"Pausando até {HORA_INICIO}...", C_GRAY) falhas_consecutivas = 0 cliques_na_sessao = 0 time.sleep(30) continue if primeiro_clique: cabecalho_sessao(numero_sessao) log( f"Aguardando {INTERVALO_PRIMEIRO_CLIQUE}s antes do primeiro clique...", C_CYAN, ) time.sleep(INTERVALO_PRIMEIRO_CLIQUE) primeiro_clique = False posicao = encontrar_botao(IMAGEM_BOTAO, CONFIANCA) if posicao: x, y = posicao log( f"[Sessão {numero_sessao}] Clicando em ({x}, {y})...", C_GREEN, ) pyautogui.click(x, y) total_cliques += 1 cliques_na_sessao += 1 log( f"Clique #{cliques_na_sessao}/{MAXIMO_CLIQUES_POR_SESSAO} | Total geral: {total_cliques}", C_GREEN + BOLD, ) falhas_consecutivas = 0 rodape_clique() else: falhas_consecutivas += 1 log( f"[Sessão {numero_sessao}] Botão não encontrado. " f"Falhas: {falhas_consecutivas} | Total: {total_cliques}", C_RED, ) log( f"[Sessão {numero_sessao}] Re-tentando em {INTERVALO_MINIMO_CLIQUE}s...", C_YELLOW, ) time.sleep(INTERVALO_MINIMO_CLIQUE) continue if cliques_na_sessao >= MAXIMO_CLIQUES_POR_SESSAO: log( f"--- Sessão {numero_sessao} finalizada: {cliques_na_sessao} cliques ---", C_MAG + BOLD, ) numero_sessao += 1 cliques_na_sessao = 0 log( f"Aguardando {INTERVALO_ENTRE_SESSOES}s até a Sessão {numero_sessao}...", C_YELLOW, ) tempo_restante = INTERVALO_ENTRE_SESSOES while tempo_restante > 0: tempo_ate_clique = min(tempo_restante, INTERVALO_CLIQUE_ESPERA) log( f"[Espera] Dormindo {tempo_ate_clique}s (restam {tempo_restante}s)...", C_GRAY, ) time.sleep(tempo_ate_clique) tempo_restante -= tempo_ate_clique if tempo_restante <= 0: break log( f"[Espera] Executando clique de keep-alive (restam {tempo_restante}s)...", C_CYAN, ) pos_espera = encontrar_botao(IMAGEM_BOTAO, CONFIANCA) if pos_espera: px, py = pos_espera log( f"[Espera] Clicando em ({px}, {py})...", C_GREEN, ) pyautogui.click(px, py) else: log("[Espera] Botão não encontrado no clique de keep-alive.", C_RED) primeiro_clique = True continue intervalo = gerar_intervalo_aleatorio( INTERVALO_MINIMO_CLIQUE, INTERVALO_MAXIMO_CLIQUE ) log( f"[Sessão {numero_sessao}] Aguardando {intervalo}s até o próximo ciclo...", C_CYAN, ) time.sleep(intervalo) except KeyboardInterrupt: print() print(C_RED + BOLD + center(" 🛑 INTERROMPIDO PELO USUÁRIO 🛑 ") + RST) print() log(f"Total de cliques realizados: {total_cliques}", C_YELLOW) if __name__ == "__main__": main()