Skip to content

Commit b94d603

Browse files
committed
a
1 parent 5ba68c9 commit b94d603

9 files changed

Lines changed: 141 additions & 51 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ env.js
22
.wwebjs_auth
33
.wwebjs_cache
44
downloads
5+
node_modules/

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,10 @@
1-
# manybot
2-
Cool whatsapp bot. Local and free.
1+
# ManyBot!
2+
3+
Criei esse bot para servir um grupo de amigos. Meu foco não é fazer ele funcionar para todo mundo.
4+
5+
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.
6+
7+
Algumas funcionalidades desse bot inclui:
8+
- Funciona em multiplos chats em apenas uma única sessão
9+
- Comandos de jogos e download com yt-dlp
10+
-

deploy.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
3+
4+
5+
TAG=$(git describe --tags --abbrev=0)
6+
npm version $TAG --no-git-tag-version

get_id.js

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
// main.js
1+
// get_id.js
2+
3+
const arg = process.argv[2]; // argumento passado no node
4+
if (!arg) {
5+
console.log("Use: node get_id.js grupos|contatos|<nome>");
6+
process.exit(0);
7+
}
8+
9+
console.log("[PESQUISANDO] Aguarde...");
10+
211
import pkg from 'whatsapp-web.js';
312
const { Client, LocalAuth } = pkg;
413
import qrcode from 'qrcode-terminal';
@@ -15,22 +24,37 @@ client.on('qr', qr => {
1524
qrcode.generate(qr, { small: true });
1625
});
1726

18-
client.on('ready', () => console.log("[BOT] WhatsApp conectado e sessão permanente"));
27+
client.on('ready', () => {
28+
console.log("[BOT] WhatsApp conectado e sessão permanente");
29+
});
1930

