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/send_messages.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { humanLikeType } from './human_typing.js';
|
|
2
2
|
|
|
3
3
|
export async function executeSendMessages(page, action) {
|
|
4
|
+
console.log('[send_messages] Starting executeSendMessages');
|
|
4
5
|
const username = action.parameters?.username || action.username;
|
|
5
6
|
let messages = action.parameters?.messages || action.messages;
|
|
6
7
|
|
|
8
|
+
console.log('[send_messages] Username:', username, 'Messages:', messages);
|
|
9
|
+
|
|
7
10
|
if (!username || !messages) {
|
|
11
|
+
console.error('[send_messages] Missing username or messages');
|
|
8
12
|
throw new Error('Missing username or messages for send_messages');
|
|
9
13
|
}
|
|
10
14
|
|
|
@@ -13,99 +17,142 @@ export async function executeSendMessages(page, action) {
|
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
const profileUrl = `https://www.linkedin.com/in/${username}`;
|
|
20
|
+
console.log('[send_messages] Navigating to profile:', profileUrl);
|
|
16
21
|
await page.goto(profileUrl, {
|
|
17
22
|
waitUntil: 'load',
|
|
18
23
|
timeout: Math.floor(Math.random() * 20000) + 40000
|
|
19
24
|
});
|
|
25
|
+
console.log('[send_messages] Page loaded, URL:', page.url());
|
|
20
26
|
|
|
21
27
|
await page.waitForLoadState('domcontentloaded');
|
|
22
28
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
23
29
|
await page.evaluate(() => { window.scrollTo(0, 300); });
|
|
24
30
|
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 2000) + 500));
|
|
25
31
|
|
|
32
|
+
console.log('[send_messages] Closing all conversation bubbles');
|
|
26
33
|
await closeAllConversationBubbles(page);
|
|
27
34
|
|
|
28
35
|
const checkConversationOpened = async () => {
|
|
36
|
+
console.log('[send_messages] Checking if conversation opened');
|
|
29
37
|
for (let i = 0; i < 10; i++) {
|
|
30
38
|
try {
|
|
31
39
|
const url = page.url();
|
|
32
|
-
if (url.includes('/messaging'))
|
|
33
|
-
|
|
40
|
+
if (url.includes('/messaging')) {
|
|
41
|
+
console.log('[send_messages] Conversation opened (URL check)');
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
} catch (e) {
|
|
45
|
+
console.log('[send_messages] Error checking URL:', e.message);
|
|
46
|
+
}
|
|
34
47
|
try {
|
|
35
48
|
const cnt = await page.locator('.msg-s-message-list-container, .msg-overlay-conversation-bubble__content-wrapper').count();
|
|
36
|
-
if (cnt > 0)
|
|
37
|
-
|
|
49
|
+
if (cnt > 0) {
|
|
50
|
+
console.log('[send_messages] Conversation opened (element count:', cnt, ')');
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.log('[send_messages] Error checking elements:', e.message);
|
|
55
|
+
}
|
|
38
56
|
await new Promise(r => setTimeout(r, 500));
|
|
39
57
|
}
|
|
58
|
+
console.log('[send_messages] Conversation not opened after 10 attempts');
|
|
40
59
|
return false;
|
|
41
60
|
};
|
|
42
61
|
|
|
43
62
|
const clickStrategies = [
|
|
44
63
|
async () => {
|
|
64
|
+
console.log('[send_messages] Strategy 1: Looking for button with text "Message"');
|
|
45
65
|
try {
|
|
46
66
|
const btn = page.locator('button:has-text("Message")').first();
|
|
47
67
|
if (await btn.isVisible().catch(() => false)) {
|
|
68
|
+
console.log('[send_messages] Found Message button, clicking...');
|
|
48
69
|
await btn.scrollIntoViewIfNeeded();
|
|
49
70
|
await new Promise(r => setTimeout(r, 300));
|
|
50
71
|
await btn.click({ timeout: 5000 });
|
|
51
72
|
await new Promise(r => setTimeout(r, 800));
|
|
52
73
|
return await checkConversationOpened();
|
|
74
|
+
} else {
|
|
75
|
+
console.log('[send_messages] Message button not visible');
|
|
53
76
|
}
|
|
54
|
-
} catch {
|
|
77
|
+
} catch (e) {
|
|
78
|
+
console.log('[send_messages] Strategy 1 error:', e.message);
|
|
79
|
+
}
|
|
55
80
|
return false;
|
|
56
81
|
},
|
|
57
82
|
async () => {
|
|
83
|
+
console.log('[send_messages] Strategy 2: Looking for button with send-privately-small icon');
|
|
58
84
|
try {
|
|
59
85
|
const btn = page.locator('button:has(svg[data-test-icon="send-privately-small"])').first();
|
|
60
86
|
if (await btn.isVisible().catch(() => false)) {
|
|
87
|
+
console.log('[send_messages] Found send-privately button, clicking...');
|
|
61
88
|
await btn.scrollIntoViewIfNeeded();
|
|
62
89
|
await new Promise(r => setTimeout(r, 300));
|
|
63
90
|
await btn.click({ timeout: 5000 });
|
|
64
91
|
await new Promise(r => setTimeout(r, 800));
|
|
65
92
|
return await checkConversationOpened();
|
|
93
|
+
} else {
|
|
94
|
+
console.log('[send_messages] send-privately button not visible');
|
|
66
95
|
}
|
|
67
|
-
} catch {
|
|
96
|
+
} catch (e) {
|
|
97
|
+
console.log('[send_messages] Strategy 2 error:', e.message);
|
|
98
|
+
}
|
|
68
99
|
return false;
|
|
69
100
|
},
|
|
70
101
|
async () => {
|
|
102
|
+
console.log('[send_messages] Strategy 3: Looking for primary button with class token');
|
|
71
103
|
try {
|
|
72
104
|
const classToken = 'DhBcSsKzUnyKdEOWwBJmWavDjlHFWuqygdMVO';
|
|
73
105
|
const candidates = await page.locator(`button.artdeco-button--primary.${classToken}`).all();
|
|
106
|
+
console.log('[send_messages] Found', candidates.length, 'candidate buttons');
|
|
74
107
|
for (const btn of candidates.slice(0, 3)) {
|
|
75
108
|
const v = await btn.isVisible().catch(() => false);
|
|
76
109
|
if (!v) continue;
|
|
110
|
+
console.log('[send_messages] Clicking candidate button');
|
|
77
111
|
await btn.scrollIntoViewIfNeeded();
|
|
78
112
|
await new Promise(r => setTimeout(r, 200));
|
|
79
113
|
await btn.click({ timeout: 5000 });
|
|
80
114
|
await new Promise(r => setTimeout(r, 800));
|
|
81
115
|
if (await checkConversationOpened()) return true;
|
|
82
116
|
}
|
|
83
|
-
} catch {
|
|
117
|
+
} catch (e) {
|
|
118
|
+
console.log('[send_messages] Strategy 3 error:', e.message);
|
|
119
|
+
}
|
|
84
120
|
return false;
|
|
85
121
|
},
|
|
86
122
|
async () => {
|
|
123
|
+
console.log('[send_messages] Strategy 4: Looking for button with aria-label containing "Message"');
|
|
87
124
|
try {
|
|
88
125
|
const buttons = await page.locator('button[aria-label^="Message"]').all();
|
|
126
|
+
console.log('[send_messages] Found', buttons.length, 'buttons with Message aria-label');
|
|
89
127
|
for (const btn of buttons) {
|
|
90
128
|
const isVisible = await btn.isVisible().catch(() => false);
|
|
91
129
|
if (!isVisible) continue;
|
|
130
|
+
console.log('[send_messages] Clicking Message button');
|
|
92
131
|
await btn.scrollIntoViewIfNeeded();
|
|
93
132
|
await new Promise(r => setTimeout(r, 300));
|
|
94
133
|
await btn.click({ timeout: 5000 });
|
|
95
134
|
await new Promise(r => setTimeout(r, 800));
|
|
96
135
|
if (await checkConversationOpened()) return true;
|
|
97
136
|
}
|
|
98
|
-
} catch {
|
|
137
|
+
} catch (e) {
|
|
138
|
+
console.log('[send_messages] Strategy 4 error:', e.message);
|
|
139
|
+
}
|
|
99
140
|
return false;
|
|
100
141
|
}
|
|
101
142
|
];
|
|
102
143
|
|
|
144
|
+
console.log('[send_messages] Trying to find and click Message button');
|
|
103
145
|
let opened = false;
|
|
104
|
-
for (
|
|
105
|
-
|
|
106
|
-
|
|
146
|
+
for (let i = 0; i < clickStrategies.length; i++) {
|
|
147
|
+
console.log('[send_messages] Trying strategy', i + 1);
|
|
148
|
+
opened = await clickStrategies[i]();
|
|
149
|
+
if (opened) {
|
|
150
|
+
console.log('[send_messages] Strategy', i + 1, 'succeeded, conversation opened');
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
107
153
|
}
|
|
108
154
|
if (!opened) {
|
|
155
|
+
console.error('[send_messages] Failed to open conversation - could not find Message button');
|
|
109
156
|
return {
|
|
110
157
|
action: 'send_messages',
|
|
111
158
|
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.` },
|
|
@@ -113,37 +160,117 @@ export async function executeSendMessages(page, action) {
|
|
|
113
160
|
};
|
|
114
161
|
}
|
|
115
162
|
|
|
163
|
+
console.log('[send_messages] Finding and clicking message input');
|
|
116
164
|
await findAndClickMessageInput(page);
|
|
117
165
|
|
|
118
|
-
|
|
166
|
+
console.log('[send_messages] Processing', messages.length, 'message(s)');
|
|
167
|
+
for (let msgIndex = 0; msgIndex < messages.length; msgIndex++) {
|
|
168
|
+
const message = messages[msgIndex];
|
|
169
|
+
console.log('[send_messages] Processing message', msgIndex + 1, 'of', messages.length, ':', message);
|
|
170
|
+
|
|
119
171
|
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 100) + 500));
|
|
120
172
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
121
173
|
|
|
122
|
-
const editor = page.locator('
|
|
123
|
-
|
|
174
|
+
const editor = page.locator('[aria-label="Write a message…"]').first();
|
|
175
|
+
console.log('[send_messages] Looking for message editor by aria-label');
|
|
176
|
+
|
|
177
|
+
let editorReady = false;
|
|
178
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
179
|
+
console.log('[send_messages] Editor preparation attempt', attempt + 1, 'of 5');
|
|
180
|
+
try {
|
|
181
|
+
const isVisible = await editor.isVisible({ timeout: 2000 }).catch(() => false);
|
|
182
|
+
console.log('[send_messages] Editor visible:', isVisible);
|
|
183
|
+
if (isVisible) {
|
|
184
|
+
console.log('[send_messages] Clicking editor');
|
|
185
|
+
await editor.click({ timeout: 3000, force: true });
|
|
186
|
+
await new Promise(r => setTimeout(r, 200));
|
|
187
|
+
|
|
188
|
+
console.log('[send_messages] Clearing and focusing editor');
|
|
189
|
+
await editor.evaluate((el) => {
|
|
190
|
+
el.focus();
|
|
191
|
+
el.innerHTML = '';
|
|
192
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
await new Promise(r => setTimeout(r, 150));
|
|
196
|
+
|
|
197
|
+
const isFocused = await editor.evaluate((el) => {
|
|
198
|
+
return document.activeElement === el;
|
|
199
|
+
});
|
|
200
|
+
console.log('[send_messages] Editor focused:', isFocused);
|
|
201
|
+
|
|
202
|
+
if (isFocused) {
|
|
203
|
+
editorReady = true;
|
|
204
|
+
console.log('[send_messages] Editor ready!');
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
} catch (e) {
|
|
209
|
+
console.log('[send_messages] Error preparing editor:', e.message);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
await new Promise(r => setTimeout(r, 300));
|
|
213
|
+
console.log('[send_messages] Retrying to find message input');
|
|
214
|
+
await findAndClickMessageInput(page);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!editorReady) {
|
|
218
|
+
console.warn('[send_messages] Editor not ready after 5 attempts, trying one more time');
|
|
219
|
+
await findAndClickMessageInput(page);
|
|
220
|
+
await new Promise(r => setTimeout(r, 500));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
console.log('[send_messages] Typing message:', message);
|
|
224
|
+
await humanLikeType(editor, message);
|
|
225
|
+
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 300) + 300));
|
|
226
|
+
|
|
227
|
+
const textTyped = await editor.evaluate((el) => {
|
|
228
|
+
const text = el.innerText || el.textContent || '';
|
|
229
|
+
return text.trim().length > 0;
|
|
230
|
+
});
|
|
231
|
+
console.log('[send_messages] Text typed successfully:', textTyped);
|
|
232
|
+
|
|
233
|
+
if (!textTyped) {
|
|
234
|
+
console.warn('[send_messages] Text not typed, retrying...');
|
|
235
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
124
236
|
await editor.click();
|
|
125
|
-
await
|
|
237
|
+
await editor.evaluate((el) => {
|
|
238
|
+
el.focus();
|
|
239
|
+
el.dispatchEvent(new Event('focus', { bubbles: true }));
|
|
240
|
+
});
|
|
241
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
242
|
+
console.log('[send_messages] Retrying to type message');
|
|
126
243
|
await humanLikeType(editor, message);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
await
|
|
244
|
+
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 300) + 300));
|
|
245
|
+
|
|
246
|
+
const textTypedRetry = await editor.evaluate((el) => {
|
|
247
|
+
const text = el.innerText || el.textContent || '';
|
|
248
|
+
return text.trim().length > 0;
|
|
249
|
+
});
|
|
250
|
+
console.log('[send_messages] Text typed after retry:', textTypedRetry);
|
|
130
251
|
}
|
|
131
|
-
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 500) + 500));
|
|
132
252
|
|
|
253
|
+
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 200) + 200));
|
|
254
|
+
|
|
255
|
+
console.log('[send_messages] Clicking send button');
|
|
133
256
|
const clickedSend = await clickSendButton(page);
|
|
134
257
|
if (!clickedSend) {
|
|
258
|
+
console.error('[send_messages] Failed to click send button');
|
|
135
259
|
return {
|
|
136
260
|
action: 'send_messages',
|
|
137
261
|
result: { status: 'send_button_not_found', message: 'Could not find send button.' },
|
|
138
262
|
status: 'failed'
|
|
139
263
|
};
|
|
140
264
|
}
|
|
265
|
+
console.log('[send_messages] Send button clicked successfully');
|
|
141
266
|
|
|
142
267
|
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 1000) + 500));
|
|
143
268
|
}
|
|
144
269
|
|
|
270
|
+
console.log('[send_messages] Closing all conversation bubbles');
|
|
145
271
|
await closeAllConversationBubbles(page);
|
|
146
272
|
|
|
273
|
+
console.log('[send_messages] Successfully completed!');
|
|
147
274
|
return {
|
|
148
275
|
action: 'send_messages',
|
|
149
276
|
result: { status: 'success', message: `Message successfully sent to ${username}` },
|
|
@@ -159,43 +286,68 @@ async function typeLikeHuman(page, text) {
|
|
|
159
286
|
}
|
|
160
287
|
|
|
161
288
|
async function findAndClickMessageInput(page) {
|
|
289
|
+
console.log('[send_messages] findAndClickMessageInput: Waiting 1 second');
|
|
162
290
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
163
291
|
|
|
292
|
+
console.log('[send_messages] findAndClickMessageInput: Looking for editor by aria-label');
|
|
164
293
|
const editorClicked = await page.evaluate(() => {
|
|
165
|
-
const editor = document.querySelector('
|
|
294
|
+
const editor = document.querySelector('[aria-label="Write a message…"]');
|
|
166
295
|
if (editor) {
|
|
296
|
+
console.log('[send_messages] Found editor, focusing and clicking');
|
|
167
297
|
editor.focus();
|
|
298
|
+
editor.click();
|
|
299
|
+
editor.dispatchEvent(new Event('focus', { bubbles: true }));
|
|
168
300
|
return true;
|
|
169
301
|
}
|
|
302
|
+
console.log('[send_messages] Editor not found');
|
|
170
303
|
return false;
|
|
171
304
|
});
|
|
172
305
|
|
|
173
306
|
if (editorClicked) {
|
|
307
|
+
console.log('[send_messages] Editor clicked successfully');
|
|
174
308
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
175
309
|
return;
|
|
176
310
|
}
|
|
177
311
|
|
|
312
|
+
console.log('[send_messages] Editor not found, trying placeholder');
|
|
178
313
|
const placeholderClicked = await page.evaluate(() => {
|
|
179
314
|
const placeholder = document.querySelector('.msg-form__placeholder');
|
|
180
315
|
if (placeholder) {
|
|
316
|
+
console.log('[send_messages] Found placeholder, clicking');
|
|
181
317
|
placeholder.click();
|
|
318
|
+
const editor = document.querySelector('[aria-label="Write a message…"]');
|
|
319
|
+
if (editor) {
|
|
320
|
+
editor.focus();
|
|
321
|
+
editor.dispatchEvent(new Event('focus', { bubbles: true }));
|
|
322
|
+
}
|
|
182
323
|
return true;
|
|
183
324
|
}
|
|
325
|
+
console.log('[send_messages] Placeholder not found');
|
|
184
326
|
return false;
|
|
185
327
|
});
|
|
186
328
|
|
|
187
329
|
if (placeholderClicked) {
|
|
330
|
+
console.log('[send_messages] Placeholder clicked successfully');
|
|
188
331
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
332
|
+
} else {
|
|
333
|
+
console.warn('[send_messages] Neither editor nor placeholder found');
|
|
189
334
|
}
|
|
190
335
|
}
|
|
191
336
|
|
|
192
337
|
async function closeAllConversationBubbles(page) {
|
|
338
|
+
console.log('[send_messages] Closing all conversation bubbles');
|
|
193
339
|
await page.evaluate(() => {
|
|
194
|
-
const
|
|
340
|
+
const allButtons = document.querySelectorAll('button');
|
|
341
|
+
const closeButtons = Array.from(allButtons).filter(btn => {
|
|
342
|
+
const useElement = btn.querySelector('svg use[href="#close-small"]');
|
|
343
|
+
return useElement !== null;
|
|
344
|
+
});
|
|
345
|
+
console.log('[send_messages] Found', closeButtons.length, 'close buttons');
|
|
195
346
|
closeButtons.forEach(btn => {
|
|
196
347
|
try {
|
|
197
348
|
btn.click();
|
|
198
349
|
} catch (e) {
|
|
350
|
+
console.log('[send_messages] Error clicking close button:', e.message);
|
|
199
351
|
}
|
|
200
352
|
});
|
|
201
353
|
});
|
|
@@ -203,18 +355,32 @@ async function closeAllConversationBubbles(page) {
|
|
|
203
355
|
}
|
|
204
356
|
|
|
205
357
|
async function clickSendButton(page) {
|
|
358
|
+
console.log('[send_messages] clickSendButton: Waiting 500ms');
|
|
206
359
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
207
360
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
sendButton.
|
|
361
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
362
|
+
console.log('[send_messages] clickSendButton: Attempt', attempt + 1, 'of 10');
|
|
363
|
+
const clicked = await page.evaluate(() => {
|
|
364
|
+
const sendButton = document.querySelector('.msg-form__send-button:not([disabled])');
|
|
365
|
+
if (sendButton && !sendButton.disabled) {
|
|
366
|
+
console.log('[send_messages] Found enabled send button, clicking');
|
|
367
|
+
sendButton.click();
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
370
|
+
console.log('[send_messages] Send button not found or disabled');
|
|
371
|
+
return false;
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
if (clicked) {
|
|
375
|
+
console.log('[send_messages] Send button clicked successfully');
|
|
212
376
|
return true;
|
|
213
377
|
}
|
|
214
|
-
|
|
215
|
-
|
|
378
|
+
|
|
379
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
380
|
+
}
|
|
216
381
|
|
|
217
|
-
|
|
382
|
+
console.error('[send_messages] Failed to click send button after 10 attempts');
|
|
383
|
+
return false;
|
|
218
384
|
}
|
|
219
385
|
|
|
220
386
|
async function getButtonByText(page, text, inMain = false) {
|