Auto-deploy: 2026-06-05 23:02:41

This commit is contained in:
Hamza-Ayed
2026-06-05 23:02:41 +03:00
parent 4516c2878f
commit 728e45c065

View File

@@ -44,81 +44,79 @@
}; };
try { try {
// 1. Name: The most reliable way is the profile link // 1. Get all text lines, filter out empty ones
const profileLinks = Array.from(cardEl.querySelectorAll('a[href*="/in/"]')) const rawLines = cardEl.innerText.split('\n').map(s => s.trim()).filter(s => s.length > 1);
.filter(a => a.innerText.trim().length > 2 && !a.innerText.includes('LinkedIn'));
if (profileLinks.length > 0) { // 2. Filter out known noise (translation extensions, action buttons, connection degrees, etc)
// Remove any injected language tags const lines = rawLines.filter(s => {
let rawName = profileLinks[0].innerText.trim().split('\n')[0]; const low = s.toLowerCase();
data.name = rawName.replace(/English \(Australia\)|Auto|Translate/gi, '').trim(); // Remove degree connections
} else { if (low.includes('degree connection')) return false;
const nameEl = cardEl.querySelector('.entity-result__title-text, .search-result__title, span[dir="ltr"], h3'); if (low.includes('• 1st') || low.includes('• 2nd') || low.includes('• 3rd')) return false;
if (nameEl) data.name = nameEl.innerText.trim().split('\n')[0].replace(/English \(Australia\)|Auto/gi, '').trim(); if (['1st', '2nd', '3rd', '3rd+'].includes(low)) return false;
// Remove translation artifacts
if (low.includes('english (australia)') || low === 'auto' || low === 'translate') return false;
// Remove action buttons (exact match to avoid removing headlines like "Connect with me")
if (low === 'connect' || low === 'message' || low === 'pending' || low === 'follow' || low === 'view profile') return false;
// Remove mutual connections line
if (low.includes('mutual connection')) return false;
// Remove injected button text from this extension
if (low.includes('scan investor')) return false;
if (low.includes('تجاهله') || low.includes('تواصل معه') || low.includes('error')) return false;
return true;
});
// 3. Assign the cleaned lines
// Remove duplicates if the name appears twice (e.g., "Hamza" then "Hamza • 2nd" filtered to "Hamza")
let uniqueLines = [];
lines.forEach(l => { if (!uniqueLines.includes(l)) uniqueLines.push(l); });
if (uniqueLines.length > 0) data.name = uniqueLines[0];
if (uniqueLines.length > 1) data.headline = uniqueLines[1];
if (uniqueLines.length > 2) data.location = uniqueLines[2];
// Everything else is summary
if (uniqueLines.length > 3) {
data.summary = uniqueLines.slice(3, 8).join(' | ');
} }
// 2. Headline
const headlineEl = cardEl.querySelector('.entity-result__primary-subtitle, [class*="subtitle"], .linked-area');
if (headlineEl) data.headline = headlineEl.innerText.trim();
// 3. Location
const locationEl = cardEl.querySelector('.entity-result__secondary-subtitle, .search-result__info');
if (locationEl) data.location = locationEl.innerText.trim();
// 4. Summary
const summaryEl = cardEl.querySelector('.entity-result__summary, .search-result__snippets');
if (summaryEl) data.summary = summaryEl.innerText.trim();
// Clean up
if (data.name) data.name = data.name.replace(/View .* profile/gi, '').trim();
if (!data.name) {
data.name = 'مستثمر محتمل';
}
} catch (e) { } catch (e) {
console.error('[LJA] Extraction failed', e); console.error('[LJA] Extraction failed', e);
data.name = 'مستثمر محتمل';
} }
if (!data.name || data.name.length < 2) data.name = 'مستثمر محتمل';
if (!data.headline) data.headline = 'لا يوجد مسمى وظيفي';
return data; return data;
} }
// ─── Find Cards Logic ────────────────────────────────────────────────────── // ─── Find Cards Logic ──────────────────────────────────────────────────────
function findCards() { function findCards() {
let cards = [];
let uniqueCards = new Set(); let uniqueCards = new Set();
// Method 1: The official LinkedIn search result container class // The most bulletproof way to find a profile card is to find the main Action Button (Connect/Message/Follow)
let containerElements = document.querySelectorAll('.reusable-search__result-container, .search-entity, .entity-result__item'); // and then go up the DOM tree until we find the container that holds the whole profile
if (containerElements.length > 0) { let buttons = Array.from(document.querySelectorAll('button')).filter(btn => {
containerElements.forEach(el => uniqueCards.add(el)); let txt = btn.innerText.toLowerCase().trim();
console.log('[LJA] Found cards via container classes:', uniqueCards.size); return txt === 'connect' || txt === 'message' || txt === 'pending' || txt === 'follow';
}
// Method 2: Fallback to finding profile links and going up to the list item
if (uniqueCards.size === 0) {
let profileLinks = Array.from(document.querySelectorAll('a[href*="/in/"]'))
.filter(a => a.innerText.trim().length > 2 && !a.querySelector('img'));
profileLinks.forEach(link => {
// Find the nearest list item or large div container
let container = link.closest('li') || link.closest('div.mb1') || link.parentElement.parentElement.parentElement;
if (container && container.innerText.length > 20) {
uniqueCards.add(container);
}
});
console.log('[LJA] Found cards via profile links:', uniqueCards.size);
}
// Convert Set to Array and filter out translation extension dropdowns
cards = Array.from(uniqueCards).filter(card => {
const txt = card.innerText.toLowerCase();
// Must not be a language selector dropdown
if (txt.includes('english (australia)') && txt.length < 50) return false;
// Should have some decent amount of text
return txt.length > 20;
}); });
buttons.forEach(btn => {
let container = btn.parentElement;
// Go up the DOM tree (max 10 levels) to find the list item
for(let i=0; i<10; i++) {
if (!container) break;
// A valid card container is usually an LI and contains an image
if (container.tagName === 'LI' && container.querySelector('img')) {
uniqueCards.add(container);
break;
}
container = container.parentElement;
}
});
const cards = Array.from(uniqueCards);
console.log('[LJA] Found valid profile cards:', cards.length);
return cards; return cards;
} }