Files
linkme/scripts/bern-langcheck.ts
T
rodado fb67c38edd chore: reorganize repo structure and update docs
- move temp scripts to scripts/, cv files to cv/, jobs.csv to results/
- update index.ts and recheck.ts CSV path to results/jobs.csv
- fix imports in scripts/ to use ../config.ts and ../fetch.ts
- update CLAUDE.md and README.md to reflect new structure
- add plans/ with LinkedIn post drafts
- update .gitignore: ignore results/, jobs/, cv binaries, .DS_Store
2026-06-03 16:01:32 +02:00

76 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bun
const DE_CONTENT_RE = /\b(Sie|Ihre?|Ihnen|Wir|wir|und\s|für|mit\s|von\s|bei\s|das\s|ist\s|sind\s|haben\s|werden\s|können|suchen|bieten|Kenntnisse|Erfahrung|Anforderungen|Aufgaben|Stellenbeschreibung|Stellenangebot|Bewerbung|Ausbildung|Berufserfahrung|Teamarbeit|Quereinsteiger|Vollzeit|Teilzeit|unbefristet|Abschluss|gesucht|Deutsch|Englisch|Schweizer)\b/g;
const FR_CONTENT_RE = /\b(vous|nous|votre|notre|pour\s|avec\s|profil|poste|emploi|entreprise|compétences|expérience|formation|équipe|rejoindre|recherchons|offrons|missions|candidature|CDI|CDD|temps\s+plein|temps\s+partiel)\b/g;
const HEADERS = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
};
const jobs = [
{ id: "4412445330", title: "Senior Software and System Architect", company: "NVIDIA AI" },
{ id: "4406964785", title: "Digital Platform Engineer – EasyGov.swiss", company: "Swiss Federal Administration" },
{ id: "4405193749", title: "Technical Lead Web Portals", company: "Smart Energy Link AG" },
{ id: "4411445039", title: "Senior System Engineer (Cloud Native, Remote-First)", company: "Adfinis" },
{ id: "4411290320", title: "Automation Data Engineer", company: "Takeda Pharmaceuticals" },
{ id: "4411348405", title: "Solutions Architect", company: "RJC Group" },
{ id: "4406980033", title: "Enterprise Architect", company: "Swiss Federal Administration" },
{ id: "4367874399", title: "Software Engineer", company: "Cartier" },
{ id: "4399418573", title: "Data Science Specialist", company: "Nestlé" },
{ id: "4411369976", title: "Data Scientist 80–100%", company: "Fincons Group" },
{ id: "4412464434", title: "Solution Engineer Management Systems", company: "Siemens" },
{ id: "4401638413", title: "Fullstack Developer (Java/React)", company: "soobr" },
{ id: "4399356316", title: "Senior Java Software Engineer", company: "Smart Energy Link AG" },
{ id: "4407778229", title: "Software Engineer", company: "Softcom" },
{ id: "4402476156", title: "Software Developer", company: "SwissPeak Partners" },
// remaining from the 20
{ id: "4404649130", title: "Senior System Engineer (100%)", company: "nanoTRONIC" },
{ id: "4408770074", title: "System Engineer", company: "Infopro AG" },
{ id: "4408864023", title: "System Engineer – Workplace Engineering", company: "Bedag Informatique SA" },
{ id: "4405214433", title: "Cloud Platform Engineer (Kubernetes/Azure/DevOps)", company: "Gramian Consulting" },
];
function detectLanguage(text: string): "de" | "fr" | "en" {
const deMatches = (text.match(DE_CONTENT_RE) ?? []).length;
const frMatches = (text.match(FR_CONTENT_RE) ?? []).length;
if (deMatches >= 6) return "de";
if (frMatches >= 6) return "fr";
return "en";
}
function extractDescription(html: string): string {
const m = html.match(/class="show-more-less-html__markup[^"]*">([\s\S]{0,8000}?)<\/div>/);
if (m) return m[1].replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
// fallback: grab large text blocks
return html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").slice(0, 5000);
}
const passed: typeof jobs = [];
const dropped: { id: string; title: string; company: string; lang: string }[] = [];
for (const job of jobs) {
await Bun.sleep(350);
process.stdout.write(` checking ${job.company} — ${job.title} … `);
try {
const res = await fetch(`https://www.linkedin.com/jobs/view/${job.id}/`, { headers: HEADERS });
const html = await res.text();
const desc = extractDescription(html);
const lang = detectLanguage(desc);
console.log(lang);
if (lang === "en") passed.push(job);
else dropped.push({ ...job, lang });
} catch (e) {
console.log("fetch error, keeping");
passed.push(job);
}
}
console.log(`\n── ${dropped.length} dropped (non-English) ──`);
for (const j of dropped) console.log(` [${j.lang}] ${j.title} @ ${j.company}`);
console.log(`\n── ${passed.length} English jobs ──`);
for (const [i, j] of passed.entries()) {
console.log(` ${i + 1}. ${j.title} — ${j.company} https://www.linkedin.com/jobs/view/${j.id}/`);
}