diff --git a/job_applier.mjs b/job_applier.mjs index 39b0c20..ef34745 100644 --- a/job_applier.mjs +++ b/job_applier.mjs @@ -201,6 +201,7 @@ async function main() { ]); result.applyStartedAt = applyStartedAt; await handleResult(job, result, results, settings, profile, apiKey); + if (results.rate_limited) break; } catch (e) { console.error(` ❌ Error: ${e.message}`); if (e.stack) console.error(` Stack: ${e.stack.split('\n').slice(1, 3).join(' | ').trim()}`); @@ -241,6 +242,10 @@ async function main() { } finally { await browser?.browser?.close().catch(() => {}); } + if (results.rate_limited) { + await sendTelegram(settings, `⚠️ *LinkedIn Easy Apply daily limit reached* — stopping all applications until tomorrow.`).catch(() => {}); + break; + } } // Final summary + Telegram @@ -325,6 +330,12 @@ async function handleResult(job, result, results, settings, profile, apiKey) { break; } + case 'rate_limited': + console.log(` ⚠️ LinkedIn Easy Apply daily limit reached — stopping run`); + updateJobStatus(job.id, 'new', { title, company, retry_reason: 'rate_limited' }); + results.rate_limited = true; + break; + case 'closed': console.log(` 🚫 Closed — no longer accepting applications`); updateJobStatus(job.id, 'closed', { title, company }); diff --git a/lib/apply/easy_apply.mjs b/lib/apply/easy_apply.mjs index 4473e93..5b9891b 100644 --- a/lib/apply/easy_apply.mjs +++ b/lib/apply/easy_apply.mjs @@ -143,13 +143,19 @@ export async function apply(page, job, formFiller) { let modal = await page.waitForSelector(LINKEDIN_EASY_APPLY_MODAL_SELECTOR, { timeout: 10000 }).catch(() => null); if (!modal) { - // Check if the listing is closed - const closed = await page.evaluate(() => { + // Check if the listing is closed or rate limited + const pageCheck = await page.evaluate(() => { const text = (document.body.innerText || '').toLowerCase(); - return text.includes('no longer accepting') || text.includes('no longer available') || + const closed = text.includes('no longer accepting') || text.includes('no longer available') || text.includes('this job has expired') || text.includes('job is closed'); - }).catch(() => false); - if (closed) { + const rateLimited = text.includes('easy apply limit') || text.includes('limit easy apply'); + return { closed, rateLimited }; + }).catch(() => ({ closed: false, rateLimited: false })); + if (pageCheck.rateLimited) { + console.log(` ⚠️ LinkedIn Easy Apply daily limit reached`); + return { status: 'rate_limited', meta }; + } + if (pageCheck.closed) { console.log(` ℹ️ Job closed — no longer accepting applications`); return { status: 'closed', meta }; }