coffeeinabit 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/public/dashboard.html +35 -82
- package/public/images/favicon.png +0 -0
- package/public/images/favicon.svg +8 -0
- package/public/login.html +15 -52
- package/public/styles.css +263 -123
- package/tools/get_messages.js +120 -227
- package/tools/human_typing.js +37 -2
- package/tools/send_messages.js +194 -28
package/tools/get_messages.js
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
export async function executeGetMessages(page, action) {
|
|
2
|
+
console.log('[get_messages] Starting executeGetMessages');
|
|
2
3
|
const username = action.parameters?.username || action.username;
|
|
3
4
|
|
|
5
|
+
console.log('[get_messages] Username:', username);
|
|
6
|
+
|
|
4
7
|
if (!username) {
|
|
8
|
+
console.error('[get_messages] Missing username');
|
|
5
9
|
throw new Error('Missing username for get_messages');
|
|
6
10
|
}
|
|
7
11
|
|
|
8
12
|
const profileUrl = `https://www.linkedin.com/in/${username}`;
|
|
13
|
+
console.log('[get_messages] Navigating to profile:', profileUrl);
|
|
9
14
|
await page.goto(profileUrl, {
|
|
10
15
|
waitUntil: 'load',
|
|
11
16
|
timeout: Math.floor(Math.random() * 20000) + 40000
|
|
12
17
|
});
|
|
18
|
+
console.log('[get_messages] Page loaded, URL:', page.url());
|
|
13
19
|
|
|
14
20
|
await page.waitForLoadState('domcontentloaded');
|
|
15
21
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
@@ -19,7 +25,10 @@ export async function executeGetMessages(page, action) {
|
|
|
19
25
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
20
26
|
await page.evaluate(() => { window.scrollTo(0, 300); });
|
|
21
27
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
22
|
-
|
|
28
|
+
|
|
29
|
+
console.log('[get_messages] Closing all conversation bubbles');
|
|
30
|
+
await closeAllConversationBubbles(page);
|
|
31
|
+
|
|
23
32
|
try {
|
|
24
33
|
await page.waitForSelector('button[aria-label^="Message"], main button.artdeco-button--primary', {
|
|
25
34
|
timeout: 5000,
|
|
@@ -27,18 +36,21 @@ export async function executeGetMessages(page, action) {
|
|
|
27
36
|
});
|
|
28
37
|
} catch (error) {
|
|
29
38
|
}
|
|
30
|
-
|
|
39
|
+
|
|
31
40
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
32
41
|
|
|
42
|
+
console.log('[get_messages] Checking for pending connection request');
|
|
33
43
|
const pendingButton = await getButtonByText(page, 'Pending', true);
|
|
34
44
|
if (pendingButton) {
|
|
45
|
+
console.log('[get_messages] Connection request is pending');
|
|
35
46
|
return {
|
|
36
47
|
action: 'get_messages',
|
|
37
48
|
result: { status: 'connection_request_pending', message: `Connection request pending for ${username}. Not connected` },
|
|
38
49
|
status: 'pending'
|
|
39
50
|
};
|
|
40
51
|
}
|
|
41
|
-
|
|
52
|
+
|
|
53
|
+
console.log('[get_messages] Trying to find and click Message button');
|
|
42
54
|
let clicked = false;
|
|
43
55
|
|
|
44
56
|
const checkOverlayAppeared = async (page) => {
|
|
@@ -87,8 +99,8 @@ export async function executeGetMessages(page, action) {
|
|
|
87
99
|
if (await btn.isVisible().catch(() => false)) {
|
|
88
100
|
await btn.scrollIntoViewIfNeeded();
|
|
89
101
|
await new Promise(resolve => setTimeout(resolve, 300));
|
|
90
|
-
await btn.click({ timeout: 5000
|
|
91
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
102
|
+
await btn.click({ timeout: 5000 });
|
|
103
|
+
await new Promise(resolve => setTimeout(resolve, 800));
|
|
92
104
|
return await checkOverlayAppeared(page);
|
|
93
105
|
}
|
|
94
106
|
} catch (error) {}
|
|
@@ -100,8 +112,8 @@ export async function executeGetMessages(page, action) {
|
|
|
100
112
|
if (await btn.isVisible().catch(() => false)) {
|
|
101
113
|
await btn.scrollIntoViewIfNeeded();
|
|
102
114
|
await new Promise(resolve => setTimeout(resolve, 300));
|
|
103
|
-
await btn.click({ timeout: 5000
|
|
104
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
115
|
+
await btn.click({ timeout: 5000 });
|
|
116
|
+
await new Promise(resolve => setTimeout(resolve, 800));
|
|
105
117
|
return await checkOverlayAppeared(page);
|
|
106
118
|
}
|
|
107
119
|
} catch (error) {}
|
|
@@ -112,14 +124,13 @@ export async function executeGetMessages(page, action) {
|
|
|
112
124
|
const classToken = 'DhBcSsKzUnyKdEOWwBJmWavDjlHFWuqygdMVO';
|
|
113
125
|
const candidates = await page.locator(`button.artdeco-button--primary.${classToken}`).all();
|
|
114
126
|
for (const btn of candidates.slice(0, 3)) {
|
|
115
|
-
const
|
|
116
|
-
if (!
|
|
127
|
+
const v = await btn.isVisible().catch(() => false);
|
|
128
|
+
if (!v) continue;
|
|
117
129
|
await btn.scrollIntoViewIfNeeded();
|
|
118
130
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
119
|
-
await btn.click({ timeout: 5000
|
|
131
|
+
await btn.click({ timeout: 5000 });
|
|
120
132
|
await new Promise(resolve => setTimeout(resolve, 800));
|
|
121
|
-
|
|
122
|
-
if (ok) return true;
|
|
133
|
+
if (await checkOverlayAppeared(page)) return true;
|
|
123
134
|
}
|
|
124
135
|
} catch (error) {}
|
|
125
136
|
return false;
|
|
@@ -129,164 +140,34 @@ export async function executeGetMessages(page, action) {
|
|
|
129
140
|
const buttons = await page.locator('button[aria-label^="Message"]').all();
|
|
130
141
|
for (const btn of buttons) {
|
|
131
142
|
const isVisible = await btn.isVisible().catch(() => false);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
await btn.scrollIntoViewIfNeeded();
|
|
135
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
136
|
-
await btn.click({ timeout: 5000, force: false });
|
|
137
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
138
|
-
return await checkOverlayAppeared(page);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
} catch (error) {
|
|
142
|
-
}
|
|
143
|
-
return false;
|
|
144
|
-
},
|
|
145
|
-
async () => {
|
|
146
|
-
try {
|
|
147
|
-
const buttons = await page.locator('main button[aria-label^="Message"]').all();
|
|
148
|
-
for (const btn of buttons) {
|
|
149
|
-
const isVisible = await btn.isVisible().catch(() => false);
|
|
150
|
-
if (isVisible) {
|
|
151
|
-
await btn.scrollIntoViewIfNeeded();
|
|
152
|
-
await new Promise(resolve => setTimeout(resolve, 300));
|
|
153
|
-
await btn.click({ timeout: 5000, force: false });
|
|
154
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
155
|
-
return await checkOverlayAppeared(page);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
} catch (error) {
|
|
159
|
-
}
|
|
160
|
-
return false;
|
|
161
|
-
},
|
|
162
|
-
async () => {
|
|
163
|
-
try {
|
|
164
|
-
const buttons = await page.locator('main button.artdeco-button--primary').all();
|
|
165
|
-
for (const btn of buttons) {
|
|
166
|
-
try {
|
|
167
|
-
const text = await btn.textContent().catch(() => '');
|
|
168
|
-
const ariaLabel = await btn.getAttribute('aria-label').catch(() => '');
|
|
169
|
-
const isVisible = await btn.isVisible().catch(() => false);
|
|
170
|
-
|
|
171
|
-
if (isVisible && text && text.trim().includes('Message') &&
|
|
172
|
-
(!text.includes('Pending')) &&
|
|
173
|
-
(!ariaLabel || !ariaLabel.includes('Pending'))) {
|
|
174
|
-
await btn.scrollIntoViewIfNeeded();
|
|
175
|
-
await new Promise(resolve => setTimeout(resolve, 300));
|
|
176
|
-
await btn.click({ timeout: 5000, force: false });
|
|
177
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
178
|
-
return await checkOverlayAppeared(page);
|
|
179
|
-
}
|
|
180
|
-
} catch (error) {
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
} catch (error) {
|
|
185
|
-
}
|
|
186
|
-
return false;
|
|
187
|
-
},
|
|
188
|
-
async () => {
|
|
189
|
-
try {
|
|
190
|
-
const allButtons = await page.locator('main button').all();
|
|
191
|
-
for (const btn of allButtons) {
|
|
192
|
-
try {
|
|
193
|
-
const text = await btn.textContent().catch(() => '');
|
|
194
|
-
const ariaLabel = await btn.getAttribute('aria-label').catch(() => '');
|
|
195
|
-
const isVisible = await btn.isVisible().catch(() => false);
|
|
196
|
-
|
|
197
|
-
if (isVisible && ((ariaLabel && ariaLabel.startsWith('Message')) ||
|
|
198
|
-
(text && text.includes('Message') && !text.includes('Pending')))) {
|
|
199
|
-
await btn.scrollIntoViewIfNeeded();
|
|
200
|
-
await new Promise(resolve => setTimeout(resolve, 300));
|
|
201
|
-
await btn.click({ timeout: 5000, force: false });
|
|
202
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
203
|
-
return await checkOverlayAppeared(page);
|
|
204
|
-
}
|
|
205
|
-
} catch (error) {
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
} catch (error) {
|
|
210
|
-
}
|
|
211
|
-
return false;
|
|
212
|
-
},
|
|
213
|
-
async () => {
|
|
214
|
-
try {
|
|
215
|
-
const buttonFound = await page.evaluate(() => {
|
|
216
|
-
const buttons = Array.from(document.querySelectorAll('button'));
|
|
217
|
-
for (const btn of buttons) {
|
|
218
|
-
const ariaLabel = btn.getAttribute('aria-label') || '';
|
|
219
|
-
const textContent = btn.textContent || '';
|
|
220
|
-
const isVisible = btn.offsetParent !== null &&
|
|
221
|
-
window.getComputedStyle(btn).visibility !== 'hidden' &&
|
|
222
|
-
window.getComputedStyle(btn).display !== 'none';
|
|
223
|
-
|
|
224
|
-
if (isVisible && (ariaLabel.startsWith('Message') ||
|
|
225
|
-
(textContent.includes('Message') && !textContent.includes('Pending')))) {
|
|
226
|
-
const rect = btn.getBoundingClientRect();
|
|
227
|
-
if (rect.width > 0 && rect.height > 0) {
|
|
228
|
-
return {
|
|
229
|
-
found: true,
|
|
230
|
-
x: rect.left + rect.width / 2,
|
|
231
|
-
y: rect.top + rect.height / 2
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return { found: false };
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
if (buttonFound.found) {
|
|
240
|
-
await page.mouse.click(buttonFound.x, buttonFound.y);
|
|
241
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
242
|
-
return await checkOverlayAppeared(page);
|
|
243
|
-
}
|
|
244
|
-
} catch (error) {
|
|
245
|
-
}
|
|
246
|
-
return false;
|
|
247
|
-
},
|
|
248
|
-
async () => {
|
|
249
|
-
try {
|
|
250
|
-
const messageBtn = await getButtonByText(page, 'Message', true);
|
|
251
|
-
if (messageBtn) {
|
|
252
|
-
await messageBtn.scrollIntoViewIfNeeded();
|
|
253
|
-
await new Promise(resolve => setTimeout(resolve, 300));
|
|
254
|
-
await messageBtn.click({ timeout: 5000, force: false });
|
|
255
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
256
|
-
return await checkOverlayAppeared(page);
|
|
257
|
-
}
|
|
258
|
-
} catch (error) {
|
|
259
|
-
}
|
|
260
|
-
return false;
|
|
261
|
-
},
|
|
262
|
-
async () => {
|
|
263
|
-
try {
|
|
264
|
-
const messageBtn = await getButtonByText(page, 'Message', false);
|
|
265
|
-
if (messageBtn) {
|
|
266
|
-
await messageBtn.scrollIntoViewIfNeeded();
|
|
143
|
+
if (!isVisible) continue;
|
|
144
|
+
await btn.scrollIntoViewIfNeeded();
|
|
267
145
|
await new Promise(resolve => setTimeout(resolve, 300));
|
|
268
|
-
await
|
|
269
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
270
|
-
|
|
146
|
+
await btn.click({ timeout: 5000 });
|
|
147
|
+
await new Promise(resolve => setTimeout(resolve, 800));
|
|
148
|
+
if (await checkOverlayAppeared(page)) return true;
|
|
271
149
|
}
|
|
272
|
-
} catch (error) {
|
|
273
|
-
}
|
|
150
|
+
} catch (error) {}
|
|
274
151
|
return false;
|
|
275
152
|
}
|
|
276
153
|
];
|
|
277
154
|
|
|
278
|
-
for (
|
|
155
|
+
for (let i = 0; i < clickStrategies.length; i++) {
|
|
156
|
+
console.log('[get_messages] Trying strategy', i + 1);
|
|
279
157
|
try {
|
|
280
|
-
clicked = await
|
|
158
|
+
clicked = await clickStrategies[i]();
|
|
281
159
|
if (clicked) {
|
|
160
|
+
console.log('[get_messages] Strategy', i + 1, 'succeeded, conversation opened');
|
|
282
161
|
break;
|
|
283
162
|
}
|
|
284
163
|
} catch (error) {
|
|
164
|
+
console.log('[get_messages] Strategy', i + 1, 'error:', error.message);
|
|
285
165
|
continue;
|
|
286
166
|
}
|
|
287
167
|
}
|
|
288
168
|
|
|
289
169
|
if (!clicked) {
|
|
170
|
+
console.error('[get_messages] Failed to open conversation - could not find Message button');
|
|
290
171
|
return {
|
|
291
172
|
action: 'get_messages',
|
|
292
173
|
result: { status: 'not_connected', message: `Could not find Message button on ${username}'s profile. This usually means you are not connected with this user on LinkedIn. You can only retrieve messages from users who are in your connections.` },
|
|
@@ -294,89 +175,81 @@ export async function executeGetMessages(page, action) {
|
|
|
294
175
|
};
|
|
295
176
|
}
|
|
296
177
|
|
|
297
|
-
|
|
298
|
-
await page.waitForSelector('.msg-s-message-list-container', { timeout: 15000 });
|
|
299
|
-
} catch (error) {
|
|
300
|
-
try {
|
|
301
|
-
await page.waitForSelector('.msg-overlay-conversation-bubble__content-wrapper', { timeout: 5000 });
|
|
302
|
-
} catch (e) {
|
|
303
|
-
return {
|
|
304
|
-
action: 'get_messages',
|
|
305
|
-
result: { status: 'error', message: `Clicked Message but no conversation view appeared for ${username}` },
|
|
306
|
-
status: 'failed'
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
}
|
|
178
|
+
console.log('[get_messages] Conversation opened successfully');
|
|
310
179
|
|
|
311
180
|
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 2000) + 1000));
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
181
|
+
|
|
182
|
+
console.log('[get_messages] Looking for message input by aria-label');
|
|
183
|
+
const messageData = await page.evaluate(() => {
|
|
184
|
+
const messageInput = document.querySelector('[aria-label="Write a message…"]');
|
|
185
|
+
if (!messageInput) {
|
|
186
|
+
console.log('[get_messages] Message input not found');
|
|
187
|
+
return { found: false, content: '', items: [] };
|
|
317
188
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
const messageList = document.querySelector('.msg-s-message-list');
|
|
328
|
-
if (!messageList) return { shouldContinue: false, scrollHeight: 0 };
|
|
329
|
-
|
|
330
|
-
const currentScrollHeight = messageList.scrollHeight;
|
|
331
|
-
messageList.scrollTop = messageList.scrollHeight;
|
|
189
|
+
|
|
190
|
+
console.log('[get_messages] Found message input, traversing up parent chain');
|
|
191
|
+
let currentElement = messageInput.parentElement;
|
|
192
|
+
let level = 0;
|
|
193
|
+
const maxLevels = 20;
|
|
194
|
+
|
|
195
|
+
while (currentElement && level < maxLevels) {
|
|
196
|
+
level++;
|
|
197
|
+
const hasMessageListContainer = currentElement.classList.contains('msg-s-message-list-container');
|
|
332
198
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
199
|
+
if (hasMessageListContainer) {
|
|
200
|
+
console.log('[get_messages] Found msg-s-message-list-container at level', level);
|
|
201
|
+
const content = currentElement.innerText || currentElement.textContent || '';
|
|
202
|
+
const ul = currentElement.querySelector('ul.msg-s-message-list-content');
|
|
203
|
+
const items = ul ? Array.from(ul.querySelectorAll('li')).map(li => (li.innerText || '').trim()).filter(Boolean) : [];
|
|
204
|
+
return { found: true, content: content.trim(), items: items };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
currentElement = currentElement.parentElement;
|
|
342
208
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const
|
|
348
|
-
|
|
209
|
+
|
|
210
|
+
console.log('[get_messages] Reached max levels or no parent found, using last element');
|
|
211
|
+
if (currentElement) {
|
|
212
|
+
const content = currentElement.innerText || currentElement.textContent || '';
|
|
213
|
+
const ul = currentElement.querySelector('ul.msg-s-message-list-content');
|
|
214
|
+
const items = ul ? Array.from(ul.querySelectorAll('li')).map(li => (li.innerText || '').trim()).filter(Boolean) : [];
|
|
215
|
+
return { found: true, content: content.trim(), items: items };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return { found: false, content: '', items: [] };
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
if (!messageData.found) {
|
|
222
|
+
console.log('[get_messages] Fallback: trying to find message list directly');
|
|
223
|
+
const fallbackData = await page.evaluate(() => {
|
|
224
|
+
const messageList = document.querySelector('.msg-s-message-list-container');
|
|
225
|
+
if (messageList) {
|
|
226
|
+
const content = messageList.innerText || messageList.textContent || '';
|
|
227
|
+
const ul = messageList.querySelector('ul.msg-s-message-list-content');
|
|
228
|
+
const items = ul ? Array.from(ul.querySelectorAll('li')).map(li => (li.innerText || '').trim()).filter(Boolean) : [];
|
|
229
|
+
return { found: true, content: content.trim(), items: items };
|
|
230
|
+
}
|
|
231
|
+
return { found: false, content: '', items: [] };
|
|
349
232
|
});
|
|
350
|
-
|
|
351
|
-
if (
|
|
352
|
-
|
|
233
|
+
|
|
234
|
+
if (fallbackData.found) {
|
|
235
|
+
return {
|
|
236
|
+
action: 'get_messages',
|
|
237
|
+
result: { status: 'success', message: fallbackData.content, items: fallbackData.items },
|
|
238
|
+
status: 'success'
|
|
239
|
+
};
|
|
353
240
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
action: 'get_messages',
|
|
244
|
+
result: { status: 'error', message: `Could not find message container for ${username}` },
|
|
245
|
+
status: 'failed'
|
|
246
|
+
};
|
|
357
247
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
const { content, items } = await page.evaluate(() => {
|
|
362
|
-
const messageList = document.querySelector('.msg-s-message-list');
|
|
363
|
-
if (messageList) {
|
|
364
|
-
const ul = messageList.querySelector('ul.msg-s-message-list-content');
|
|
365
|
-
const lis = ul ? Array.from(ul.querySelectorAll('li')) : [];
|
|
366
|
-
const texts = lis.map(li => (li.innerText || '').trim()).filter(Boolean);
|
|
367
|
-
return { content: (messageList.innerText || ''), items: texts };
|
|
368
|
-
}
|
|
369
|
-
const wrapper = document.querySelector('.msg-overlay-conversation-bubble__content-wrapper');
|
|
370
|
-
const list = wrapper ? wrapper.querySelector('.msg-s-message-list') : null;
|
|
371
|
-
const ul = list ? list.querySelector('ul.msg-s-message-list-content') : null;
|
|
372
|
-
const lis = ul ? Array.from(ul.querySelectorAll('li')) : [];
|
|
373
|
-
const texts = lis.map(li => (li.innerText || '').trim()).filter(Boolean);
|
|
374
|
-
return { content: (wrapper ? wrapper.innerText : ''), items: texts };
|
|
375
|
-
});
|
|
376
|
-
|
|
248
|
+
|
|
249
|
+
console.log('[get_messages] Successfully extracted messages');
|
|
377
250
|
return {
|
|
378
251
|
action: 'get_messages',
|
|
379
|
-
result: { status: 'success', message: content },
|
|
252
|
+
result: { status: 'success', message: messageData.content, items: messageData.items },
|
|
380
253
|
status: 'success'
|
|
381
254
|
};
|
|
382
255
|
}
|
|
@@ -412,3 +285,23 @@ async function getButtonByText(page, text, inMain = false) {
|
|
|
412
285
|
|
|
413
286
|
return null;
|
|
414
287
|
}
|
|
288
|
+
|
|
289
|
+
async function closeAllConversationBubbles(page) {
|
|
290
|
+
console.log('[get_messages] Closing all conversation bubbles');
|
|
291
|
+
await page.evaluate(() => {
|
|
292
|
+
const allButtons = document.querySelectorAll('button');
|
|
293
|
+
const closeButtons = Array.from(allButtons).filter(btn => {
|
|
294
|
+
const useElement = btn.querySelector('svg use[href="#close-small"]');
|
|
295
|
+
return useElement !== null;
|
|
296
|
+
});
|
|
297
|
+
console.log('[get_messages] Found', closeButtons.length, 'close buttons');
|
|
298
|
+
closeButtons.forEach(btn => {
|
|
299
|
+
try {
|
|
300
|
+
btn.click();
|
|
301
|
+
} catch (e) {
|
|
302
|
+
console.log('[get_messages] Error clicking close button:', e.message);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
307
|
+
}
|
package/tools/human_typing.js
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
|
-
export async function humanLikeType(element, text) {
|
|
1
|
+
export async function humanLikeType(element, text, mistypeProbability = 0.05) {
|
|
2
2
|
for (const char of text) {
|
|
3
|
+
const shouldMistype = Math.random() < mistypeProbability;
|
|
4
|
+
|
|
5
|
+
if (shouldMistype && char !== ' ' && char !== '\n') {
|
|
6
|
+
const wrongChar = getRandomMistypeChar(char);
|
|
7
|
+
await element.type(wrongChar, { delay: 0 });
|
|
8
|
+
|
|
9
|
+
const mistypeDelay = Math.floor(Math.random() * 200) + 50;
|
|
10
|
+
await new Promise(resolve => setTimeout(resolve, mistypeDelay));
|
|
11
|
+
|
|
12
|
+
await element.press('Backspace', { delay: 0 });
|
|
13
|
+
|
|
14
|
+
const correctionDelay = Math.floor(Math.random() * 200) + 50;
|
|
15
|
+
await new Promise(resolve => setTimeout(resolve, correctionDelay));
|
|
16
|
+
}
|
|
17
|
+
|
|
3
18
|
await element.type(char, { delay: 0 });
|
|
4
19
|
|
|
5
|
-
const delay = Math.floor(Math.random() *
|
|
20
|
+
const delay = Math.floor(Math.random() * 200) + 50;
|
|
6
21
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
7
22
|
}
|
|
8
23
|
|
|
@@ -10,6 +25,26 @@ export async function humanLikeType(element, text) {
|
|
|
10
25
|
await new Promise(resolve => setTimeout(resolve, finalDelay));
|
|
11
26
|
}
|
|
12
27
|
|
|
28
|
+
function getRandomMistypeChar(correctChar) {
|
|
29
|
+
const alphabet = 'abcdefghijklmnopqrstuvwxyz';
|
|
30
|
+
const numbers = '012389';
|
|
31
|
+
const specialChars = '!@';
|
|
32
|
+
|
|
33
|
+
let pool = alphabet;
|
|
34
|
+
if (/\d/.test(correctChar)) {
|
|
35
|
+
pool = numbers;
|
|
36
|
+
} else if (/[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]/.test(correctChar)) {
|
|
37
|
+
pool = specialChars;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let wrongChar;
|
|
41
|
+
do {
|
|
42
|
+
wrongChar = pool[Math.floor(Math.random() * pool.length)];
|
|
43
|
+
} while (wrongChar === correctChar && pool.length > 1);
|
|
44
|
+
|
|
45
|
+
return wrongChar;
|
|
46
|
+
}
|
|
47
|
+
|
|
13
48
|
export async function readLinkedInCredentials() {
|
|
14
49
|
const fs = (await import('fs')).default;
|
|
15
50
|
const path = (await import('path')).default;
|