Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba08626bd8 | ||
|
|
1ce6740a3b | ||
|
|
f0f87dde78 | ||
|
|
12a9cf122f | ||
|
|
48e851fd05 | ||
|
|
ae256da596 | ||
|
|
92e2ea2337 | ||
|
|
438e674eff | ||
|
|
5b74cf2dc5 | ||
|
|
4f5d937265 | ||
|
|
544dc770cd | ||
|
|
5fbe257625 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,3 +7,5 @@ node_modules/
|
||||
cookies.txt
|
||||
bin/
|
||||
mychats.txt
|
||||
manybot.conf
|
||||
update.log
|
||||
162
README.md
162
README.md
@@ -1,15 +1,157 @@
|
||||

|
||||
|
||||
Criei esse bot para servir um grupo de amigos. Meu foco não é fazer ele funcionar para todo mundo.
|
||||
ManyBot é um bot para WhatsApp que roda 100% localmente, sem depender da API oficial do WhatsApp. Ele utiliza a biblioteca `whatsapp-web.js`, que automatiza o WhatsApp Web sem depender de gráficos (headless).
|
||||
|
||||
Ele é 100% local e gratuito, sem necessidade de APIs burocraticas. Usufrui da biblioteca `whatsapp-web.js`, que permite bastante coisa mesmo sem a API oficial.
|
||||
|
||||
Você consegue totalmente clonar esse repoistório e rodar seu próprio ManyBot. A licenca GPLv3 permite que você modifique o que quiser e faça seu próprio bot, mas se for publicar, deve ser open source assim como o ManyBot original.
|
||||
|
||||
Algumas funcionalidades desse bot inclui:
|
||||
- Funciona em multiplos chats em apenas uma única sessão
|
||||
- Comandos de jogos e download com yt-dlp
|
||||
Algumas funcionalidades desse bot incluem:
|
||||
- Suporte a múltiplos chats em uma única sessão
|
||||
- Comandos de jogos
|
||||
- Download de mídia via yt-dlp
|
||||
- Gerador de figurinhas
|
||||
- Ferramenta para pegar IDs dos chats
|
||||
- Entre outros
|
||||
|
||||
# Screenshots
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
# Requisitos
|
||||
- Node.js
|
||||
- NPM
|
||||
- Sistema Linux ou Windows
|
||||
|
||||
obs: Sistemas Android e iOS ainda não são 100% compatíveis. O suporte para Termux está em fases de testes e sem garantia de funcionamento correto.
|
||||
|
||||
# Instalação (Linux)
|
||||
|
||||
1. Clone o repositório e entre:
|
||||
```
|
||||
git clone https://github.com/synt-xerror/manybot
|
||||
cd manybot
|
||||
```
|
||||
|
||||
2. Crie e abra o arquivo de configuração (use o editor de sua preferência):
|
||||
```
|
||||
touch manybot.conf
|
||||
nano manybot.conf
|
||||
```
|
||||
|
||||
3. Nele você pode configurar algumas coisas do ManyBot. Esse é o arquivo base para que possa modificar:
|
||||
```
|
||||
CLIENT_ID=manybot
|
||||
BOT_PREFIX=🤖 *ManyBot:*
|
||||
CMD_PREFIX=!
|
||||
CHATS=[
|
||||
123456789@c.us,
|
||||
123456789@g.us
|
||||
]
|
||||
```
|
||||
- **CLIENT_ID:** ID do cliente, serve para identificar sua sessão.
|
||||
- **BOT_PREFIX:** Prefixo/nome do bot, o que aparece sempre que manda uma mensagem.
|
||||
- **CMD_PREFIX:** Prefixo do comando, o caractere que você usa para executar um comando (!many, !figurinha).
|
||||
- **CHATS:** ID dos chats no qual você quer que o bot assista. Use o utilitário: `src/utils/get_id.js` para descobrir os IDs. Deixe vazio caso queira que funcione com qualquer chat.
|
||||
|
||||
4. Execute o script de instalação:
|
||||
```
|
||||
bash ./setup
|
||||
```
|
||||
|
||||
5. Rode o bot pela primeira vez:
|
||||
```
|
||||
node ./src/main.js
|
||||
```
|
||||
Ele vai pedir para que escaneie o QR Code com seu celular.
|
||||
|
||||
No WhatsApp:
|
||||
Menu (três pontos) > Dispositivos conectados > Conectar um dispositivo
|
||||
|
||||
# Instalação (Windows)
|
||||
|
||||
O uso desse bot foi pensado para rodar em um terminal Linux. No entanto, você pode usar o Git Bash, que simula um terminal Linux com Bash real:
|
||||
|
||||
1. Para baixar o Git Bash: https://git-scm.com/install/windows
|
||||
Selecione a versão que deseja (portátil ou instalador)
|
||||
|
||||
2. Para baixar o Node.js: https://nodejs.org/pt-br/download
|
||||
Role a tela e selecione "Instalador Windows (.msi)"
|
||||
Ou se preferir, use um gerenciador de pacotes como mostra no conteúdo inicial
|
||||
|
||||
Depois de instalar ambos, abra o Git Bash e execute exatamente os mesmos comandos mostrados na seção Linux.
|
||||
|
||||
# Uso
|
||||
|
||||
Feito a instalação, você pode executar o bot apenas rodando:
|
||||
```
|
||||
node ./src/main.js
|
||||
```
|
||||
|
||||
## Atualizações
|
||||
|
||||
É recomendável sempre ter a versão mais recente do ManyBot. Para isso, temos um utilitário logo na raíz. Para executar:
|
||||
```
|
||||
bash ./update
|
||||
```
|
||||
|
||||
## Criando um serviço (opcional)
|
||||
|
||||
Se estiver rodando numa VPS ou apenas quer mais controle, é recomendável criar um serviço systemd. Siga os passos abaixo para saber como criar, habilitar e gerenciar um.
|
||||
|
||||
1. Configurando o diretório
|
||||
|
||||
Primeiro passo é garantir que o diretório do ManyBot esteja no local adequado, é recomendável guardar em `/root/manybot` (os passos a seguir supõem que esteja essa localização)
|
||||
|
||||
2. Criando o serviço
|
||||
|
||||
Abra o arquivo:
|
||||
```
|
||||
/etc/systemd/system/manybot.service
|
||||
```
|
||||
|
||||
E cole o seguinte conteúdo:
|
||||
```
|
||||
[Unit]
|
||||
Description=ManyBot
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/env node /root/manybot/src/main.js
|
||||
WorkingDirectory=/root/manybot
|
||||
Restart=always
|
||||
Environment=NODE_ENV=production
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
3. Iniciando e habilitando o serviço:
|
||||
|
||||
Primeiro reinicie o daemon do systemd:
|
||||
```
|
||||
systemctl daemon-reload
|
||||
```
|
||||
|
||||
Inicie o serviço:
|
||||
```
|
||||
systemctl start manybot
|
||||
```
|
||||
|
||||
Habilite para que ele seja iniciado junto com o seu sistema (opcional):
|
||||
```
|
||||
systemctl enable manybot
|
||||
```
|
||||
|
||||
## Comandos
|
||||
|
||||
O ManyBot vem com alguns comandos pré-definidos, sendo esses:
|
||||
|
||||
- `video <link>`: baixa um vídeo da internet
|
||||
- `audio <link>`: também baixa um vídeo, mas manda apenas o áudio
|
||||
- `figurinha`: gerador de figurinhas
|
||||
- `adivinhação`: jogo simples de adivnhação de um número entre 1 a 100
|
||||
|
||||
O prefixo para ativá-los depende da sua configuração, mas por padrão é o ponto de exclamação (`!`).
|
||||
|
||||
# Considerações
|
||||
|
||||
ManyBot é distribuído sob a licença GPLv3. Você pode usar, modificar e redistribuir o software conforme os termos da licença.
|
||||
|
||||
Saiba mais sobre as permissões lendo o arquivo [[LICENSE]] ou em: https://www.gnu.org/licenses/quick-guide-gplv3.pt-br.html
|
||||
11
deploy.sh
11
deploy.sh
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
# development tool
|
||||
# ferramenta de desenvolvimento apenas, pode apagar se quiser
|
||||
# ./deploy <commit> <branch> <version (if branch=master)>
|
||||
|
||||
COMMIT_MSG="$1"
|
||||
@@ -12,15 +12,6 @@ if [ -z "$COMMIT_MSG" ] || [ -z "$BRANCH" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Rewriting config.js"
|
||||
cat > "src/config.js" << 'EOF'
|
||||
export const CLIENT_ID = "bot_permanente";
|
||||
export const BOT_PREFIX = "🤖 *ManyBot:* ";
|
||||
export const CHATS = [
|
||||
// coloque os chats que quer aqui
|
||||
];
|
||||
EOF
|
||||
|
||||
# mudar para a branch
|
||||
git checkout $BRANCH || { echo "Error ao change to $BRANCH"; exit 1; }
|
||||
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "whatsapp-bot",
|
||||
"version": "2.3.1",
|
||||
"version": "2.3.6",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "whatsapp-bot",
|
||||
"version": "2.3.1",
|
||||
"version": "2.3.6",
|
||||
"dependencies": {
|
||||
"node-addon-api": "^7",
|
||||
"node-gyp": "^12.2.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "manybot",
|
||||
"version": "2.3.1",
|
||||
"version": "2.3.6",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"node-addon-api": "^7",
|
||||
|
||||
28
setup
28
setup
@@ -1,6 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Salvando diretório para evitar problemas
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# ------------------------
|
||||
# Cores
|
||||
# ------------------------
|
||||
@@ -48,8 +51,6 @@ cat << "EOF"
|
||||
website: www.mlplovers.com.br/manybot
|
||||
repo: github.com/synt-xerror/manybot
|
||||
|
||||
A Amizade é Mágica!
|
||||
|
||||
EOF
|
||||
echo -e "${RESET}"
|
||||
}
|
||||
@@ -190,6 +191,27 @@ fi
|
||||
|
||||
log_debug "Total de arquivos para baixar: ${#files[@]}"
|
||||
|
||||
# ------------------------
|
||||
# Config
|
||||
# ------------------------
|
||||
log_info "Criando arquivo de configuração"
|
||||
|
||||
cat > "src/config.js" << 'EOF'
|
||||
export const CLIENT_ID = "bot_permanente";
|
||||
export const BOT_PREFIX = "🤖 *ManyBot:* ";
|
||||
export const CMD_PREFIX = "!";
|
||||
export const CHATS = [
|
||||
// coloque os chats que quer aqui
|
||||
];
|
||||
|
||||
EOF
|
||||
|
||||
if [[ -f src/config.js ]]; then
|
||||
log_ok "Arquivo de configuração criado"
|
||||
else
|
||||
log_error "Erro durante criação do arquivo de configuração"
|
||||
fi
|
||||
|
||||
# ------------------------
|
||||
# Download
|
||||
# ------------------------
|
||||
@@ -201,4 +223,4 @@ for file in "${files[@]}"; do
|
||||
download_file "$url" "$dest"
|
||||
done
|
||||
|
||||
log_ok "Setup concluído com sucesso"
|
||||
log_ok "Setup concluído com sucesso.\nRode sempre na raíz: 'node src/main.js' (ou equivalente) para rodar o bot."
|
||||
@@ -16,7 +16,15 @@ logger.info(isTermux
|
||||
// ── Instância ─────────────────────────────────────────────────
|
||||
export const client = new Client({
|
||||
authStrategy: new LocalAuth({ clientId: CLIENT_ID }),
|
||||
puppeteer: { headless: true, ...resolvePuppeteerConfig() },
|
||||
puppeteer: {
|
||||
headless: true,
|
||||
args: [
|
||||
'--no-sandbox',
|
||||
'--disable-setuid-sandbox',
|
||||
...(resolvePuppeteerConfig().args || [])
|
||||
],
|
||||
...resolvePuppeteerConfig()
|
||||
},
|
||||
});
|
||||
|
||||
// ── Eventos ───────────────────────────────────────────────────
|
||||
|
||||
@@ -21,7 +21,7 @@ const DOWNLOADS_DIR = path.resolve("downloads");
|
||||
const FFMPEG = os.platform() === "win32" ? ".\\bin\\ffmpeg.exe" : "./bin/ffmpeg";
|
||||
const MAX_STICKER_SIZE = 900 * 1024;
|
||||
const SESSION_TIMEOUT = 2 * 60 * 1000;
|
||||
const MAX_MEDIA = 10;
|
||||
const MAX_MEDIA = 30;
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────
|
||||
function ensureDownloadsDir() {
|
||||
|
||||
@@ -1,5 +1,64 @@
|
||||
export const CLIENT_ID = "bot_permanente";
|
||||
export const BOT_PREFIX = "🤖 *ManyBot:* ";
|
||||
export const CHATS = [
|
||||
// coloque os chats que quer aqui
|
||||
];
|
||||
import fs from "fs";
|
||||
|
||||
function parseConf(raw) {
|
||||
// Remove comentários inline e de linha inteira, preservando estrutura
|
||||
const lines = raw.split("\n");
|
||||
|
||||
const cleaned = [];
|
||||
let insideList = false;
|
||||
let buffer = "";
|
||||
|
||||
for (let line of lines) {
|
||||
// Remove comentário inline (# ...) — mas só fora de strings
|
||||
line = line.replace(/#.*$/, "").trim();
|
||||
if (!line) continue;
|
||||
|
||||
if (!insideList) {
|
||||
if (line.includes("=[") && !line.includes("]")) {
|
||||
// Início de lista multilinha
|
||||
insideList = true;
|
||||
buffer = line;
|
||||
} else {
|
||||
cleaned.push(line);
|
||||
}
|
||||
} else {
|
||||
buffer += line;
|
||||
if (line.includes("]")) {
|
||||
// Fim da lista
|
||||
insideList = false;
|
||||
cleaned.push(buffer);
|
||||
buffer = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parseia cada linha chave=valor
|
||||
const result = {};
|
||||
for (const line of cleaned) {
|
||||
const eqIdx = line.indexOf("=");
|
||||
if (eqIdx === -1) continue;
|
||||
|
||||
const key = line.slice(0, eqIdx).trim();
|
||||
const raw = line.slice(eqIdx + 1).trim();
|
||||
|
||||
if (raw.startsWith("[") && raw.endsWith("]")) {
|
||||
result[key] = raw
|
||||
.slice(1, -1)
|
||||
.split(",")
|
||||
.map(x => x.trim())
|
||||
.filter(Boolean);
|
||||
} else {
|
||||
result[key] = raw;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const raw = fs.readFileSync("manybot.conf", "utf8");
|
||||
const config = parseConf(raw);
|
||||
|
||||
export const CLIENT_ID = config.CLIENT_ID ?? "bot_permanente";
|
||||
export const BOT_PREFIX = config.BOT_PREFIX ?? "🤖 *ManyBot:* ";
|
||||
export const CMD_PREFIX = config.CMD_PREFIX ?? "!";
|
||||
export const CHATS = config.CHATS ?? [];
|
||||
@@ -16,7 +16,11 @@ export async function handleMessage(msg) {
|
||||
const chat = await msg.getChat();
|
||||
const chatId = getChatId(chat);
|
||||
|
||||
// se CHATS estiver vazio, ele pega todos os chats.
|
||||
// se nao, ele pega os que estão na lista.
|
||||
if (CHATS.length > 0) {
|
||||
if (!CHATS.includes(chatId)) return;
|
||||
}
|
||||
|
||||
const ctx = await buildMessageContext(msg, chat, BOT_PREFIX);
|
||||
logger.msg(ctx);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import pkg from "whatsapp-web.js";
|
||||
import qrcode from "qrcode-terminal";
|
||||
import { CLIENT_ID } from "../config.js";
|
||||
import { resolvePuppeteerConfig } from "../client/environment.js";
|
||||
|
||||
const { Client, LocalAuth } = pkg;
|
||||
|
||||
@@ -17,7 +18,15 @@ if (!arg) {
|
||||
|
||||
const client = new Client({
|
||||
authStrategy: new LocalAuth({ clientId: CLIENT_ID }),
|
||||
puppeteer: { headless: true },
|
||||
puppeteer: {
|
||||
headless: true,
|
||||
args: [
|
||||
'--no-sandbox',
|
||||
'--disable-setuid-sandbox',
|
||||
...(resolvePuppeteerConfig().args || [])
|
||||
],
|
||||
...resolvePuppeteerConfig()
|
||||
},
|
||||
});
|
||||
|
||||
client.on("qr", (qr) => {
|
||||
|
||||
141
update
Normal file
141
update
Normal file
@@ -0,0 +1,141 @@
|
||||
#!/bin/bash
|
||||
# ==============================================================================
|
||||
# update.sh — Script de atualização segura do ManyBot
|
||||
# ==============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Configuração
|
||||
# ------------------------------------------------------------------------------
|
||||
dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
tmp_dir="$dir/tmp"
|
||||
log_file="$dir/update.log"
|
||||
config_items=(".wwebjs_auth" ".wwebjs_cache" "node_modules")
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Logging
|
||||
# ------------------------------------------------------------------------------
|
||||
log() {
|
||||
local level="$1"; shift
|
||||
local msg="$*"
|
||||
local timestamp
|
||||
timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "[$timestamp] [$level] $msg" | tee -a "$log_file"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Trap: executa em caso de qualquer erro
|
||||
# ------------------------------------------------------------------------------
|
||||
cleanup_on_error() {
|
||||
local exit_code=$?
|
||||
log "ERROR" "Falha durante a atualização (código: $exit_code)."
|
||||
if [ -d "$tmp_dir" ] && [ "$(ls -A "$tmp_dir" 2>/dev/null)" ]; then
|
||||
log "WARN" "Arquivos de configuração preservados em: $tmp_dir"
|
||||
log "WARN" "Restaure manualmente com: mv $tmp_dir/* $dir/"
|
||||
fi
|
||||
exit $exit_code
|
||||
}
|
||||
trap cleanup_on_error ERR
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Validações iniciais
|
||||
# ------------------------------------------------------------------------------
|
||||
log "INFO" "Iniciando atualização do ManyBot..."
|
||||
|
||||
# Verifica dependências obrigatórias
|
||||
for cmd in git npm; do
|
||||
if ! command -v "$cmd" &>/dev/null; then
|
||||
log "ERROR" "Dependência ausente: '$cmd' não encontrado no PATH."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Verifica se está em um repositório git
|
||||
if ! git -C "$dir" rev-parse --is-inside-work-tree &>/dev/null; then
|
||||
log "ERROR" "'$dir' não é um repositório git."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Exibe o remote para transparência
|
||||
remote_url=$(git -C "$dir" remote get-url origin 2>/dev/null || echo "(não definido)")
|
||||
log "INFO" "Remote: $remote_url"
|
||||
|
||||
# Verifica se há alterações locais não commitadas
|
||||
if ! git -C "$dir" diff --quiet || ! git -C "$dir" diff --cached --quiet; then
|
||||
log "WARN" "Existem alterações locais não commitadas. Elas serão descartadas pelo reset."
|
||||
read -r -p "Deseja continuar mesmo assim? [s/N] " confirm
|
||||
confirm="${confirm:-N}"
|
||||
if [[ ! "$confirm" =~ ^[sS]$ ]]; then
|
||||
log "INFO" "Atualização cancelada pelo usuário."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Backup dos arquivos de configuração
|
||||
# ------------------------------------------------------------------------------
|
||||
rm -rf "$tmp_dir"
|
||||
mkdir -p "$tmp_dir"
|
||||
|
||||
backed_up=()
|
||||
for item in "${config_items[@]}"; do
|
||||
src="$dir/$item"
|
||||
if [ -e "$src" ]; then
|
||||
mv "$src" "$tmp_dir/"
|
||||
backed_up+=("$item")
|
||||
log "INFO" "Backup: $item → tmp/"
|
||||
fi
|
||||
done
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Atualização do repositório
|
||||
# ------------------------------------------------------------------------------
|
||||
log "INFO" "Buscando atualizações..."
|
||||
git -C "$dir" fetch origin
|
||||
|
||||
branch=$(git -C "$dir" rev-parse --abbrev-ref HEAD)
|
||||
log "INFO" "Branch atual: $branch"
|
||||
|
||||
# Registra o hash antes e depois para auditoria
|
||||
hash_before=$(git -C "$dir" rev-parse HEAD)
|
||||
git -C "$dir" reset --hard "origin/$branch"
|
||||
hash_after=$(git -C "$dir" rev-parse HEAD)
|
||||
|
||||
if [ "$hash_before" = "$hash_after" ]; then
|
||||
log "INFO" "Repositório já estava atualizado (sem mudanças)."
|
||||
else
|
||||
log "INFO" "Atualizado: $hash_before → $hash_after"
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Instalação de dependências
|
||||
# ------------------------------------------------------------------------------
|
||||
log "INFO" "Instalando dependências..."
|
||||
npm ci --omit=dev 2>&1 | tee -a "$log_file"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Restauração dos arquivos de configuração
|
||||
# ------------------------------------------------------------------------------
|
||||
if [ ${#backed_up[@]} -gt 0 ]; then
|
||||
for item in "${backed_up[@]}"; do
|
||||
src="$tmp_dir/$item"
|
||||
dst="$dir/$item"
|
||||
if [ -e "$src" ]; then
|
||||
# Remove o que npm possa ter criado (ex: node_modules)
|
||||
rm -rf "$dst"
|
||||
mv "$src" "$dst"
|
||||
log "INFO" "Restaurado: $item"
|
||||
else
|
||||
log "WARN" "Item esperado no backup não encontrado: $item"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Limpa tmp apenas após restauração bem-sucedida
|
||||
rm -rf "$tmp_dir"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Concluído
|
||||
# ------------------------------------------------------------------------------
|
||||
log "INFO" "ManyBot atualizado com sucesso."
|
||||
Reference in New Issue
Block a user