Auto-deploy: 2026-05-17 22:45:01
This commit is contained in:
149
content.js
149
content.js
@@ -955,6 +955,149 @@ Brief honest assessment of this opportunity for my profile`
|
||||
setTimeout(() => toast.classList.remove('show'), 2500);
|
||||
}
|
||||
|
||||
// ─── List Scanner ────────────────────────────────────────────────────────
|
||||
|
||||
function injectListScanner() {
|
||||
if (document.getElementById('lja-scan-btn')) return;
|
||||
|
||||
const btn = document.createElement('button');
|
||||
btn.id = 'lja-scan-btn';
|
||||
btn.innerHTML = '🔍 Scan List';
|
||||
btn.style.cssText = `
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
z-index: 999999;
|
||||
background: linear-gradient(135deg, #00d67e, #00a65e);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
padding: 12px 24px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 15px rgba(0, 214, 126, 0.4);
|
||||
transition: transform 0.2s;
|
||||
font-family: Arial, sans-serif;
|
||||
`;
|
||||
btn.onmouseover = () => btn.style.transform = 'scale(1.05)';
|
||||
btn.onmouseout = () => btn.style.transform = 'scale(1)';
|
||||
|
||||
btn.onclick = async () => {
|
||||
btn.innerHTML = '⏳ Scanning...';
|
||||
try {
|
||||
await scanJobList();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
alert('Scan failed: ' + e.message);
|
||||
}
|
||||
btn.innerHTML = '🔍 Scan List';
|
||||
};
|
||||
|
||||
document.body.appendChild(btn);
|
||||
}
|
||||
|
||||
async function scanJobList() {
|
||||
const listItems = document.querySelectorAll('.jobs-search-results__list-item, .job-card-container');
|
||||
if (!listItems.length) {
|
||||
alert('No job items found on this page. Scroll down to load them.');
|
||||
return;
|
||||
}
|
||||
|
||||
const jobsToScan = [];
|
||||
listItems.forEach((item, index) => {
|
||||
const titleEl = item.querySelector('.job-card-list__title, .artdeco-entity-lockup__title');
|
||||
const companyEl = item.querySelector('.job-card-container__primary-description, .artdeco-entity-lockup__subtitle');
|
||||
if (titleEl && companyEl) {
|
||||
jobsToScan.push({
|
||||
index: index,
|
||||
title: titleEl.textContent.trim().replace(/\n/g, ''),
|
||||
company: companyEl.textContent.trim().replace(/\n/g, ''),
|
||||
element: item
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (!jobsToScan.length) {
|
||||
alert('Could not parse job titles.');
|
||||
return;
|
||||
}
|
||||
|
||||
document.querySelectorAll('.lja-badge').forEach(b => b.remove());
|
||||
|
||||
const listDataStr = JSON.stringify(jobsToScan.map(j => ({ index: j.index, title: j.title, company: j.company })));
|
||||
|
||||
const settings = await getSettings();
|
||||
if (!settings.apiKey) {
|
||||
alert('Please set your API key in the extension popup first.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof buildPromptV2 !== 'function') {
|
||||
alert('buildPromptV2 not found. Extension error.');
|
||||
return;
|
||||
}
|
||||
|
||||
const promptStr = buildPromptV2('list_analysis', { skills: [], listData: listDataStr }, settings.userProfile, settings.language);
|
||||
|
||||
const response = await fetch(
|
||||
\`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=\${settings.apiKey}\`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
contents: [{ parts: [{ text: promptStr }] }],
|
||||
generationConfig: { maxOutputTokens: 2048, temperature: 0.1 }
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) throw new Error('API Request failed');
|
||||
const data = await response.json();
|
||||
let resultText = data.candidates[0].content.parts[0].text;
|
||||
resultText = resultText.replace(/\`\`\`json/g, '').replace(/\`\`\`/g, '').trim();
|
||||
|
||||
let results;
|
||||
try {
|
||||
results = JSON.parse(resultText);
|
||||
} catch(e) {
|
||||
console.error(resultText);
|
||||
throw new Error('Failed to parse AI response');
|
||||
}
|
||||
|
||||
results.forEach(res => {
|
||||
const jobItem = jobsToScan.find(j => j.index === res.index);
|
||||
if (jobItem) {
|
||||
const badge = document.createElement('div');
|
||||
badge.className = 'lja-badge';
|
||||
badge.style.cssText = \`
|
||||
display: inline-block;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
margin-top: 6px;
|
||||
color: white;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
\`;
|
||||
if (res.verdict === 'YES') {
|
||||
badge.style.background = 'linear-gradient(135deg, #00d67e, #00a65e)';
|
||||
badge.innerHTML = \`✅ MATCH: \${res.reason}\`;
|
||||
} else if (res.verdict === 'NO') {
|
||||
badge.style.background = 'linear-gradient(135deg, #ff4d6d, #d90429)';
|
||||
badge.innerHTML = \`❌ SKIP: \${res.reason}\`;
|
||||
} else {
|
||||
badge.style.background = 'linear-gradient(135deg, #ffb347, #ff9200)';
|
||||
badge.innerHTML = \`⚠️ MAYBE: \${res.reason}\`;
|
||||
}
|
||||
|
||||
const contentContainer = jobItem.element.querySelector('.artdeco-entity-lockup__content');
|
||||
if (contentContainer) contentContainer.appendChild(badge);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ─── SPA Navigation Observer ─────────────────────────────────────────────
|
||||
|
||||
let lastUrl = location.href;
|
||||
@@ -970,7 +1113,7 @@ Brief honest assessment of this opportunity for my profile`
|
||||
const old = document.getElementById('lja-root');
|
||||
if (old) old.remove();
|
||||
window.__linkedinAnalyzerLoaded = false;
|
||||
setTimeout(injectOverlay, 1200);
|
||||
setTimeout(() => { injectOverlay(); injectListScanner(); }, 1200);
|
||||
}
|
||||
|
||||
// Watch for URL changes (SPA navigation + job switches)
|
||||
@@ -1006,9 +1149,9 @@ Brief honest assessment of this opportunity for my profile`
|
||||
|
||||
function init() {
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', () => setTimeout(injectOverlay, 1000));
|
||||
document.addEventListener('DOMContentLoaded', () => setTimeout(() => { injectOverlay(); injectListScanner(); }, 1000));
|
||||
} else {
|
||||
setTimeout(injectOverlay, 1000);
|
||||
setTimeout(() => { injectOverlay(); injectListScanner(); }, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user