Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba08626bd8 | ||
|
|
1ce6740a3b | ||
|
|
f0f87dde78 | ||
|
|
12a9cf122f | ||
|
|
48e851fd05 | ||
|
|
ae256da596 | ||
|
|
92e2ea2337 | ||
|
|
438e674eff | ||
|
|
5b74cf2dc5 | ||
|
|
4f5d937265 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@ cookies.txt
|
|||||||
bin/
|
bin/
|
||||||
mychats.txt
|
mychats.txt
|
||||||
manybot.conf
|
manybot.conf
|
||||||
|
update.log
|
||||||
139
README.md
139
README.md
@@ -1,17 +1,16 @@
|
|||||||

|

|
||||||
|
|
||||||
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.
|
Algumas funcionalidades desse bot incluem:
|
||||||
|
- Suporte a múltiplos chats em uma única sessão
|
||||||
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.
|
- Comandos de jogos
|
||||||
|
- Download de mídia via yt-dlp
|
||||||
Algumas funcionalidades desse bot inclui:
|
|
||||||
- Funciona em multiplos chats em apenas uma única sessão
|
|
||||||
- Comandos de jogos e download com yt-dlp
|
|
||||||
- Gerador de figurinhas
|
- Gerador de figurinhas
|
||||||
- Ferramenta para pegar IDs dos chats
|
|
||||||
- Entre outros
|
# Screenshots
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -30,27 +29,129 @@ git clone https://github.com/synt-xerror/manybot
|
|||||||
cd manybot
|
cd manybot
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Execute o script de instalação:
|
2. Crie e abra o arquivo de configuração (use o editor de sua preferência):
|
||||||
```
|
```
|
||||||
bash setup
|
touch manybot.conf
|
||||||
|
nano manybot.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Rode o bot pela primeira vez:
|
3. Nele você pode configurar algumas coisas do ManyBot. Esse é o arquivo base para que possa modificar:
|
||||||
```
|
```
|
||||||
node src/main.js
|
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.
|
Ele vai pedir para que escaneie o QR Code com seu celular.
|
||||||
Vá em: WhatsApp > Trẽs pontos no canto inferior > Dispositivos conectados > Conectar um dispositivo
|
|
||||||
|
No WhatsApp:
|
||||||
|
Menu (três pontos) > Dispositivos conectados > Conectar um dispositivo
|
||||||
|
|
||||||
# Instalação (Windows)
|
# Instalação (Windows)
|
||||||
|
|
||||||
O uso desse bot foi pensado para rodar em um terminal Linux com Bash. No entanto, você pode usar o Git Bash, que simula um terminal Linux com Bash real:
|
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
|
1. Para baixar o Git Bash: https://git-scm.com/install/windows
|
||||||
Selecione a versão que deseja (portátil ou instalador)
|
Selecione a versão que deseja (portátil ou instalador)
|
||||||
|
|
||||||
2. Para baixar o Node.js: https://nodejs.org/pt-br/download/current
|
2. Para baixar o Node.js: https://nodejs.org/pt-br/download
|
||||||
Role a tela e selecione "binário independente (.zip)"
|
Role a tela e selecione "Instalador Windows (.msi)"
|
||||||
Ou se preferir, use um gerenciador de pacotes como mostra no conteúdo inicial
|
Ou se preferir, use um gerenciador de pacotes como mostra no conteúdo inicial
|
||||||
|
|
||||||
Após baixar e instalar ambos, abra o Git Bash e execute exatamente os mesmos passos do Linux
|
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
|
||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "whatsapp-bot",
|
"name": "whatsapp-bot",
|
||||||
"version": "2.3.2",
|
"version": "2.3.6",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "whatsapp-bot",
|
"name": "whatsapp-bot",
|
||||||
"version": "2.3.2",
|
"version": "2.3.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-addon-api": "^7",
|
"node-addon-api": "^7",
|
||||||
"node-gyp": "^12.2.0",
|
"node-gyp": "^12.2.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "manybot",
|
"name": "manybot",
|
||||||
"version": "2.3.2",
|
"version": "2.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-addon-api": "^7",
|
"node-addon-api": "^7",
|
||||||
|
|||||||
@@ -16,7 +16,15 @@ logger.info(isTermux
|
|||||||
// ── Instância ─────────────────────────────────────────────────
|
// ── Instância ─────────────────────────────────────────────────
|
||||||
export const client = new Client({
|
export const client = new Client({
|
||||||
authStrategy: new LocalAuth({ clientId: CLIENT_ID }),
|
authStrategy: new LocalAuth({ clientId: CLIENT_ID }),
|
||||||
puppeteer: { headless: true, ...resolvePuppeteerConfig() },
|
puppeteer: {
|
||||||
|
headless: true,
|
||||||
|
args: [
|
||||||
|
'--no-sandbox',
|
||||||
|
'--disable-setuid-sandbox',
|
||||||
|
...(resolvePuppeteerConfig().args || [])
|
||||||
|
],
|
||||||
|
...resolvePuppeteerConfig()
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Eventos ───────────────────────────────────────────────────
|
// ── Eventos ───────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const DOWNLOADS_DIR = path.resolve("downloads");
|
|||||||
const FFMPEG = os.platform() === "win32" ? ".\\bin\\ffmpeg.exe" : "./bin/ffmpeg";
|
const FFMPEG = os.platform() === "win32" ? ".\\bin\\ffmpeg.exe" : "./bin/ffmpeg";
|
||||||
const MAX_STICKER_SIZE = 900 * 1024;
|
const MAX_STICKER_SIZE = 900 * 1024;
|
||||||
const SESSION_TIMEOUT = 2 * 60 * 1000;
|
const SESSION_TIMEOUT = 2 * 60 * 1000;
|
||||||
const MAX_MEDIA = 10;
|
const MAX_MEDIA = 30;
|
||||||
|
|
||||||
// ── Helpers ───────────────────────────────────────────────────
|
// ── Helpers ───────────────────────────────────────────────────
|
||||||
function ensureDownloadsDir() {
|
function ensureDownloadsDir() {
|
||||||
|
|||||||
@@ -1,32 +1,62 @@
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
function parseValue(v) {
|
function parseConf(raw) {
|
||||||
v = v.trim();
|
// Remove comentários inline e de linha inteira, preservando estrutura
|
||||||
|
const lines = raw.split("\n");
|
||||||
|
|
||||||
// lista: [a, b, c]
|
const cleaned = [];
|
||||||
if (v.startsWith("[") && v.endsWith("]")) {
|
let insideList = false;
|
||||||
return v
|
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)
|
.slice(1, -1)
|
||||||
.split(",")
|
.split(",")
|
||||||
.map(x => x.trim())
|
.map(x => x.trim())
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
|
} else {
|
||||||
|
result[key] = raw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const raw = fs.readFileSync("manybot.conf", "utf8");
|
const raw = fs.readFileSync("manybot.conf", "utf8");
|
||||||
|
const config = parseConf(raw);
|
||||||
const config = Object.fromEntries(
|
|
||||||
raw
|
|
||||||
.split("\n")
|
|
||||||
.map(l => l.trim())
|
|
||||||
.filter(l => l && !l.startsWith("#"))
|
|
||||||
.map(l => {
|
|
||||||
const [k, ...v] = l.split("=");
|
|
||||||
return [k.trim(), parseValue(v.join("="))];
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
export const CLIENT_ID = config.CLIENT_ID ?? "bot_permanente";
|
export const CLIENT_ID = config.CLIENT_ID ?? "bot_permanente";
|
||||||
export const BOT_PREFIX = config.BOT_PREFIX ?? "🤖 *ManyBot:* ";
|
export const BOT_PREFIX = config.BOT_PREFIX ?? "🤖 *ManyBot:* ";
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ export async function handleMessage(msg) {
|
|||||||
const chat = await msg.getChat();
|
const chat = await msg.getChat();
|
||||||
const chatId = getChatId(chat);
|
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;
|
if (!CHATS.includes(chatId)) return;
|
||||||
|
}
|
||||||
|
|
||||||
const ctx = await buildMessageContext(msg, chat, BOT_PREFIX);
|
const ctx = await buildMessageContext(msg, chat, BOT_PREFIX);
|
||||||
logger.msg(ctx);
|
logger.msg(ctx);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
import pkg from "whatsapp-web.js";
|
import pkg from "whatsapp-web.js";
|
||||||
import qrcode from "qrcode-terminal";
|
import qrcode from "qrcode-terminal";
|
||||||
import { CLIENT_ID } from "../config.js";
|
import { CLIENT_ID } from "../config.js";
|
||||||
|
import { resolvePuppeteerConfig } from "../client/environment.js";
|
||||||
|
|
||||||
const { Client, LocalAuth } = pkg;
|
const { Client, LocalAuth } = pkg;
|
||||||
|
|
||||||
@@ -17,7 +18,15 @@ if (!arg) {
|
|||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
authStrategy: new LocalAuth({ clientId: CLIENT_ID }),
|
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) => {
|
client.on("qr", (qr) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user