-
Notifications
You must be signed in to change notification settings - Fork 0
/
wbm-api.js.bak
231 lines (213 loc) · 7.52 KB
/
wbm-api.js.bak
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
const puppeteer = require("puppeteer");
const qrcode = require("qrcode-terminal");
const { from, merge } = require('rxjs');
const { take } = require('rxjs/operators');
const path = require('path');
var rimraf = require("rimraf");
let browser = null;
let page = null;
let counter = { fails: 0, success: 0 }
const tmpPath = path.resolve(__dirname, '../tmp');
const SELECTORS = {
LOADING: "progress",
INSIDE_CHAT: "document.getElementsByClassName('two')[0]",
QRCODE_PAGE: "body > div > div > .landing-wrapper",
QRCODE_DATA: "div[data-ref]",
QRCODE_DATA_ATTR: "data-ref",
SEND_BUTTON: 'div:nth-child(2) > button > span[data-icon="send"]'
};
/**
* Initialize browser, page and setup page desktop mode
*/
async function start({ showBrowser = false, qrCodeData = false, session = true } = {}) {
if (!session) {
deleteSession(tmpPath);
}
const args = {
headless: !showBrowser,
userDataDir: tmpPath,
args: ["--no-sandbox",
// "--blink-settings=imagesEnabled=false"]
]
}
try {
browser = await puppeteer.launch(args);
page = await browser.newPage();
// prevent dialog blocking page and just accept it(necessary when a message is sent too fast)
page.on("dialog", async dialog => { await dialog.accept(); });
// fix the chrome headless mode true issues
// https://gitmemory.com/issue/GoogleChrome/puppeteer/1766/482797370
await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36");
//await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36");
page.setDefaultTimeout(60000);
await page.goto("https://web.whatsapp.com");
if (session && await isAuthenticated()) {
return;
}
else {
if (qrCodeData) {
console.log('Getting QRCode data...');
console.log('Note: You should use wbm.waitQRCode() inside wbm.start() to avoid errors.');
return await getQRCodeData();
} else {
await generateQRCode();
}
}
} catch (err) {
deleteSession(tmpPath);
throw err;
}
}
/**
* Check if needs to scan qr code or already is is inside the chat
*/
function isAuthenticated() {
console.log('Authenticating...');
return merge(needsToScan(page), isInsideChat(page))
.pipe(take(1))
.toPromise();
}
function needsToScan() {
return from(
page
.waitForSelector(SELECTORS.QRCODE_PAGE, {
timeout: 0,
}).then(() => false)
);
}
function isInsideChat() {
return from(
page
.waitForFunction(SELECTORS.INSIDE_CHAT,
{
timeout: 0,
}).then(() => true)
);
}
function deleteSession() {
rimraf.sync(tmpPath);
}
/**
* return the data used to create the QR Code
*/
async function getQRCodeData() {
await page.waitForSelector(SELECTORS.QRCODE_DATA, { timeout: 60000 });
const qrcodeData = await page.evaluate((SELECTORS) => {
let qrcodeDiv = document.querySelector(SELECTORS.QRCODE_DATA);
return qrcodeDiv.getAttribute(SELECTORS.QRCODE_DATA_ATTR);
}, SELECTORS);
return await qrcodeData;
}
/**
* Access whatsapp web page, get QR Code data and generate it on terminal
*/
async function generateQRCode() {
try {
console.log("generating QRCode...");
const qrcodeData = await getQRCodeData();
qrcode.generate(qrcodeData, { small: true });
console.log("QRCode generated! Scan it using Whatsapp App.");
} catch (err) {
throw await QRCodeExeption("QR Code can't be generated(maybe your connection is too slow).");
}
await waitQRCode();
}
/**
* Wait 30s to the qrCode be hidden on page
*/
async function waitQRCode() {
// if user scan QR Code it will be hidden
try {
await page.waitForSelector(SELECTORS.QRCODE_PAGE, { timeout: 30000, hidden: true });
} catch (err) {
throw await QRCodeExeption("Dont't be late to scan the QR Code.");
}
}
/**
* Close browser and show an error message
* @param {string} msg
*/
async function QRCodeExeption(msg) {
await browser.close();
return "QRCodeException: " + msg;
}
/**
* @param {string} phone phone number: '5535988841854'
* @param {string} message Message to send to phone number
* Send message to a phone number
*/
async function sendTo(phoneOrContact, message) {
let phone = phoneOrContact;
if (typeof phoneOrContact === "object") {
phone = phoneOrContact.phone;
message = generateCustomMessage(phoneOrContact, message);
}
try {
let idpesan = Math.floor(100000000 + Math.random() * 900000000);
process.stdout.write("Sending Message...\r");
await page.evaluate((phone,message,idpesan) => {
if (document.querySelector(`.targetklik`) != null){
document.querySelector(`.targetklik`).remove();
}
document.getElementById("app").insertAdjacentHTML("afterend",
`<a style="z-index: 9999999;position: fixed;height:16px;width:16px;background:black;" href="https://web.whatsapp.com/send?phone=${phone}&text=${encodeURIComponent(message)}" title="https://web.whatsapp.com/send?phone=${phone}&text=${encodeURIComponent(message)}" target="_blank" rel="noopener noreferrer" class="selectable-text copyable-text targetklik"></a>"`);
}, phone,message,idpesan).then((sum) => {
setTimeout(() => {
}, 2000)
});
await page.waitForSelector(`.targetklik`);
await page.click(`.targetklik`);
//await page.goto(`https://web.whatsapp.com/send?phone=${phone}&text=${encodeURIComponent(message)}`);
await page.waitForSelector(SELECTORS.LOADING, { hidden: true, timeout: 10000 });
await page.waitForSelector(SELECTORS.SEND_BUTTON, { timeout: 2000 });
await page.keyboard.press("Enter");
await page.waitFor(3000);
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write(`${phone} Sent\n`);
counter.success++;
} catch (err) {
console.log(err);
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write(`${phone} Failed\n`);
counter.fails++;
}
}
/**
* @param {array} phones Array of phone numbers: ['5535988841854', ...]
* @param {string} message Message to send to every phone number
* Send same message to every phone number
*/
async function send(phoneOrContacts, message) {
for (let phoneOrContact of phoneOrContacts) {
await sendTo(phoneOrContact, message);
}
}
/**
* @param {object} contact contact with several properties defined by the user
* @param {string} messagePrototype Custom message to send to every phone number
* @returns {string} message
* Replace all text between {{}} to respective contact property
*/
function generateCustomMessage(contact, messagePrototype) {
let message = messagePrototype;
for (let property in contact) {
message = message.replace(new RegExp(`{{${property}}}`, "g"), contact[property]);
}
return message;
}
/**
* Close browser and show results(number of messages sent and failed)
*/
async function end() {
await browser.close();
console.log(`Result: ${counter.success} sent, ${counter.fails} failed`);
}
module.exports = {
start,
send,
sendTo,
end,
waitQRCode
}