20-
client.on('message_create', async msg => {
21-
try {
22-
const chat = await msg.getChat(); // pega o chat uma única vez
31+
client.on('ready', async () => {
32+
const chats = await client.getChats();
2333

24-
console.log("==================================");
25-
console.log(`CHAT NAME : ${chat.name || chat.id.user || "Sem nome"}`);
26-
console.log(`CHAT ID : ${chat.id._serialized}`);
27-
console.log(`FROM : ${msg.from}`);
28-
console.log(`BODY : ${msg.body}`);
29-
console.log("==================================\n");
34+
let filtered = [];
3035

31-
} catch (err) {
32-
console.error("[ERRO]", err);
36+
if (arg.toLowerCase() === "grupos") {
37+
filtered = chats.filter(c => c.isGroup);
38+
} else if (arg.toLowerCase() === "contatos") {
39+
filtered = chats.filter(c => !c.isGroup);
40+
} else {
41+
const search = arg.toLowerCase();
42+
filtered = chats.filter(c => (c.name || c.id.user).toLowerCase().includes(search));
3343
}
44+
45+
if (filtered.length === 0) {
46+
console.log("Nenhum chat encontrado com esse filtro.");
47+
} else {
48+
console.log(`Encontrados ${filtered.length} chats:`);
49+
filtered.forEach(c => {
50+
console.log("================================");
51+
console.log("NAME:", c.name || c.id.user);
52+
console.log("ID:", c.id._serialized);
53+
console.log("GROUP:", c.isGroup);
54+
});
55+
}
56+
57+
process.exit(0); // fecha o script após listar
3458
});
3559

3660
client.initialize();

main.js

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,54 @@
1+
// main_global.js
2+
console.log("[CARREGANDO] Aguarde...");
3+
14
import pkg from 'whatsapp-web.js';
25
const { Client, LocalAuth, MessageMedia } = pkg;
3-
46
import qrcode from 'qrcode-terminal';
57
import fs from 'fs';
8+
import { exec } from 'child_process';
69

7-
const CHAT_ID_ALVO = process.argv[2];
8-
if (!CHAT_ID_ALVO) {
9-
console.error("Use: node main.js <ID_DO_CHAT>");
10-
process.exit(1);
11-
}
12-
13-
// Cada chat tem um clientId único e persistente
14-
const CLIENT_ID = `chat_${CHAT_ID_ALVO.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
10+
const CLIENT_ID = "bot_permanente"; // sessão única global
1511
const BOT_PREFIX = "🤖 *ManyBot:* ";
1612

13+
// lista fixa de chats que queremos interagir
14+
import { CHATS_PERMITIDOS } from "./env.js"
15+
// parecido com isso:
16+
/*
17+
export const CHATS_PERMITIDOS = [
18+
"123456789101234567@c.us", // pedrinho
19+
"987654321012345678@g.us" // escola
20+
];
21+
*/
22+
23+
let jogoAtivo = null;
24+
25+
// criar client único
1726
const client = new Client({
1827
authStrategy: new LocalAuth({ clientId: CLIENT_ID }),
19-
puppeteer: {
20-
headless: true,
21-
args: ['--no-sandbox', '--disable-setuid-sandbox'],
22-
timeout: 60000,
23-
}
28+
puppeteer: { headless: true }
2429
});
2530

2631
client.on('qr', qr => {
27-
console.log(`[${CHAT_ID_ALVO}] QR Code gerado. Escaneie apenas uma vez:`);
32+
console.log("[BOT] QR Code gerado. Escaneie apenas uma vez:");
2833
qrcode.generate(qr, { small: true });
2934
});
3035

31-
client.on('ready', () => console.log(`[${CHAT_ID_ALVO}] WhatsApp conectado.`));
36+
client.on('ready', () => {
37+
exec("clear");
38+
console.log("[BOT] WhatsApp conectado e sessão permanente");
39+
});
3240

3341
client.on('disconnected', reason => {
34-
console.warn(`[${CHAT_ID_ALVO}] Desconectado: ${reason}. Tentando reconectar...`);
42+
console.warn(`[BOT] Desconectado: ${reason}. Tentando reconectar...`);
3543
setTimeout(() => client.initialize(), 5000);
3644
});
3745

3846
client.on('message_create', async msg => {
3947
try {
4048
const chat = await msg.getChat();
41-
if (chat.id._serialized !== CHAT_ID_ALVO) return;
49+
50+
// filtra apenas chats permitidos
51+
if (!CHATS_PERMITIDOS.includes(chat.id._serialized)) return;
4252

4353
console.log("==================================");
4454
console.log(`CHAT NAME : ${chat.name || chat.id.user || "Sem nome"}`);
@@ -55,6 +65,7 @@ client.on('message_create', async msg => {
5565
}
5666
});
5767

68+
5869
// ---------------- Funções de envio ----------------
5970

6071
async function enviarVideo(cliente, chatId, caminhoArquivo) {
@@ -88,7 +99,6 @@ function iniciarJogo(chat) {
8899
jogoAtivo = numeroSecreto;
89100

90101
console.log(`[JOGO] ${chat.name}: Número escolhido ${numeroSecreto}`);
91-
chat.sendMessage(botMsg("Hora do jogo! Tentem adivinhar o número de 1 a 100!"));
92102
}
93103

94104
// ---------------- Download ----------------
@@ -101,45 +111,64 @@ let processingQueue = false;
101111
// Garantir que a pasta downloads exista
102112
if (!fs.existsSync('downloads')) fs.mkdirSync('downloads');
103113

104-
import { exec } from "child_process";
114+
function runYtDlp(cmd1, cmd2) {
115+
return new Promise((resolve, reject) => {
116+
exec(cmd1, (error, stdout, stderr) => {
117+
if (!error) return resolve({ stdout, stderr });
118+
119+
exec(cmd2, (error2, stdout2, stderr2) => {
120+
if (error2) return reject(error2);
121+
resolve({ stdout: stdout2, stderr: stderr2 });
122+
});
123+
});
124+
});
125+
}
105126

106127
function get_video(url, id) {
107128
downloadsAtivos++;
108129

109-
return new Promise((resolve, reject) => {
110-
const cmd = `yt-dlp -t mp4 --print after_move:filepath -o "downloads/${id}.%(ext)s" "${url}"`;
130+
return new Promise(async (resolve, reject) => {
131+
const cmd1 = `yt-dlp -t mp4 --print after_move:filepath -o "downloads/${id}.%(ext)s" "${url}"`;
132+
const cmd2 = `.\yt-dlp.exe -t mp4 --print after_move:filepath -o "downloads/${id}.%(ext)s" "${url}"`;
111133

112-
exec(cmd, (error, stdout, stderr) => {
134+
try {
135+
const { stdout, stderr } = await runYtDlp(cmd1, cmd2);
113136
downloadsAtivos--;
114137

115138
if (stderr) console.error(stderr);
116-
if (error) return reject(new Error(`yt-dlp falhou: ${error.message}`));
117139

118140
const filepath = stdout.trim();
119141
if (!filepath) return reject(new Error("yt-dlp não retornou filepath"));
120142

121143
resolve(filepath);
122-
});
144+
} catch (err) {
145+
downloadsAtivos--;
146+
reject(new Error(`yt-dlp falhou: ${err.message}`));
147+
}
123148
});
124149
}
125150

126151
function get_audio(url, id) {
127152
downloadsAtivos++;
128153

129-
return new Promise((resolve, reject) => {
130-
const cmd = `yt-dlp -t mp3 --print after_move:filepath -o "downloads/${id}.%(ext)s" "${url}"`;
154+
return new Promise(async (resolve, reject) => {
155+
const cmd1 = `yt-dlp -t mp3 --print after_move:filepath -o "downloads/${id}.%(ext)s" "${url}"`;
156+
const cmd2 = `.\yt-dlp.exe -t mp3 --print after_move:filepath -o "downloads/${id}.%(ext)s" "${url}"`;
131157

132-
exec(cmd, (error, stdout, stderr) => {
158+
try {
159+
const { stdout, stderr } = await runYtDlp(cmd1, cmd2);
133160
downloadsAtivos--;
134161

135162
if (stderr) console.error(stderr);
136-
if (error) return reject(new Error(`yt-dlp falhou: ${error.message}`));
137163

138164
const filepath = stdout.trim();
139165
if (!filepath) return reject(new Error("yt-dlp não retornou filepath"));
140166

141167
resolve(filepath);
142-
});
168+
} catch (err) {
169+
downloadsAtivos--;
170+
reject(new Error(`yt-dlp falhou: ${err.message}`));
171+
}
143172
});
144173
}
145174

@@ -188,15 +217,28 @@ async function processarComando(msg) {
188217
if (tokens.length === 1) {
189218
chat.sendMessage(botMsg(
190219
"- `!many ping` -> testa se estou funcionando\n" +
191-
"- `!many jogo` -> jogo de adivinhação\n" +
220+
"- `!many adivinhação <começar|parar>` -> jogo de adivinhação\n" +
192221
"- `!many video <link>` -> baixo um vídeo da internet para você!\n" +
193222
"- `!many audio <link>` -> baixo um audio da internet para você!"
194223
));
195224
return;
196225
}
197226

198227
if (tokens[1] === "ping") chat.sendMessage(botMsg("pong 🏓"));
199-
if (tokens[1] === "jogo") iniciarJogo(chat);
228+
if (tokens[1] === "adivinhação") {
229+
if (tokens[2] === undefined) {
230+
chat.sendMessage(botMsg("Acho que você se esqueceu de algo! 😅\n" +
231+
"🏁 `!many adivinhação começar` -> começa o jogo\n" +
232+
"🛑 `!many adivinhação parar` -> para o jogo atual"
233+
));
234+
} else if (tokens[2] === "começar") {
235+
iniciarJogo(chat);
236+
chat.sendMessage(botMsg("Hora do jogo! 🏁 Tentem adivinhar o número de 1 a 100 que eu estou pensando!"));
237+
} else if (tokens[2] === "parar") {
238+
jogoAtivo = null
239+
chat.sendMessage(botMsg("O jogo atual foi interrompido 🛑"));
240+
}
241+
}
200242

201243
if (tokens[1] === "video" && tokens[2]) {
202244
chat.sendMessage(botMsg("⏳ Baixando vídeo, aguarde..."));

package-lock.json

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"name": "whatsapp-bot",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"type": "module",
55
"dependencies": {
66
"whatsapp-web.js": "^1.24.0",
77
"qrcode-terminal": "^0.12.0"
88
}
9-
}
9+
}

teste.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const str = "�»⃟⃫⚡️⃥��������������☆�";
2+
3+
// percorre cada caractere
4+
for (const char of str) {
5+
const code = char.codePointAt(0); // pega o ponto de código Unicode
6+
process.stdout.write(`${char} (U+${code.toString(16).toUpperCase()})\n`);
7+
}

yt-dlp.exe

17.6 MB
Binary file not shown.

0 commit comments

Comments
 (0)