Auto-deploy: 2026-08-05 18:11:15
This commit is contained in:
+43
-41
@@ -48,25 +48,6 @@
|
||||
return '';
|
||||
}
|
||||
|
||||
// ── Job Title (many fallbacks)
|
||||
data.jobTitle = trySelectors([
|
||||
'.job-details-jobs-unified-top-card__job-title h1 a',
|
||||
'.job-details-jobs-unified-top-card__job-title h1',
|
||||
'.jobs-unified-top-card__job-title h1',
|
||||
'.jobs-unified-top-card__job-title',
|
||||
'.job-details-jobs-unified-top-card__job-title',
|
||||
'h2.job-details-jobs-unified-top-card__job-title',
|
||||
'.jobs-unified-top-card__job-title a',
|
||||
'h1.t-24',
|
||||
'h1.t-18',
|
||||
'h1[class*="job-title"]',
|
||||
'h2[class*="job-title"]',
|
||||
'.t-24.t-bold',
|
||||
'.top-card-layout__title',
|
||||
'a[class*="topcard__title"]',
|
||||
'.topcard__title',
|
||||
]);
|
||||
|
||||
// LinkedIn's job panel is full of text that is neither navigation nor the
|
||||
// job title: screen-reader-only headings ("0 notifications"), and product
|
||||
// furniture inside the detail column itself ("Are these results helpful?",
|
||||
@@ -98,33 +79,54 @@
|
||||
return text.length > 4 && text.length < 100 && !NAV_NOISE.test(text);
|
||||
}
|
||||
|
||||
// Preferred fallback 1: Extract from active job link using currentJobId
|
||||
if (!data.jobTitle) {
|
||||
let currentJobId = new URLSearchParams(window.location.search).get('currentJobId');
|
||||
if (!currentJobId) {
|
||||
const match = window.location.pathname.match(/\/jobs\/view\/(\d+)/);
|
||||
if (match) currentJobId = match[1];
|
||||
}
|
||||
if (currentJobId) {
|
||||
const links = document.querySelectorAll(`a[href*="/jobs/view/${currentJobId}"]`);
|
||||
for (const link of links) {
|
||||
const text = link.innerText.trim();
|
||||
// Filter out empty or obviously wrong texts
|
||||
if (plausibleTitle(text) && !text.includes('Easy Apply') && !text.includes('Save')) {
|
||||
data.jobTitle = text;
|
||||
break;
|
||||
}
|
||||
// 1. Most Reliable Method: Extract from active job link using currentJobId
|
||||
let currentJobId = new URLSearchParams(window.location.search).get('currentJobId');
|
||||
if (!currentJobId) {
|
||||
const match = window.location.pathname.match(/\/jobs\/view\/(\d+)/);
|
||||
if (match) currentJobId = match[1];
|
||||
}
|
||||
|
||||
if (currentJobId) {
|
||||
// Find all links containing this job ID
|
||||
const links = document.querySelectorAll(`a[href*="/jobs/view/${currentJobId}"]`);
|
||||
for (const link of links) {
|
||||
const text = (link.textContent || '').trim();
|
||||
// Filter out empty or obviously wrong texts (like "Save", "Easy Apply")
|
||||
if (text && plausibleTitle(text) && !text.includes('Easy Apply') && !text.includes('Save')) {
|
||||
data.jobTitle = text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preferred fallback 2: the browser tab title. LinkedIn sets it to
|
||||
// "(N) Job Title | Company | LinkedIn" on every job page, it is not part of
|
||||
// the React DOM that keeps getting restructured, and it cannot pick up a
|
||||
// stray card heading. This is far more reliable than guessing at headings,
|
||||
// so it runs before the DOM scan, not after it.
|
||||
// 2. Fallback: Try known selectors
|
||||
if (!data.jobTitle) {
|
||||
data.jobTitle = trySelectors([
|
||||
'.job-details-jobs-unified-top-card__job-title h1 a',
|
||||
'.job-details-jobs-unified-top-card__job-title h1',
|
||||
'.jobs-unified-top-card__job-title h1',
|
||||
'.jobs-unified-top-card__job-title',
|
||||
'.job-details-jobs-unified-top-card__job-title',
|
||||
'h2.job-details-jobs-unified-top-card__job-title',
|
||||
'.jobs-unified-top-card__job-title a',
|
||||
'h1.t-24',
|
||||
'h1.t-18',
|
||||
'h1[class*="job-title"]',
|
||||
'h2[class*="job-title"]',
|
||||
'.t-24.t-bold',
|
||||
'.top-card-layout__title',
|
||||
'a[class*="topcard__title"]',
|
||||
'.topcard__title',
|
||||
]);
|
||||
|
||||
// If we grabbed garbage, reset it
|
||||
if (data.jobTitle && !plausibleTitle(data.jobTitle)) {
|
||||
data.jobTitle = '';
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Last Resort Fallback: Browser tab title
|
||||
if (!data.jobTitle) {
|
||||
// The "(N)" prefix is LinkedIn's unread counter and can read "(99+)".
|
||||
const m = document.title.match(/^(?:\(\d+\+?\)\s*)?(.+?)\s*[|·]/);
|
||||
if (m) {
|
||||
const candidate = m[1].trim();
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user