coffeeinabit 0.0.26 → 0.0.27
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/linkedin_automation.js +1 -2
- package/package.json +1 -1
- package/public/dashboard.html +1 -1
- package/tools/comment_post.js +1 -1
- package/tools/get_daily_linkedin_connections.js +5 -5
- package/tools/get_messages.js +5 -5
- package/tools/get_new_messages.js +1 -1
- package/tools/get_profile.js +75 -24
- package/tools/human_mouse.js +12 -8
- package/tools/send_connection_request.js +1 -1
- package/tools/send_messages.js +6 -6
package/linkedin_automation.js
CHANGED
|
@@ -543,7 +543,6 @@ export class LinkedInAutomation {
|
|
|
543
543
|
try {
|
|
544
544
|
const screenshot = await this.page.screenshot({
|
|
545
545
|
fullPage: false,
|
|
546
|
-
clip: { x: 0, y: 0, width: 1200, height: 800 },
|
|
547
546
|
type: 'png',
|
|
548
547
|
timeout: 60000
|
|
549
548
|
});
|
|
@@ -963,7 +962,7 @@ export class LinkedInAutomation {
|
|
|
963
962
|
|
|
964
963
|
const launchOptions = {
|
|
965
964
|
headless: this.headless || false,
|
|
966
|
-
viewport: null,
|
|
965
|
+
viewport: (this.headless || false) ? { width: 1920, height: 1080 } : null,
|
|
967
966
|
ignoreHTTPSErrors: true,
|
|
968
967
|
args: [
|
|
969
968
|
'--disable-blink-features=AutomationControlled',
|
package/package.json
CHANGED
package/public/dashboard.html
CHANGED
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
<small class="text-muted" id="screenshotTimestamp">Last updated: --</small>
|
|
111
111
|
</div>
|
|
112
112
|
<div class="text-center">
|
|
113
|
-
<img id="browserScreenshot" class="img-fluid border rounded shadow-sm" style="max-width: 100%; max-height: 400px;" alt="Browser Screenshot">
|
|
113
|
+
<img id="browserScreenshot" class="img-fluid border rounded shadow-sm" style="max-width: 100%; max-height: 400px; object-fit: contain;" alt="Browser Screenshot">
|
|
114
114
|
</div>
|
|
115
115
|
</div>
|
|
116
116
|
</div>
|
package/tools/comment_post.js
CHANGED
|
@@ -44,7 +44,7 @@ export async function executeCommentPost(page, action) {
|
|
|
44
44
|
}
|
|
45
45
|
await waitRandom(1200, 3200, page);
|
|
46
46
|
console.log('[CommentPost] Scrolling to middle of page');
|
|
47
|
-
await page.evaluate(()
|
|
47
|
+
await page.evaluate(function() { window.scrollTo(0, document.body.scrollHeight / 2); });
|
|
48
48
|
await waitRandom(900, 2100, page);
|
|
49
49
|
|
|
50
50
|
console.log('[CommentPost] Searching for comment editor');
|
|
@@ -17,7 +17,7 @@ export async function executeGetDailyLinkedInConnections(page, action) {
|
|
|
17
17
|
|
|
18
18
|
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 5000) + 500));
|
|
19
19
|
|
|
20
|
-
const totalConnections = await page.evaluate(()
|
|
20
|
+
const totalConnections = await page.evaluate(function() {
|
|
21
21
|
const headerElement = document.querySelector('h1');
|
|
22
22
|
if (headerElement) {
|
|
23
23
|
const match = headerElement.textContent.match(/(\d+)\s+Connections?/i);
|
|
@@ -33,7 +33,7 @@ export async function executeGetDailyLinkedInConnections(page, action) {
|
|
|
33
33
|
const maxNoScrollAttempts = 2;
|
|
34
34
|
|
|
35
35
|
while (!shouldStopScrolling) {
|
|
36
|
-
const currentConnections = await page.evaluate(()
|
|
36
|
+
const currentConnections = await page.evaluate(function() {
|
|
37
37
|
function parseConnectionDate(str) {
|
|
38
38
|
if (!str) return null;
|
|
39
39
|
const match = str.match(/Connected on (.+)/i);
|
|
@@ -98,7 +98,7 @@ export async function executeGetDailyLinkedInConnections(page, action) {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
const scrollInfoBefore = await page.evaluate(()
|
|
101
|
+
const scrollInfoBefore = await page.evaluate(function() {
|
|
102
102
|
const main = document.querySelector('main');
|
|
103
103
|
if (main) {
|
|
104
104
|
return {
|
|
@@ -123,7 +123,7 @@ export async function executeGetDailyLinkedInConnections(page, action) {
|
|
|
123
123
|
const containerExists = await mainElement.count();
|
|
124
124
|
|
|
125
125
|
if (containerExists > 0) {
|
|
126
|
-
await mainElement.evaluate(el
|
|
126
|
+
await mainElement.evaluate(function(el) {
|
|
127
127
|
console.log('Main element found, scrolling...');
|
|
128
128
|
console.log('Main scrollHeight:', el.scrollHeight);
|
|
129
129
|
console.log('Main clientHeight:', el.clientHeight);
|
|
@@ -145,7 +145,7 @@ export async function executeGetDailyLinkedInConnections(page, action) {
|
|
|
145
145
|
console.log('Stack trace:', e.stack);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
const scrollInfoAfter = await page.evaluate(()
|
|
148
|
+
const scrollInfoAfter = await page.evaluate(function() {
|
|
149
149
|
const main = document.querySelector('main');
|
|
150
150
|
if (main) {
|
|
151
151
|
return {
|
package/tools/get_messages.js
CHANGED
|
@@ -34,9 +34,9 @@ export async function executeGetMessages(page, action) {
|
|
|
34
34
|
await waitRandom(900, 1400, page);
|
|
35
35
|
await waitRandom(1600, 2600, page);
|
|
36
36
|
|
|
37
|
-
await page.evaluate(()
|
|
37
|
+
await page.evaluate(function() { window.scrollTo(0, 0); });
|
|
38
38
|
await waitRandom(400, 650, page);
|
|
39
|
-
await page.evaluate(()
|
|
39
|
+
await page.evaluate(function() { window.scrollTo(0, 300); });
|
|
40
40
|
await waitRandom(900, 1500, page);
|
|
41
41
|
|
|
42
42
|
console.log('[get_messages] Closing all conversation bubbles');
|
|
@@ -199,7 +199,7 @@ export async function executeGetMessages(page, action) {
|
|
|
199
199
|
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 2000) + 1000));
|
|
200
200
|
|
|
201
201
|
console.log('[get_messages] Looking for message input by aria-label');
|
|
202
|
-
const messageData = await page.evaluate(()
|
|
202
|
+
const messageData = await page.evaluate(function() {
|
|
203
203
|
const messageInput = document.querySelector('[aria-label="Write a message…"]');
|
|
204
204
|
if (!messageInput) {
|
|
205
205
|
console.log('[get_messages] Message input not found');
|
|
@@ -251,7 +251,7 @@ export async function executeGetMessages(page, action) {
|
|
|
251
251
|
|
|
252
252
|
if (!messageData.found) {
|
|
253
253
|
console.log('[get_messages] Fallback: trying to find message list directly');
|
|
254
|
-
const fallbackData = await page.evaluate(()
|
|
254
|
+
const fallbackData = await page.evaluate(function() {
|
|
255
255
|
const messageList = document.querySelector('.msg-s-message-list-container');
|
|
256
256
|
if (messageList) {
|
|
257
257
|
const content = messageList.innerText || messageList.textContent || '';
|
|
@@ -343,7 +343,7 @@ async function getButtonByText(page, text, inMain = false) {
|
|
|
343
343
|
|
|
344
344
|
async function closeAllConversationBubbles(page) {
|
|
345
345
|
console.log('[get_messages] Closing all conversation bubbles');
|
|
346
|
-
await page.evaluate(()
|
|
346
|
+
await page.evaluate(function() {
|
|
347
347
|
const allButtons = document.querySelectorAll('button');
|
|
348
348
|
const closeButtons = Array.from(allButtons).filter(btn => {
|
|
349
349
|
const useElement = btn.querySelector('svg use[href="#close-small"]');
|
|
@@ -239,7 +239,7 @@ export async function executeGetNewMessages(page, action, accessToken) {
|
|
|
239
239
|
|
|
240
240
|
|
|
241
241
|
for (let i = 0; i < 5; i++) {
|
|
242
|
-
await messageContainer.evaluate(el
|
|
242
|
+
await messageContainer.evaluate(function(el) {
|
|
243
243
|
el.scrollBy({ top: -2000, behavior: 'smooth' });
|
|
244
244
|
});
|
|
245
245
|
console.log(`[GetNewMessages] Scrolled up -2000px (${i + 1}/5)`);
|
package/tools/get_profile.js
CHANGED
|
@@ -86,15 +86,45 @@ export async function executeGetProfile(page, action) {
|
|
|
86
86
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
87
87
|
console.log('[GetProfile] Page fully loaded, starting to scroll and extract content');
|
|
88
88
|
|
|
89
|
+
try {
|
|
90
|
+
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.warn('[GetProfile] Network idle timeout, continuing anyway');
|
|
93
|
+
}
|
|
94
|
+
|
|
89
95
|
console.log('[GetProfile] Scrolling down to load profile content');
|
|
90
|
-
|
|
96
|
+
try {
|
|
97
|
+
await gentleScroll(page, 'down');
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (error.message.includes('well-serializable')) {
|
|
100
|
+
console.error('[GetProfile] Serialization error in gentleScroll, trying alternative scroll method');
|
|
101
|
+
await page.evaluate(function() {
|
|
102
|
+
window.scrollTo(0, document.documentElement.scrollHeight);
|
|
103
|
+
});
|
|
104
|
+
await waitRandom(500, 1000, page);
|
|
105
|
+
} else {
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
91
109
|
await waitRandom(260, 480, page);
|
|
92
110
|
console.log('[GetProfile] Scrolling up');
|
|
93
|
-
|
|
111
|
+
try {
|
|
112
|
+
await gentleScroll(page, 'up');
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if (error.message.includes('well-serializable')) {
|
|
115
|
+
console.error('[GetProfile] Serialization error in gentleScroll (up), trying alternative scroll method');
|
|
116
|
+
await page.evaluate(function() {
|
|
117
|
+
window.scrollTo(0, 0);
|
|
118
|
+
});
|
|
119
|
+
await waitRandom(300, 500, page);
|
|
120
|
+
} else {
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
94
124
|
await waitRandom(240, 420, page);
|
|
95
125
|
console.log('[GetProfile] Extracting profile text content');
|
|
96
126
|
|
|
97
|
-
const profileText = await page.evaluate(()
|
|
127
|
+
const profileText = await page.evaluate(function() {
|
|
98
128
|
const mainContent = document.querySelector('main');
|
|
99
129
|
if (!mainContent) return '';
|
|
100
130
|
function getAllText(element) {
|
|
@@ -141,7 +171,7 @@ export async function executeGetProfile(page, action) {
|
|
|
141
171
|
await gentleScroll(page, 'down', { stepRange: [140, 260], pauseRange: [80, 160], maxIterations: 40 });
|
|
142
172
|
console.log('[GetProfile] Extracting recent posts');
|
|
143
173
|
|
|
144
|
-
recentPosts = await page.evaluate(()
|
|
174
|
+
recentPosts = await page.evaluate(function() {
|
|
145
175
|
const mainContent = document.querySelector('main');
|
|
146
176
|
if (!mainContent) return {};
|
|
147
177
|
const postContainers = mainContent.querySelectorAll('article, [data-urn*="activity"], .feed-shared-update-v2, .feed-shared-text');
|
|
@@ -241,7 +271,7 @@ async function getDropdownOptions(page) {
|
|
|
241
271
|
}
|
|
242
272
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
243
273
|
|
|
244
|
-
const dropdownOptions = await page.evaluate(()
|
|
274
|
+
const dropdownOptions = await page.evaluate(function() {
|
|
245
275
|
const options = [];
|
|
246
276
|
const dropdownItems = document.querySelectorAll('[role="menuitem"], [role="option"], .artdeco-dropdown__content-inner li, .artdeco-dropdown__content-inner button');
|
|
247
277
|
|
|
@@ -286,15 +316,30 @@ async function gentleScroll(page, direction = 'down', options = {}) {
|
|
|
286
316
|
const stepRange = options.stepRange || [180, 320];
|
|
287
317
|
const pauseRange = options.pauseRange || [90, 180];
|
|
288
318
|
const maxIterations = options.maxIterations || 50;
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
319
|
+
|
|
320
|
+
let position = 0;
|
|
321
|
+
let target = 0;
|
|
322
|
+
|
|
323
|
+
try {
|
|
324
|
+
const scrollInfo = await page.evaluate(function() {
|
|
325
|
+
const doc = document.documentElement;
|
|
326
|
+
const start = window.scrollY || doc.scrollTop || 0;
|
|
327
|
+
const limit = Math.max(doc.scrollHeight - window.innerHeight, 0);
|
|
328
|
+
return {
|
|
329
|
+
position: start,
|
|
330
|
+
target: limit
|
|
331
|
+
};
|
|
332
|
+
});
|
|
333
|
+
position = scrollInfo.position;
|
|
334
|
+
target = down ? scrollInfo.target : 0;
|
|
335
|
+
} catch (error) {
|
|
336
|
+
console.warn('[GetProfile] Error getting scroll position, using mouse wheel instead');
|
|
337
|
+
for (let i = 0; i < 10; i++) {
|
|
338
|
+
await page.mouse.wheel(0, down ? 300 : -300);
|
|
339
|
+
await waitRandom(pauseRange[0], pauseRange[1], page);
|
|
340
|
+
}
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
298
343
|
|
|
299
344
|
let iterations = 0;
|
|
300
345
|
while ((down && position < target - 1) || (!down && position > 1)) {
|
|
@@ -302,16 +347,22 @@ async function gentleScroll(page, direction = 'down', options = {}) {
|
|
|
302
347
|
Math.abs(target - position),
|
|
303
348
|
Math.floor(randomBetween(stepRange[0], stepRange[1]))
|
|
304
349
|
);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
350
|
+
|
|
351
|
+
try {
|
|
352
|
+
const scrollDelta = down ? delta : -delta;
|
|
353
|
+
await page.mouse.wheel(0, scrollDelta);
|
|
354
|
+
|
|
355
|
+
position = await page.evaluate(function() {
|
|
356
|
+
return window.scrollY || document.documentElement.scrollTop || 0;
|
|
357
|
+
});
|
|
358
|
+
} catch (error) {
|
|
359
|
+
if (error.message.includes('well-serializable')) {
|
|
360
|
+
await page.mouse.wheel(0, down ? delta : -delta);
|
|
361
|
+
} else {
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
315
366
|
await waitRandom(pauseRange[0], pauseRange[1], page);
|
|
316
367
|
iterations += 1;
|
|
317
368
|
if (iterations >= maxIterations) {
|
package/tools/human_mouse.js
CHANGED
|
@@ -24,10 +24,12 @@ const getViewportSize = async (page) => {
|
|
|
24
24
|
return viewportGetter;
|
|
25
25
|
}
|
|
26
26
|
try {
|
|
27
|
-
return await page.evaluate(()
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
return await page.evaluate(function() {
|
|
28
|
+
return {
|
|
29
|
+
width: window.innerWidth,
|
|
30
|
+
height: window.innerHeight
|
|
31
|
+
};
|
|
32
|
+
});
|
|
31
33
|
} catch (_) {
|
|
32
34
|
return { width: 1280, height: 720 };
|
|
33
35
|
}
|
|
@@ -175,10 +177,12 @@ export const humanLikeAmbientMove = async (page) => {
|
|
|
175
177
|
|
|
176
178
|
let viewport = page.viewportSize();
|
|
177
179
|
if (!viewport) {
|
|
178
|
-
viewport = await page.evaluate(()
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
viewport = await page.evaluate(function() {
|
|
181
|
+
return {
|
|
182
|
+
width: window.innerWidth,
|
|
183
|
+
height: window.innerHeight
|
|
184
|
+
};
|
|
185
|
+
}).catch(() => ({ width: 1280, height: 720 }));
|
|
182
186
|
}
|
|
183
187
|
|
|
184
188
|
const safeMargin = 80;
|
|
@@ -31,7 +31,7 @@ export async function executeSendConnectionRequest(page, action) {
|
|
|
31
31
|
await waitRandom(1700, 2600, page);
|
|
32
32
|
|
|
33
33
|
console.log('[SendConnectionRequest] Scrolling page and detecting connection status');
|
|
34
|
-
await page.evaluate(()
|
|
34
|
+
await page.evaluate(function() { window.scrollTo(0, 300); });
|
|
35
35
|
await waitRandom(600, 2500, page);
|
|
36
36
|
|
|
37
37
|
const result = await detectConnectionStatus(page, username);
|
package/tools/send_messages.js
CHANGED
|
@@ -38,7 +38,7 @@ export async function executeSendMessages(page, action) {
|
|
|
38
38
|
|
|
39
39
|
await page.waitForLoadState('domcontentloaded');
|
|
40
40
|
await waitRandom(800, 1400, page);
|
|
41
|
-
await page.evaluate(()
|
|
41
|
+
await page.evaluate(function() { window.scrollTo(0, 300); });
|
|
42
42
|
await waitRandom(600, 2500, page);
|
|
43
43
|
|
|
44
44
|
console.log('[send_messages] Closing all conversation bubbles');
|
|
@@ -199,7 +199,7 @@ export async function executeSendMessages(page, action) {
|
|
|
199
199
|
await waitRandom(180, 260, page);
|
|
200
200
|
|
|
201
201
|
console.log('[send_messages] Clearing and focusing editor');
|
|
202
|
-
await editor.evaluate((el)
|
|
202
|
+
await editor.evaluate(function(el) {
|
|
203
203
|
el.focus();
|
|
204
204
|
el.innerHTML = '';
|
|
205
205
|
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
@@ -207,7 +207,7 @@ export async function executeSendMessages(page, action) {
|
|
|
207
207
|
|
|
208
208
|
await waitRandom(130, 210, page);
|
|
209
209
|
|
|
210
|
-
const isFocused = await editor.evaluate((el)
|
|
210
|
+
const isFocused = await editor.evaluate(function(el) {
|
|
211
211
|
return document.activeElement === el;
|
|
212
212
|
});
|
|
213
213
|
console.log('[send_messages] Editor focused:', isFocused);
|
|
@@ -248,7 +248,7 @@ export async function executeSendMessages(page, action) {
|
|
|
248
248
|
await humanLikeType(editor, message);
|
|
249
249
|
await waitRandom(320, 620, page);
|
|
250
250
|
|
|
251
|
-
const textTyped = await editor.evaluate((el)
|
|
251
|
+
const textTyped = await editor.evaluate(function(el) {
|
|
252
252
|
const text = el.innerText || el.textContent || '';
|
|
253
253
|
return text.trim().length > 0;
|
|
254
254
|
});
|
|
@@ -258,7 +258,7 @@ export async function executeSendMessages(page, action) {
|
|
|
258
258
|
console.warn('[send_messages] Text not typed, retrying...');
|
|
259
259
|
await waitRandom(420, 620, page);
|
|
260
260
|
await humanLikeClick(page, editor, { timeout: 3000 });
|
|
261
|
-
await editor.evaluate((el)
|
|
261
|
+
await editor.evaluate(function(el) {
|
|
262
262
|
el.focus();
|
|
263
263
|
el.dispatchEvent(new Event('focus', { bubbles: true }));
|
|
264
264
|
});
|
|
@@ -267,7 +267,7 @@ export async function executeSendMessages(page, action) {
|
|
|
267
267
|
await humanLikeType(editor, message);
|
|
268
268
|
await waitRandom(320, 620, page);
|
|
269
269
|
|
|
270
|
-
const textTypedRetry = await editor.evaluate((el)
|
|
270
|
+
const textTypedRetry = await editor.evaluate(function(el) {
|
|
271
271
|
const text = el.innerText || el.textContent || '';
|
|
272
272
|
return text.trim().length > 0;
|
|
273
273
|
});
|