Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b375120fb2 | ||
|
|
8c4b3d9701 | ||
|
|
fa2be1a13c | ||
|
|
9b95ecd551 | ||
|
|
64f597c7ff | ||
|
|
ace146a8eb | ||
|
|
b9a99f8a37 | ||
|
|
1e8327d49f |
@@ -1,10 +1,30 @@
|
||||
LARGURA_TERMINAL=50
|
||||
INTERVALO_MINIMO_CLIQUE=15
|
||||
INTERVALO_MAXIMO_CLIQUE=30
|
||||
INTERVALO_MINIMO_CLIQUE=7
|
||||
INTERVALO_MAXIMO_CLIQUE=15
|
||||
INTERVALO_PRIMEIRO_CLIQUE=10
|
||||
MAXIMO_CLIQUES_POR_SESSAO=60
|
||||
INTERVALO_ENTRE_SESSOES=3600
|
||||
MAXIMO_FALHAS=3
|
||||
HORA_INICIO=09:00
|
||||
HORA_FIM=18:00
|
||||
MAXIMO_CLIQUES_POR_SESSAO=20
|
||||
INTERVALO_ENTRE_SESSOES=3300
|
||||
INTERVALO_CLIQUE_GLOBAL=900
|
||||
MAXIMO_FALHAS=10
|
||||
# Períodos de sessão (até 10). Deixe vazio para desativar um período.
|
||||
PERIODO_1_INICIO=01:00
|
||||
PERIODO_1_FIM=05:00
|
||||
PERIODO_2_INICIO=08:00
|
||||
PERIODO_2_FIM=10:00
|
||||
PERIODO_3_INICIO=12:00
|
||||
PERIODO_3_FIM=14:00
|
||||
PERIODO_4_INICIO=18:00
|
||||
PERIODO_4_FIM=20:00
|
||||
PERIODO_5_INICIO=
|
||||
PERIODO_5_FIM=
|
||||
PERIODO_6_INICIO=
|
||||
PERIODO_6_FIM=
|
||||
PERIODO_7_INICIO=
|
||||
PERIODO_7_FIM=
|
||||
PERIODO_8_INICIO=
|
||||
PERIODO_8_FIM=
|
||||
PERIODO_9_INICIO=
|
||||
PERIODO_9_FIM=
|
||||
PERIODO_10_INICIO=
|
||||
PERIODO_10_FIM=
|
||||
CONFIANCA=0.9
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
# AutoTigrinho 🤖
|
||||
|
||||
Sistema de cliques automáticos baseado em **reconhecimento de imagem**. O bot detecta visualmente um botão na tela e clica nele em intervalos configuráveis, respeitando horários e períodos definidos pelo usuário.
|
||||
|
||||
---
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Python 3.10+
|
||||
- Ambiente gráfico (DISPLAY) — em servidores headless o script usa Xvfb automaticamente
|
||||
|
||||
---
|
||||
|
||||
## Instalação
|
||||
|
||||
```bash
|
||||
./iniciar.sh
|
||||
```
|
||||
|
||||
O `iniciar.sh` executa automaticamente:
|
||||
|
||||
1. Verifica/cria o ambiente virtual (`venv/`)
|
||||
2. Instala/atualiza as dependências do `requirements.txt`
|
||||
3. Verifica a existência do `.env` e da imagem do botão
|
||||
4. Configura Xvfb se não houver ambiente gráfico
|
||||
5. Inicia o programa
|
||||
|
||||
---
|
||||
|
||||
## Configuração
|
||||
|
||||
Edite o arquivo `.env` para ajustar o comportamento:
|
||||
|
||||
### Intervalos de clique
|
||||
|
||||
| Variável | Descrição | Padrão |
|
||||
|---|---|---|
|
||||
| `INTERVALO_MINIMO_CLIQUE` | Tempo mínimo entre cliques durante uma sessão (s) | `10` |
|
||||
| `INTERVALO_MAXIMO_CLIQUE` | Tempo máximo entre cliques durante uma sessão (s) | `30` |
|
||||
| `INTERVALO_PRIMEIRO_CLIQUE` | Espera antes do primeiro clique de uma sessão (s) | `10` |
|
||||
| `INTERVALO_ENTRE_SESSOES` | Tempo de espera entre o fim de uma sessão e o início da próxima (s) | `60` |
|
||||
| `INTERVALO_CLIQUE_GLOBAL` | Intervalo para clique de keep-alive em qualquer estado (s) | `900` (15 min) |
|
||||
|
||||
### Controle de sessões
|
||||
|
||||
| Variável | Descrição | Padrão |
|
||||
|---|---|---|
|
||||
| `MAXIMO_CLIQUES_POR_SESSAO` | Número de cliques por sessão antes da pausa | `20` |
|
||||
| `MAXIMO_FALHAS` | Limite de falhas de detecção antes de encerrar | `5` |
|
||||
| `CONFIANCA` | Confiança mínima da correspondência de imagem (0.0 a 1.0) | `0.8` |
|
||||
|
||||
### Períodos de funcionamento
|
||||
|
||||
Até **10 períodos** podem ser configurados. Fora desses intervalos o sistema permanece ativo mas **não executa sessões**, apenas cliques de keep-alive.
|
||||
|
||||
```ini
|
||||
PERIODO_1_INICIO=09:00
|
||||
PERIODO_1_FIM=12:00
|
||||
|
||||
PERIODO_2_INICIO=14:00
|
||||
PERIODO_2_FIM=18:00
|
||||
|
||||
PERIODO_3_INICIO= ← deixe vazio para desativar
|
||||
PERIODO_3_FIM=
|
||||
```
|
||||
|
||||
### Aparência
|
||||
|
||||
| Variável | Descrição | Padrão |
|
||||
|---|---|---|
|
||||
| `LARGURA_TERMINAL` | Largura da interface em caracteres | `60` |
|
||||
|
||||
---
|
||||
|
||||
## Como funciona
|
||||
|
||||
### Sessões
|
||||
|
||||
Uma **sessão** é um bloco de até `MAXIMO_CLIQUES_POR_SESSAO` cliques consecutivos. Quando esse limite é atingido:
|
||||
|
||||
1. A sessão é finalizada e contabilizada
|
||||
2. O sistema entra em modo de espera por `INTERVALO_ENTRE_SESSOES` segundos
|
||||
3. A cada `INTERVALO_CLIQUE_GLOBAL` segundos durante essa espera, um **clique de keep-alive** é executado
|
||||
4. Ao terminar a espera, uma nova sessão é iniciada automaticamente
|
||||
|
||||
### Clique de keep-alive (global)
|
||||
|
||||
Independentemente do estado — **dentro ou fora dos períodos**, **durante espera entre sessões** — o sistema executa um clique de manutenção a cada `INTERVALO_CLIQUE_GLOBAL` segundos. Isso evita timeout de sessão em aplicações que exigem atividade contínua.
|
||||
|
||||
### Detecção de botão
|
||||
|
||||
O sistema usa **OpenCV** com template matching (`TM_CCOEFF_NORMED`) para encontrar a posição do botão na tela. O template deve ser fornecido como `botaoparaclicar.png` na raiz do projeto. Quando o botão não é encontrado, o sistema re-tenta automaticamente a cada `INTERVALO_MINIMO_CLIQUE` segundos até conseguir detectar e clicar.
|
||||
|
||||
### Controle de horário
|
||||
|
||||
- Dentro de um período configurado → sessões são executadas normalmente
|
||||
- Fora de todos os períodos → aguarda `INTERVALO_CLIQUE_GLOBAL` segundos, executa um clique de keep-alive e volta a verificar
|
||||
|
||||
### Modo headless (sem DISPLAY)
|
||||
|
||||
Em servidores ou máquinas sem ambiente gráfico, o `iniciar.sh` tenta instalar e usar o **Xvfb** (X virtual framebuffer) automaticamente, sem necessidade de sudo.
|
||||
|
||||
---
|
||||
|
||||
## Estrutura de arquivos
|
||||
|
||||
```
|
||||
AutoTigrinho/app/
|
||||
├── main.py # Código principal
|
||||
├── iniciar.sh # Script de inicialização e setup
|
||||
├── .env # Configurações
|
||||
├── botaoparaclicar.png # Imagem do botão (template)
|
||||
├── requirements.txt # Dependências Python
|
||||
├── log.txt # Log de execução
|
||||
└── venv/ # Ambiente virtual Python
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Log de execução
|
||||
|
||||
Todas as ações são registradas em `log.txt` com timestamp:
|
||||
|
||||
```
|
||||
[2026-09-09 15:00:00] Sessão 1 iniciada
|
||||
[2026-09-09 15:00:10] Clicando em (450, 320)...
|
||||
[2026-09-09 15:01:15] Aguardando 15s até o próximo ciclo...
|
||||
[2026-09-09 15:05:00] Sessão 1 finalizada: 20 cliques
|
||||
[2026-09-09 15:05:00] Aguardando 900s até a Sessão 2...
|
||||
[2026-09-09 15:20:00] [Espera] Clicando em (450, 320)...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Interromper
|
||||
|
||||
Pressione **CTRL+C** para parar o programa a qualquer momento. O total de cliques realizados é exibido no encerramento.
|
||||
|
||||
---
|
||||
|
||||
## Dicas
|
||||
|
||||
- A imagem `botaoparaclicar.png` deve ser um recorte **apenas do botão**, sem fundo ou com fundo transparente (PNG com canal alpha é suportado)
|
||||
- Ajuste `CONFIANCA` conforme necessário: valores mais baixos detectam com menos precisão, valores mais altos exigem correspondência exata
|
||||
- Use `INTERVALO_MINIMO_CLIQUE` e `INTERVALO_MAXIMO_CLIQUE` para simular comportamento humano (intervalos aleatórios)
|
||||
- O `pyautogui.FAILSAFE` está ativado: mova o mouse para um dos cantos da tela para abortar imediatamente
|
||||
@@ -0,0 +1,330 @@
|
||||
# RULES.md — Regras de Desenvolvimento do AutoTigrinho
|
||||
|
||||
Este documento define as regras que **qualquer agente de IA ou desenvolvedor** deve seguir ao modificar, estender ou corrigir este sistema. Violar estas regras pode quebrar funcionalidades existentes.
|
||||
|
||||
---
|
||||
|
||||
## 1. Estrutura do Projeto
|
||||
|
||||
```
|
||||
AutoTigrinho/app/
|
||||
├── main.py # Código principal — todo o loop e lógica
|
||||
├── iniciar.sh # Launcher — setup de venv, deps e Xvfb
|
||||
├── .env # Configurações — NÃO hardcodificar valores aqui
|
||||
├── requirements.txt # Dependências Python — sempre usar --upgrade --force-reinstall
|
||||
├── botaoparaclicar.png # Template de imagem para detecção
|
||||
├── log.txt # Log de execução — gerado em runtime
|
||||
├── venv/ # Ambiente virtual Python — recriado em outra máquina
|
||||
└── bin/ # Xvfb local para modo headless — gerado automaticamente
|
||||
```
|
||||
|
||||
**Regra:** todos os arquivos acima devem permanecer na raiz do projeto. Não criar pastas adicionais sem motivo explícito.
|
||||
|
||||
---
|
||||
|
||||
## 2. Ordenação e Organização de Código em `main.py`
|
||||
|
||||
O arquivo `main.py` **não deve ser reestruturado livremente**. A ordem das seções é:
|
||||
|
||||
```
|
||||
1. Shebang + docstring (linhas 1-6)
|
||||
2. Imports (linhas 8-17) — stdlib primeiro, terceiros depois
|
||||
3. load_dotenv() (linha 19)
|
||||
4. Constantes carregadas do .env (linhas 21-31)
|
||||
5. Função _carregar_periodos() + PERIODOS_SESSAO (linhas 34-43)
|
||||
6. Funções utilitárias (dentro_horario, encontrar_botao, gerar_intervalo_aleatorio)
|
||||
7. Funções de UI (vis_largura, terminal_width, largura, center, banner, painel_config, cabecalho_sessao, rodape_clique, log)
|
||||
8. Função main()
|
||||
9. if __name__ == "__main__": main()
|
||||
```
|
||||
|
||||
**Regra:** nunca remover ou reordenar as constantes do `.env` da seção 4. Sempre adicionar novas constantes nessa mesma seção, mantendo a ordem lógica (intervalos, limites, detectores).
|
||||
|
||||
---
|
||||
|
||||
## 3. Variáveis de Ambiente — Regras Obrigatórias
|
||||
|
||||
Todas as configurações devem ser lidas via `os.getenv()` e devem ter um valor padrão sensato. **Nunca hardcodificar valores de configuração** diretamente no código.
|
||||
|
||||
### Nomenclatura das variáveis
|
||||
|
||||
```
|
||||
INTERVALO_* → valores em SEGUNDOS (int)
|
||||
MAXIMO_* → valores limites inteiros (int)
|
||||
CONFIANCA → valor float entre 0.0 e 1.0
|
||||
PERIODO_N_* → strings no formato "HH:MM" ou vazias
|
||||
```
|
||||
|
||||
### Formato dos períodos
|
||||
|
||||
```ini
|
||||
# Correto: range completo dentro de um dia
|
||||
PERIODO_1_INICIO=09:00
|
||||
PERIODO_1_FIM=12:00
|
||||
|
||||
# Correto: períodos que cruzam meia-noite NÃO são suportados
|
||||
# PERIODO_X_INICIO=23:00 ← PERIODO_X_FIM=01:00 NÃO FUNCIONA
|
||||
|
||||
# Correto: desativar um período deixando campos vazios
|
||||
PERIODO_3_INICIO=
|
||||
PERIODO_3_FIM=
|
||||
```
|
||||
|
||||
**Regra:** períodos que cruzam meia-noite não são suportados pela lógica atual de `datetime.strptime().time()`. Se necessário implementar, modificar `dentro_horario()` com lógica de comparação de `datetime` completo (não só `.time()`).
|
||||
|
||||
### Padrão ao adicionar nova variável de ambiente
|
||||
|
||||
1. Adicionar linha no `.env` com valor padrão e comentário opcional
|
||||
2. Adicionar constante no topo de `main.py` seção 4: `NOME = tipo(os.getenv("NOME", "default"))`
|
||||
3. Adicionar entrada em `painel_config()` para exibir no painel inicial
|
||||
4. Usar a constante, nunca `os.getenv()` diretamente em outros pontos
|
||||
|
||||
---
|
||||
|
||||
## 4. Fluxo de Execução — Ordem de Verificações
|
||||
|
||||
O loop `while True` em `main()` (linha 240) segue esta ordem **estrita**:
|
||||
|
||||
```
|
||||
while True:
|
||||
1. Verificar dentro_horario(PERIODOS_SESSAO)
|
||||
└─ FORA dos períodos → clique global + continue
|
||||
└─ DENTRO dos períodos → prossegue para 2
|
||||
|
||||
2. Verificar primeiro_clique
|
||||
└─ True → dorme INTERVALO_PRIMEIRO_CLIQUE, depois False
|
||||
|
||||
3. Chamar encontrar_botao()
|
||||
└─ ENCONTROU → pyautogui.click(), incrementa contadores, falhas=0
|
||||
└─ NÃO ENCONTROU → incrementa falhas, dorme INTERVALO_MINIMO_CLIQUE, continue (re-tenta)
|
||||
|
||||
4. Verificar MAXIMO_CLIQUES_POR_SESSAO
|
||||
└─ Atingido → finaliza sessão, loop de espera com clique global, depois continue
|
||||
|
||||
5. Dorme intervalo aleatório (INTERVALO_MINIMO_CLIQUE ~ INTERVALO_MAXIMO_CLIQUE)
|
||||
```
|
||||
|
||||
**Regra:** NÃO alterar esta ordem sem justificativa explícita do usuário. O `continue` em cada branch é intencional para reiniciar o ciclo de verificações.
|
||||
|
||||
---
|
||||
|
||||
## 5. Regras de Logging
|
||||
|
||||
Todas as mensagens devem passar pela função `log(mensagem, cor)`:
|
||||
|
||||
```python
|
||||
log("mensagem aqui", COR)
|
||||
```
|
||||
|
||||
### Cores disponíveis
|
||||
|
||||
| Constante | Cor | Uso recomendado |
|
||||
|---|---|---|
|
||||
| `C_GREEN` | Verde | Sucesso, clique executado |
|
||||
| `C_GREEN + BOLD` | Verde negrito | Contador de cliques |
|
||||
| `C_RED` | Vermelho | Erros, botão não encontrado |
|
||||
| `C_RED + BOLD` | Vermelho negrito | Erros críticos, encerramento |
|
||||
| `C_YELLOW` | Amarelo | Avisos, fora de período |
|
||||
| `C_CYAN` | Ciano | Esperas, ciclos |
|
||||
| `C_GRAY` | Cinza | Timestamps e esperas longas |
|
||||
| `C_MAG` | Magenta | Sessões |
|
||||
| `C_WHITE` | Branco | Valores, títulos |
|
||||
| `C_TITLE` | Ciano claro | Banner e títulos de seção |
|
||||
|
||||
### Prefixos de log
|
||||
|
||||
| Prefixo | Quando usar |
|
||||
|---|---|
|
||||
| `[Sessão N]` | Qualquer evento durante uma sessão ativa |
|
||||
| `[Espera]` | Cliques de keep-alive (fora de período ou entre sessões) |
|
||||
| Sem prefixo | Eventos globais (inicialização, encerramento) |
|
||||
|
||||
**Regra:** nunca usar `print()` diretamente para mensagens de evento — sempre use `log()`. O `print()` só deve ser usado para `banner()`, `painel_config()`, `cabecalho_sessao()`, `rodape_clique()` e mensagens de `KeyboardInterrupt`.
|
||||
|
||||
### Formato do arquivo `log.txt`
|
||||
|
||||
O arquivo é escrito com `f.write()` dentro de `log()`. Sem ANSI codes, com timestamp completo `YYYY-MM-DD HH:MM:SS`.
|
||||
|
||||
**Regra:** não alterar o formato de escrita do `log.txt` sem atualizar o README.
|
||||
|
||||
---
|
||||
|
||||
## 6. Regras de Detecção de Botão (`encontrar_botao`)
|
||||
|
||||
```python
|
||||
def encontrar_botao(imagem_path: str, confianca: float = 0.8):
|
||||
```
|
||||
|
||||
- Usa **OpenCV `cv2.matchTemplate`** com método `TM_CCOEFF_NORMED`
|
||||
- Suporta PNG com canal alpha (transparência) — o alpha é convertido em máscara
|
||||
- Retorna `(centro_x, centro_y)` se `max_val >= confianca`, senão `None`
|
||||
- O centro é calculado como `max_loc + (w//2, h//2)` — **não** usar `max_loc` diretamente
|
||||
- A screenshot é convertida de RGB (PIL) → BGR (OpenCV) via `cv2.cvtColor(screenshot_np, cv2.COLOR_RGB2BGR)`
|
||||
|
||||
**Regra:** não alterar o método de template matching, a lógica de máscara alpha ou o cálculo do centro sem motivo explícito.
|
||||
|
||||
---
|
||||
|
||||
## 7. Regras de Sessão
|
||||
|
||||
### Estados da variável `numero_sessao`
|
||||
|
||||
- Inicia em `1`
|
||||
- Incrementado apenas no bloco de finalização de sessão (linha 309)
|
||||
- Usado em todos os logs de sessão
|
||||
|
||||
### Estados de `cliques_na_sessao`
|
||||
|
||||
- Inicia em `0`
|
||||
- Incrementado apenas em `pyautogui.click()` bem-sucedido (linha 283)
|
||||
- Resetado para `0` ao finalizar sessão **e** ao sair dos períodos
|
||||
|
||||
### Estados de `falhas_consecutivas`
|
||||
|
||||
- Incrementado quando `encontrar_botao()` retorna `None` (linha 291)
|
||||
- Resetado para `0` a cada clique bem-sucedido E ao sair dos períodos
|
||||
- NÃO causa mais encerramento automático — o sistema re-tenta indefinidamente
|
||||
|
||||
---
|
||||
|
||||
## 8. Regras de Clique Global / Keep-Alive
|
||||
|
||||
O **clique global** é executado em dois pontos distintos do código:
|
||||
|
||||
### Ponto A — Fora dos períodos (linhas 248-259)
|
||||
|
||||
```python
|
||||
# dorme INTERVALO_CLIQUE_GLOBAL, depois tenta detectar e clicar
|
||||
time.sleep(INTERVALO_CLIQUE_GLOBAL)
|
||||
pos_global = encontrar_botao(IMAGEM_BOTAO, CONFIANCA)
|
||||
if pos_global:
|
||||
pyautogui.click(gx, gy)
|
||||
```
|
||||
|
||||
### Ponto B — Entre sessões (linhas 316-339)
|
||||
|
||||
```python
|
||||
# loop while que divide o INTERVALO_ENTRE_SESSOES em ciclos de INTERVALO_CLIQUE_GLOBAL
|
||||
while tempo_restante > 0:
|
||||
tempo_ate_clique = min(tempo_restante, INTERVALO_CLIQUE_GLOBAL)
|
||||
time.sleep(tempo_ate_clique)
|
||||
# ... tenta detectar e clicar
|
||||
```
|
||||
|
||||
**Regra:** o intervalo de keep-alive é **sempre** `INTERVALO_CLIQUE_GLOBAL`. O nome `INTERVALO_CLIQUE_ESPERA` está obsoleto — não reintroduzi-lo.
|
||||
|
||||
---
|
||||
|
||||
## 9. Regras de Interface Terminal
|
||||
|
||||
### Funções de UI existentes
|
||||
|
||||
| Função | Propósito |
|
||||
|---|---|
|
||||
| `banner()` | Cabeçalho inicial |
|
||||
| `painel_config()` | Painel de configuração — adicionar entradas aqui se nova variável |
|
||||
| `cabecalho_sessao(num)` | Cabeçalho de sessão |
|
||||
| `rodape_clique()` | Barra de progresso visual pós-clique |
|
||||
| `center(text, pre, pos)` | Centraliza texto com prefixo/sufixo cor |
|
||||
|
||||
### Adicionar nova entrada no painel
|
||||
|
||||
```python
|
||||
(COR, "Label da configuração", f"{CONSTANTE}s"), # note a vírgula final
|
||||
```
|
||||
|
||||
Inserir no dicionário `itens` dentro de `painel_config()`, mantendo a ordem lógica.
|
||||
|
||||
### Adicionar nova lista abaixo do painel
|
||||
|
||||
Se houver dados adicionais para exibir (como os períodos), adicionar **após** o loop de renderização de `itens` e **antes** de `def cabecalho_sessao()`.
|
||||
|
||||
---
|
||||
|
||||
## 10. Regras do `iniciar.sh`
|
||||
|
||||
- Usa `set -e` — qualquer comando que falhar encerra o script
|
||||
- Ordem das etapas: Python check → venv → activate → pip upgrade → .env check → imagem check → deps → Xvfb → run
|
||||
- **NÃO modificar a lógica de setup do Xvfb** — a extração do `.deb` é frágil e específica de Debian/Ubuntu
|
||||
- Se o `.env` não existir, o script cria um `.env` mínimo e **sai com erro** — não prossegue
|
||||
- `requirements.txt` é sempre reinstalado com `--force-reinstall` para evitar erros de arquitetura
|
||||
|
||||
---
|
||||
|
||||
## 11. Regras para Modificações
|
||||
|
||||
### ✅ Sempre permitido
|
||||
|
||||
- Adicionar novas variáveis de configuração no `.env` e `main.py`
|
||||
- Adicionar novas entradas no `painel_config()`
|
||||
- Adicionar novas mensagens de log seguindo o padrão existente
|
||||
- Ajustar valores padrão de constantes
|
||||
- Adicionar novos períodos no `.env` (até 10)
|
||||
|
||||
### ⚠️ Permitido com cuidado
|
||||
|
||||
- Modificar `dentro_horario()` — testar períodos que cruzam meia-noite
|
||||
- Modificar a lógica de keep-alive — manter `INTERVALO_CLIQUE_GLOBAL` como intervalo base
|
||||
- Ajustar `CONFIANCA` — valores muito baixos geram falsos positivos
|
||||
|
||||
### ❌ Nunca fazer
|
||||
|
||||
- Remover `pyautogui.FAILSAFE = True`
|
||||
- Remover `_RE_ANSI` e a remoção de ANSI do `log.txt`
|
||||
- Remover `try/except` no `log()` — o log deve nunca crashar o programa
|
||||
- Remover o `continue` nos branches do loop principal — quebra o fluxo
|
||||
- Remover o `time.sleep(INTERVALO_MINIMO_CLIQUE)` no branch de botão não encontrado — causa CPU 100%
|
||||
- Alterar o método de template matching sem discussão explícita
|
||||
- Introduzir dependências novas sem atualizar `requirements.txt`
|
||||
- Mudar a ordem das seções de `main.py`
|
||||
- Adicionar `sys.exit()` ou `raise` em pontos que não sejam o topo do `main()`
|
||||
|
||||
### 🔴 Requer aprovação explícita do usuário
|
||||
|
||||
- Qualquer mudança que altere o fluxo de sessões
|
||||
- Qualquer remoção ou substituição de funcionalidade existente
|
||||
- Qualquer alteração em `iniciar.sh`
|
||||
|
||||
---
|
||||
|
||||
## 12. Padrão para Adicionar Nova Funcionalidade
|
||||
|
||||
```
|
||||
1. Adicionar variável no .env com valor padrão e comentário
|
||||
2. Adicionar constante em main.py seção 4
|
||||
3. Adicionar entrada em painel_config()
|
||||
4. Implementar lógica no main()
|
||||
5. Adicionar logs apropriados com cores corretas
|
||||
6. Atualizar README.md com a nova configuração/funcionalidade
|
||||
7. Verificar sintaxe: python3 -m py_compile main.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. Regras de Teste e Verificação
|
||||
|
||||
Após qualquer modificação em `main.py`:
|
||||
|
||||
```bash
|
||||
python3 -m py_compile main.py # deve retornar "Syntax OK"
|
||||
```
|
||||
|
||||
Verificar também:
|
||||
- Nenhuma referência a constantes removidas
|
||||
- Nenhuma duplicação de código (especialmente `CONFIANCA`, `IMAGEM_BOTAO`, `LOG_FILE`)
|
||||
- `PERIODOS_SESSAO` é carregado uma única vez no topo do arquivo
|
||||
|
||||
---
|
||||
|
||||
## 14. Glossário de Termos
|
||||
|
||||
| Termo | Significado no código |
|
||||
|---|---|
|
||||
| Sessão | Bloco de cliques consecutivos até `MAXIMO_CLIQUES_POR_SESSAO` |
|
||||
| Keep-alive | Clique de manutenção executado fora de sessão ativa |
|
||||
| Período | Faixa de horário (HH:MM → HH:MM) em que sessões são permitidas |
|
||||
| Fora do período | Momento em que o sistema só executa cliques globais, não sessões |
|
||||
| Clique global | Clique de keep-alive executado a cada `INTERVALO_CLIQUE_GLOBAL` segundos em qualquer estado |
|
||||
| Template matching | Algoritmo OpenCV que busca a imagem `botaoparaclicar.png` na tela |
|
||||
| Confiança | Threshold de correspondência (0.0 a 1.0) para aceitar uma detecção |
|
||||
| Failsafe | `pyautogui.FAILSAFE = True` — mover mouse no canto aborta o programa |
|
||||
Binary file not shown.
@@ -24,12 +24,32 @@ 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_GLOBAL = int(os.getenv("INTERVALO_CLIQUE_GLOBAL", "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")
|
||||
PERIODOS_SESSAO = []
|
||||
|
||||
def _carregar_periodos():
|
||||
periodos = []
|
||||
for i in range(1, 11):
|
||||
ini = os.getenv(f"PERIODO_{i}_INICIO", "").strip()
|
||||
fim = os.getenv(f"PERIODO_{i}_FIM", "").strip()
|
||||
if ini and fim:
|
||||
periodos.append((ini, fim))
|
||||
return periodos
|
||||
|
||||
PERIODOS_SESSAO = _carregar_periodos()
|
||||
|
||||
def dentro_horario(periodos: list) -> bool:
|
||||
agora = datetime.now().time()
|
||||
for ini, fim in periodos:
|
||||
hi = datetime.strptime(ini, "%H:%M").time()
|
||||
hf = datetime.strptime(fim, "%H:%M").time()
|
||||
if hi <= agora <= hf:
|
||||
return True
|
||||
return False
|
||||
|
||||
pyautogui.FAILSAFE = True
|
||||
|
||||
@@ -87,8 +107,8 @@ def painel_config() -> None:
|
||||
(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 global de espera", f"{INTERVALO_CLIQUE_GLOBAL}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)),
|
||||
]
|
||||
|
||||
@@ -114,6 +134,15 @@ def painel_config() -> None:
|
||||
)
|
||||
print()
|
||||
|
||||
if PERIODOS_SESSAO:
|
||||
print(C_WHITE + BOLD + center(" 📅 Períodos de sessão", C_TITLE) + RST)
|
||||
print()
|
||||
for idx, (ini, fim) in enumerate(PERIODOS_SESSAO, 1):
|
||||
print(C_WHITE + f" {idx}. " + C_CYAN + f"{ini} → {fim}" + RST)
|
||||
else:
|
||||
print(C_RED + center(" ⚠ Nenhum período configurado!", C_RED) + RST)
|
||||
print()
|
||||
|
||||
def cabecalho_sessao(num: int) -> None:
|
||||
print()
|
||||
print(C_MAG + BOLD + f" 🔄 SESSÃO {num} 🔄" + RST)
|
||||
@@ -147,12 +176,6 @@ def log(mensagem: str, cor: str = C_WHITE) -> None:
|
||||
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)
|
||||
@@ -217,15 +240,25 @@ def main() -> None:
|
||||
while True:
|
||||
agora = datetime.now()
|
||||
|
||||
if not dentro_horario(HORA_INICIO, HORA_FIM):
|
||||
if not dentro_horario(PERIODOS_SESSAO):
|
||||
log(
|
||||
f"[Sessão {numero_sessao}] Fora do horário permitido ({agora.strftime('%H:%M:%S')}).",
|
||||
f"[Sessão {numero_sessao}] Fora de todos os períodos configurados ({agora.strftime('%H:%M:%S')}).",
|
||||
C_YELLOW,
|
||||
)
|
||||
log(f"Pausando até {HORA_INICIO}...", C_GRAY)
|
||||
log(f"[Espera] Dormindo {INTERVALO_CLIQUE_GLOBAL}s até o próximo clique global...", C_GRAY)
|
||||
time.sleep(INTERVALO_CLIQUE_GLOBAL)
|
||||
pos_global = encontrar_botao(IMAGEM_BOTAO, CONFIANCA)
|
||||
if pos_global:
|
||||
gx, gy = pos_global
|
||||
log(
|
||||
f"[Espera] Clicando globalmente em ({gx}, {gy})...",
|
||||
C_GREEN,
|
||||
)
|
||||
pyautogui.click(gx, gy)
|
||||
else:
|
||||
log("[Espera] Botão não encontrado no clique global.", C_RED)
|
||||
falhas_consecutivas = 0
|
||||
cliques_na_sessao = 0
|
||||
time.sleep(30)
|
||||
continue
|
||||
|
||||
if primeiro_clique:
|
||||
@@ -258,17 +291,15 @@ def main() -> None:
|
||||
falhas_consecutivas += 1
|
||||
log(
|
||||
f"[Sessão {numero_sessao}] Botão não encontrado. "
|
||||
f"Falhas: {falhas_consecutivas}/{MAXIMO_FALHAS} | Total: {total_cliques}",
|
||||
f"Falhas: {falhas_consecutivas} | Total: {total_cliques}",
|
||||
C_RED,
|
||||
)
|
||||
if falhas_consecutivas >= MAXIMO_FALHAS:
|
||||
print()
|
||||
log(
|
||||
f"⚠ Máximo de falhas ({MAXIMO_FALHAS}) atingido. Encerrando.",
|
||||
C_RED + BOLD,
|
||||
)
|
||||
log(f"Total de cliques realizados: {total_cliques}", C_YELLOW)
|
||||
sys.exit(1)
|
||||
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(
|
||||
@@ -281,7 +312,31 @@ def main() -> None:
|
||||
f"Aguardando {INTERVALO_ENTRE_SESSOES}s até a Sessão {numero_sessao}...",
|
||||
C_YELLOW,
|
||||
)
|
||||
time.sleep(INTERVALO_ENTRE_SESSOES)
|
||||
tempo_restante = INTERVALO_ENTRE_SESSOES
|
||||
while tempo_restante > 0:
|
||||
tempo_ate_clique = min(tempo_restante, INTERVALO_CLIQUE_GLOBAL)
|
||||
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
|
||||
|
||||
|
||||
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user